[ANN] JNIPort for Pharo 3.0 alpha

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

[ANN] JNIPort for Pharo 3.0 alpha

Joachim Geidel
Hi everybody,

JNIPort for Pharo 3.0 alpha is now available at SmalltalkHub.

JNIPort is a Smalltalk library which allows Java code to be invoked from Smalltalk. It acts as a bridge between the world of Smalltalk objects and a Java Virtual Machine (JVM) where Java code is executing.

When I first ported JNIPort to Squeak and Pharo 1.x, I used Alien as the FFI library. As NativeBoost has superseded Alien, the interface to the Java Native Interface library had to be rewritten. There are still some undocumented and obscure parts in NativeBoost, so this has taken some time.

If you want to try it, load it via the ConfigurationOfJNIPort. I hope this works. If it does not, load the packages individually in the order in which they appear in the ConfigurationOfJNIPort.
        http://www.smalltalkhub.com/#!/~JNIPort/JNIPort
The next step is to read the documentation at
        http://jniport.wikispaces.com/
Otherwise, you won't know what to do next. ;-)
Download the extra files from the download page at Wikispaces, you will need two jar files from there.

Start a Java VM attached to Pharo by adapting and executing the following code snippet:

----
| jvmSettings |
 "You can set the path to the Java VM library by editing the path as needed."
JNIPortJNIInterface libraryFile: '/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libclient.dylib' .
"JNIPortJNIInterface libraryFile: 'C:\Programme\Java\jre7\bin\client\jvm.dll' ."

 jvmSettings := JVMSettings new.
 jvmSettings usesGhosts: true.
 jvmSettings supportsCallbacks: true.
 jvmSettings jniPortSettings  useJNIHelperLibrary: false.
jvmSettings ghostClassSettings retainMethodSource: true.

 "On Mac OS X and Linux, class path entries are separated by colons."
 "On Windows, you have to use semicolons instead. Edit the following line as needed."
jvmSettings runtimeSettings classpath: '.:/Users/myname/JNIPort.jar:/Users/myname/JNIPort-Tests.jar'.
" jvmSettings runtimeSettings classpath: '.;.\JNIPort.jar;.\JNIPort-Tests.jar'."

 "Uncomment the following if you want the Java VM to emit verbose messages.
  How to access these messages depends on your platform.
  On Mac OS X, they are visible in the Console application."
"jvmSettings runtimeSettings addOption: '-verbose:jni'; addOption: '-verbose:gc'; addOption: '-verbose:class'."
Cursor execute showWhile: [JVM newWithSettings: jvmSettings].
----

Then the fun starts:

----
| zfClass zipfile entries |
zfClass := JVM current findClass: #'java.util.zip.ZipFile'.
zipfile := zfClass new_String: 'JNIPort.jar'.
zipfile size. "--> answers an Integer"
entries := zipfile entries.
entries asAnEnumeration do: [:each | Transcript cr; print: each].
----

And now to the ugly little secret reason why I call it an alpha version:

While everything seems to work, it is much slower than it used to be in Pharo 1.2 with Alien. And when I compare it with VisualWorks, I wonder if the Pharo version secretly does some additional work for SETI:
- Starting the JVM:
        VisualWorks 0.7 seconds
        Pharo 7 to 8 seconds
- A benchmark using some methods of java.io.BufferedReader and java.util.StringTokenizer:
        VisualWorks 114 milliseconds
        Pharo 12 to 13 seconds

I have not yet found the reason. The TimeProfiler is not very helpful, as its 1 millisecond resolution is too coarse. It would be nice if it had microsecond resolution. From the TimeProfiler results, it seems that calling a JNI method with NativeBoost is extremely slow, but I don't trust those profiles too much.

So, give it a try, and if you find something useful concerning the bad performance, please send me a message.

Best regards,
Joachim Geidel
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Tudor Girba-2
Thanks a lot for this contribution!

I will give it a try soon.

Doru


On Tue, Mar 25, 2014 at 7:59 PM, Joachim Geidel <[hidden email]> wrote:
Hi everybody,

JNIPort for Pharo 3.0 alpha is now available at SmalltalkHub.

JNIPort is a Smalltalk library which allows Java code to be invoked from
Smalltalk. It acts as a bridge between the world of Smalltalk objects and a
Java Virtual Machine (JVM) where Java code is executing.

When I first ported JNIPort to Squeak and Pharo 1.x, I used Alien as the FFI
library. As NativeBoost has superseded Alien, the interface to the Java
Native Interface library had to be rewritten. There are still some
undocumented and obscure parts in NativeBoost, so this has taken some time.

If you want to try it, load it via the ConfigurationOfJNIPort. I hope this
works. If it does not, load the packages individually in the order in which
they appear in the ConfigurationOfJNIPort.
        http://www.smalltalkhub.com/#!/~JNIPort/JNIPort
The next step is to read the documentation at
        http://jniport.wikispaces.com/
Otherwise, you won't know what to do next. ;-)
Download the extra files from the download page at Wikispaces, you will need
two jar files from there.

Start a Java VM attached to Pharo by adapting and executing the following
code snippet:

----
| jvmSettings |
 "You can set the path to the Java VM library by editing the path as
needed."
JNIPortJNIInterface libraryFile:
'/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libclient.dylib'
.
"JNIPortJNIInterface libraryFile:
'C:\Programme\Java\jre7\bin\client\jvm.dll' ."

 jvmSettings := JVMSettings new.
 jvmSettings usesGhosts: true.
 jvmSettings supportsCallbacks: true.
 jvmSettings jniPortSettings  useJNIHelperLibrary: false.
jvmSettings ghostClassSettings retainMethodSource: true.

 "On Mac OS X and Linux, class path entries are separated by colons."
 "On Windows, you have to use semicolons instead. Edit the following line as
needed."
jvmSettings runtimeSettings classpath:
'.:/Users/myname/JNIPort.jar:/Users/myname/JNIPort-Tests.jar'.
" jvmSettings runtimeSettings classpath:
'.;.\JNIPort.jar;.\JNIPort-Tests.jar'."

 "Uncomment the following if you want the Java VM to emit verbose messages.
  How to access these messages depends on your platform.
  On Mac OS X, they are visible in the Console application."
"jvmSettings runtimeSettings addOption: '-verbose:jni'; addOption:
'-verbose:gc'; addOption: '-verbose:class'."
Cursor execute showWhile: [JVM newWithSettings: jvmSettings].
----

Then the fun starts:

----
| zfClass zipfile entries |
zfClass := JVM current findClass: #'java.util.zip.ZipFile'.
zipfile := zfClass new_String: 'JNIPort.jar'.
zipfile size. "--> answers an Integer"
entries := zipfile entries.
entries asAnEnumeration do: [:each | Transcript cr; print: each].
----

And now to the ugly little secret reason why I call it an alpha version:

While everything seems to work, it is *much* slower than it used to be in
Pharo 1.2 with Alien. And when I compare it with VisualWorks, I wonder if
the Pharo version secretly does some additional work for SETI:
- Starting the JVM:
        VisualWorks 0.7 seconds
        Pharo 7 to 8 seconds
- A benchmark using some methods of java.io.BufferedReader and
java.util.StringTokenizer:
        VisualWorks 114 milliseconds
        Pharo 12 to 13 seconds

I have not yet found the reason. The TimeProfiler is not very helpful, as
its 1 millisecond resolution is too coarse. It would be nice if it had
microsecond resolution. From the TimeProfiler results, it seems that calling
a JNI method with NativeBoost is extremely slow, but I don't trust those
profiles too much.

So, give it a try, and if you find something useful concerning the bad
performance, please send me a message.

Best regards,
Joachim Geidel




--
View this message in context: http://forum.world.st/ANN-JNIPort-for-Pharo-3-0-alpha-tp4750750.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




--

"Every thing has its own flow"
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

philippeback

Works on Windows 8.1 x64 with a 32-bit JRE 1.7 on a freshly fetched Pharo30

 

There is a Transcript flush that would help seeing the output to the Transcript…

 

Snippet:

 

| jvmSettings |

"You can set the path to the Java VM library by editing the path as

needed."

"JNIPortJNIInterface libraryFile:

'/System/Library/Java/JavaVirtualMachines/1..6.0.jdk/Contents/Libraries/libclient.dylib'"

.

JNIPortJNIInterface libraryFile: 'C:\Program Files (x86)\Java\jre7\bin\client\jvm.dll' ..

 

jvmSettings := JVMSettings new.

jvmSettings usesGhosts: true.

jvmSettings supportsCallbacks: true.

jvmSettings jniPortSettings  useJNIHelperLibrary: false.

jvmSettings ghostClassSettings retainMethodSource: true.

 

"On Mac OS X and Linux, class path entries are separated by colons."

"On Windows, you have to use semicolons instead. Edit the following line as

needed."

"jvmSettings runtimeSettings classpath:

'.:/Users/myname/JNIPort.jar:/Users/myname/JNIPort-Tests.jar'."

jvmSettings runtimeSettings classpath: '.;.\JNIPort.jar;.\JNIPort-Tests.jar'.

 

"Uncomment the following if you want the Java VM to emit verbose messages.

  How to access these messages depends on your platform.

  On Mac OS X, they are visible in the Console application."

"jvmSettings runtimeSettings addOption: '-verbose:jni'; addOption:

'-verbose:gc'; addOption: '-verbose:class'."

Cursor execute showWhile: [JVM newWithSettings: jvmSettings].

"----

 

Then the fun starts:

 

----"

zfClass := JVM current findClass: #'java.util.zip.ZipFile'.

zipfile := zfClass new_String: 'JNIPort.jar'.

zipfile size. "--> answers an Integer"

entries := zipfile entries.

entries asAnEnumeration do: [:each | Transcript cr; print: each].

Transcript flush.

"----"

 

Cool to have a bridge.

 

Phil

 

 

From: Pharo-users [mailto:[hidden email]] On Behalf Of Tudor Girba
Sent: mardi 25 mars 2014 21:26
To: Any question about pharo is welcome
Subject: Re: [Pharo-users] [ANN] JNIPort for Pharo 3.0 alpha

 

Thanks a lot for this contribution!

 

I will give it a try soon.

 

Doru

 

On Tue, Mar 25, 2014 at 7:59 PM, Joachim Geidel <[hidden email]> wrote:

Hi everybody,

JNIPort for Pharo 3.0 alpha is now available at SmalltalkHub.

JNIPort is a Smalltalk library which allows Java code to be invoked from
Smalltalk. It acts as a bridge between the world of Smalltalk objects and a
Java Virtual Machine (JVM) where Java code is executing.

When I first ported JNIPort to Squeak and Pharo 1.x, I used Alien as the FFI
library. As NativeBoost has superseded Alien, the interface to the Java
Native Interface library had to be rewritten. There are still some
undocumented and obscure parts in NativeBoost, so this has taken some time.

If you want to try it, load it via the ConfigurationOfJNIPort. I hope this
works. If it does not, load the packages individually in the order in which
they appear in the ConfigurationOfJNIPort.
        http://www.smalltalkhub.com/#!/~JNIPort/JNIPort
The next step is to read the documentation at
        http://jniport.wikispaces.com/
Otherwise, you won't know what to do next. ;-)
Download the extra files from the download page at Wikispaces, you will need
two jar files from there.

Start a Java VM attached to Pharo by adapting and executing the following
code snippet:

----
| jvmSettings |
 "You can set the path to the Java VM library by editing the path as
needed."
JNIPortJNIInterface libraryFile:
'/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libclient.dylib'
.
"JNIPortJNIInterface libraryFile:
'C:\Programme\Java\jre7\bin\client\jvm.dll' .."

 jvmSettings := JVMSettings new.
 jvmSettings usesGhosts: true.
 jvmSettings supportsCallbacks: true.
 jvmSettings jniPortSettings  useJNIHelperLibrary: false.
jvmSettings ghostClassSettings retainMethodSource: true.

 "On Mac OS X and Linux, class path entries are separated by colons."
 "On Windows, you have to use semicolons instead. Edit the following line as
needed."
jvmSettings runtimeSettings classpath:
'.:/Users/myname/JNIPort.jar:/Users/myname/JNIPort-Tests.jar'.
" jvmSettings runtimeSettings classpath:
'.;.\JNIPort.jar;.\JNIPort-Tests.jar'."

 "Uncomment the following if you want the Java VM to emit verbose messages.
  How to access these messages depends on your platform.
  On Mac OS X, they are visible in the Console application."
"jvmSettings runtimeSettings addOption: '-verbose:jni'; addOption:
'-verbose:gc'; addOption: '-verbose:class'."
Cursor execute showWhile: [JVM newWithSettings: jvmSettings].
----

Then the fun starts:

----
| zfClass zipfile entries |
zfClass := JVM current findClass: #'java.util.zip.ZipFile'.
zipfile := zfClass new_String: 'JNIPort.jar'.
zipfile size. "--> answers an Integer"
entries := zipfile entries.
entries asAnEnumeration do: [:each | Transcript cr; print: each].
----

And now to the ugly little secret reason why I call it an alpha version:

While everything seems to work, it is *much* slower than it used to be in
Pharo 1.2 with Alien. And when I compare it with VisualWorks, I wonder if
the Pharo version secretly does some additional work for SETI:
- Starting the JVM:
        VisualWorks 0.7 seconds
        Pharo 7 to 8 seconds
- A benchmark using some methods of java.io.BufferedReader and
java.util.StringTokenizer:
        VisualWorks 114 milliseconds
        Pharo 12 to 13 seconds

I have not yet found the reason. The TimeProfiler is not very helpful, as
its 1 millisecond resolution is too coarse. It would be nice if it had
microsecond resolution. From the TimeProfiler results, it seems that calling
a JNI method with NativeBoost is extremely slow, but I don't trust those
profiles too much.

So, give it a try, and if you find something useful concerning the bad
performance, please send me a message.

Best regards,
Joachim Geidel




--
View this message in context: http://forum.world.st/ANN-JNIPort-for-Pharo-3-0-alpha-tp4750750.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.



 

--

 

"Every thing has its own flow"




Ce courrier électronique ne contient aucun virus ou logiciel malveillant parce que la protection Antivirus avast! est active.



JNIPort25-03-14 23-52-52.png (243K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Tudor Girba-2
I also tested it on Windows 7 and it works just great.

Just a question: is there a way to communicate with an already running VM that was started independently from Pharo?

Doru


On Tue, Mar 25, 2014 at 11:55 PM, Philippe Back <[hidden email]> wrote:

Works on Windows 8.1 x64 with a 32-bit JRE 1.7 on a freshly fetched Pharo30

 

There is a Transcript flush that would help seeing the output to the Transcript…

 

Snippet:

 

| jvmSettings |

"You can set the path to the Java VM library by editing the path as

needed."

"JNIPortJNIInterface libraryFile:

'/System/Library/Java/JavaVirtualMachines/1..6.0.jdk/Contents/Libraries/libclient.dylib'"

.

JNIPortJNIInterface libraryFile: 'C:\Program Files (x86)\Java\jre7\bin\client\jvm.dll' ..

 

jvmSettings := JVMSettings new.

jvmSettings usesGhosts: true.

jvmSettings supportsCallbacks: true.

jvmSettings jniPortSettings  useJNIHelperLibrary: false.

jvmSettings ghostClassSettings retainMethodSource: true.

 

"On Mac OS X and Linux, class path entries are separated by colons."

"On Windows, you have to use semicolons instead. Edit the following line as

needed."

"jvmSettings runtimeSettings classpath:

'.:/Users/myname/JNIPort.jar:/Users/myname/JNIPort-Tests.jar'."

jvmSettings runtimeSettings classpath: '.;.\JNIPort.jar;.\JNIPort-Tests.jar'.

 

"Uncomment the following if you want the Java VM to emit verbose messages.

  How to access these messages depends on your platform.

  On Mac OS X, they are visible in the Console application."

"jvmSettings runtimeSettings addOption: '-verbose:jni'; addOption:

'-verbose:gc'; addOption: '-verbose:class'."

Cursor execute showWhile: [JVM newWithSettings: jvmSettings].

"----

 

Then the fun starts:

 

----"

zfClass := JVM current findClass: #'java.util.zip.ZipFile'.

zipfile := zfClass new_String: 'JNIPort.jar'.

zipfile size. "--> answers an Integer"

entries := zipfile entries.

entries asAnEnumeration do: [:each | Transcript cr; print: each].

Transcript flush.

"----"

 

Cool to have a bridge.

 

Phil

 

 

From: Pharo-users [mailto:[hidden email]] On Behalf Of Tudor Girba
Sent: mardi 25 mars 2014 21:26
To: Any question about pharo is welcome
Subject: Re: [Pharo-users] [ANN] JNIPort for Pharo 3.0 alpha

 

Thanks a lot for this contribution!

 

I will give it a try soon.

 

Doru

 

On Tue, Mar 25, 2014 at 7:59 PM, Joachim Geidel <[hidden email]> wrote:

Hi everybody,

JNIPort for Pharo 3.0 alpha is now available at SmalltalkHub.

JNIPort is a Smalltalk library which allows Java code to be invoked from
Smalltalk. It acts as a bridge between the world of Smalltalk objects and a
Java Virtual Machine (JVM) where Java code is executing.

When I first ported JNIPort to Squeak and Pharo 1.x, I used Alien as the FFI
library. As NativeBoost has superseded Alien, the interface to the Java
Native Interface library had to be rewritten. There are still some
undocumented and obscure parts in NativeBoost, so this has taken some time.

If you want to try it, load it via the ConfigurationOfJNIPort. I hope this
works. If it does not, load the packages individually in the order in which
they appear in the ConfigurationOfJNIPort.
        http://www.smalltalkhub.com/#!/~JNIPort/JNIPort
The next step is to read the documentation at
        http://jniport.wikispaces.com/
Otherwise, you won't know what to do next. ;-)
Download the extra files from the download page at Wikispaces, you will need
two jar files from there.

Start a Java VM attached to Pharo by adapting and executing the following
code snippet:

----
| jvmSettings |
 "You can set the path to the Java VM library by editing the path as
needed."
JNIPortJNIInterface libraryFile:
'/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libclient.dylib'
.
"JNIPortJNIInterface libraryFile:
'C:\Programme\Java\jre7\bin\client\jvm.dll' .."


 jvmSettings := JVMSettings new.
 jvmSettings usesGhosts: true.
 jvmSettings supportsCallbacks: true.
 jvmSettings jniPortSettings  useJNIHelperLibrary: false.
jvmSettings ghostClassSettings retainMethodSource: true.

 "On Mac OS X and Linux, class path entries are separated by colons."
 "On Windows, you have to use semicolons instead. Edit the following line as
needed."
jvmSettings runtimeSettings classpath:
'.:/Users/myname/JNIPort.jar:/Users/myname/JNIPort-Tests.jar'.
" jvmSettings runtimeSettings classpath:
'.;.\JNIPort.jar;.\JNIPort-Tests.jar'."

 "Uncomment the following if you want the Java VM to emit verbose messages.
  How to access these messages depends on your platform.
  On Mac OS X, they are visible in the Console application."
"jvmSettings runtimeSettings addOption: '-verbose:jni'; addOption:
'-verbose:gc'; addOption: '-verbose:class'."
Cursor execute showWhile: [JVM newWithSettings: jvmSettings].
----

Then the fun starts:

----
| zfClass zipfile entries |
zfClass := JVM current findClass: #'java.util.zip.ZipFile'.
zipfile := zfClass new_String: 'JNIPort.jar'.
zipfile size. "--> answers an Integer"
entries := zipfile entries.
entries asAnEnumeration do: [:each | Transcript cr; print: each].
----

And now to the ugly little secret reason why I call it an alpha version:

While everything seems to work, it is *much* slower than it used to be in
Pharo 1.2 with Alien. And when I compare it with VisualWorks, I wonder if
the Pharo version secretly does some additional work for SETI:
- Starting the JVM:
        VisualWorks 0.7 seconds
        Pharo 7 to 8 seconds
- A benchmark using some methods of java.io.BufferedReader and
java.util.StringTokenizer:
        VisualWorks 114 milliseconds
        Pharo 12 to 13 seconds

I have not yet found the reason. The TimeProfiler is not very helpful, as
its 1 millisecond resolution is too coarse. It would be nice if it had
microsecond resolution. From the TimeProfiler results, it seems that calling
a JNI method with NativeBoost is extremely slow, but I don't trust those
profiles too much.

So, give it a try, and if you find something useful concerning the bad
performance, please send me a message.

Best regards,
Joachim Geidel




--
View this message in context: http://forum.world.st/ANN-JNIPort-for-Pharo-3-0-alpha-tp4750750.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.



 

--

 

"Every thing has its own flow"




Ce courrier électronique ne contient aucun virus ou logiciel malveillant parce que la protection Antivirus avast! est active.





--

"Every thing has its own flow"
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

pharo4Stef@free.fr
In reply to this post by Joachim Geidel
EXCELLENT!!!!
Thanks for this important contribution.

Stef

On 25 Mar 2014, at 19:59, Joachim Geidel <[hidden email]> wrote:

> Hi everybody,
>
> JNIPort for Pharo 3.0 alpha is now available at SmalltalkHub.
>
> JNIPort is a Smalltalk library which allows Java code to be invoked from
> Smalltalk. It acts as a bridge between the world of Smalltalk objects and a
> Java Virtual Machine (JVM) where Java code is executing.
>
> When I first ported JNIPort to Squeak and Pharo 1.x, I used Alien as the FFI
> library. As NativeBoost has superseded Alien, the interface to the Java
> Native Interface library had to be rewritten. There are still some
> undocumented and obscure parts in NativeBoost, so this has taken some time.
>
> If you want to try it, load it via the ConfigurationOfJNIPort. I hope this
> works. If it does not, load the packages individually in the order in which
> they appear in the ConfigurationOfJNIPort.
> http://www.smalltalkhub.com/#!/~JNIPort/JNIPort
> The next step is to read the documentation at
> http://jniport.wikispaces.com/
> Otherwise, you won't know what to do next. ;-)
> Download the extra files from the download page at Wikispaces, you will need
> two jar files from there.
>
> Start a Java VM attached to Pharo by adapting and executing the following
> code snippet:
>
> ----
> | jvmSettings |
> "You can set the path to the Java VM library by editing the path as
> needed."
> JNIPortJNIInterface libraryFile:
> '/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libclient.dylib'
> .
> "JNIPortJNIInterface libraryFile:
> 'C:\Programme\Java\jre7\bin\client\jvm.dll' ."
>
> jvmSettings := JVMSettings new.
> jvmSettings usesGhosts: true.
> jvmSettings supportsCallbacks: true.
> jvmSettings jniPortSettings  useJNIHelperLibrary: false.
> jvmSettings ghostClassSettings retainMethodSource: true.
>
> "On Mac OS X and Linux, class path entries are separated by colons."
> "On Windows, you have to use semicolons instead. Edit the following line as
> needed."
> jvmSettings runtimeSettings classpath:
> '.:/Users/myname/JNIPort.jar:/Users/myname/JNIPort-Tests.jar'.
> " jvmSettings runtimeSettings classpath:
> '.;.\JNIPort.jar;.\JNIPort-Tests.jar'."
>
> "Uncomment the following if you want the Java VM to emit verbose messages.
> How to access these messages depends on your platform.
> On Mac OS X, they are visible in the Console application."
> "jvmSettings runtimeSettings addOption: '-verbose:jni'; addOption:
> '-verbose:gc'; addOption: '-verbose:class'."
> Cursor execute showWhile: [JVM newWithSettings: jvmSettings].
> ----
>
> Then the fun starts:
>
> ----
> | zfClass zipfile entries |
> zfClass := JVM current findClass: #'java.util.zip.ZipFile'.
> zipfile := zfClass new_String: 'JNIPort.jar'.
> zipfile size. "--> answers an Integer"
> entries := zipfile entries.
> entries asAnEnumeration do: [:each | Transcript cr; print: each].
> ----
>
> And now to the ugly little secret reason why I call it an alpha version:
>
> While everything seems to work, it is *much* slower than it used to be in
> Pharo 1.2 with Alien. And when I compare it with VisualWorks, I wonder if
> the Pharo version secretly does some additional work for SETI:
> - Starting the JVM:
> VisualWorks 0.7 seconds
> Pharo 7 to 8 seconds
> - A benchmark using some methods of java.io.BufferedReader and
> java.util.StringTokenizer:
> VisualWorks 114 milliseconds
> Pharo 12 to 13 seconds
>
> I have not yet found the reason. The TimeProfiler is not very helpful, as
> its 1 millisecond resolution is too coarse. It would be nice if it had
> microsecond resolution. From the TimeProfiler results, it seems that calling
> a JNI method with NativeBoost is extremely slow, but I don't trust those
> profiles too much.
>
> So, give it a try, and if you find something useful concerning the bad
> performance, please send me a message.
>
> Best regards,
> Joachim Geidel
>
>
>
>
> --
> View this message in context: http://forum.world.st/ANN-JNIPort-for-Pharo-3-0-alpha-tp4750750.html
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Joachim Geidel
In reply to this post by Tudor Girba-2
Hi Doru,

Am 27.03.2014 um 13:07 schrieb Tudor Girba:
> Just a question: is there a way to communicate with an already running VM that was started independently from Pharo?

JNIPort uses the Java VM as a DLL / shared library, using the Java Invocation Interface which is part of the Java Native Interface. Actually, the Java VM *is* a shared library, and the java.exe is just a wrapper for starting it. When using JNIPort, the Pharo VM and the Java VM run in the same operating system process, and communicating with the Java VM just means calling functions from a library.

Communicating with an already running Java VM is a totally different use case, as the Pharo VM and the Java VM run in two different operating system processes. To establish a communication between them, you would have to use an inter-process communication mechanism available in both of them. Pipes, TCP sockets, a messaging system, or running one of them as a server and the other as a client using a common protocol. That’s not what JNIPort is made for, and what you need for implementing it depends on the communication mechanism.

HTH,
Joachim


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Tudor Girba-2
Hi Joachim,

Thanks for the answer. I suspected that it goes in this direction :).

Now, the next question. I saw that it is possible to enable callbacks, but I could not find an example of how it works.

For example, could we model this:

- in a JavaClassOriginator class we have a method like
execute(JavaClassTargetInterface target) { target.m() }
- In Pharo we create PharoClassTargetImplementation as an implementation of JavaClassTargetInterface
- passing an instance of PharoClassTargetImplementation to JavaClassOriginator results in calling PharoClassTargetImplementation>>m

?


Cheers,
Doru



On Sat, Mar 29, 2014 at 11:32 AM, Joachim Geidel <[hidden email]> wrote:
Hi Doru,

Am 27.03.2014 um 13:07 schrieb Tudor Girba:
> Just a question: is there a way to communicate with an already running VM that was started independently from Pharo?

JNIPort uses the Java VM as a DLL / shared library, using the Java Invocation Interface which is part of the Java Native Interface. Actually, the Java VM *is* a shared library, and the java.exe is just a wrapper for starting it. When using JNIPort, the Pharo VM and the Java VM run in the same operating system process, and communicating with the Java VM just means calling functions from a library.

Communicating with an already running Java VM is a totally different use case, as the Pharo VM and the Java VM run in two different operating system processes. To establish a communication between them, you would have to use an inter-process communication mechanism available in both of them. Pipes, TCP sockets, a messaging system, or running one of them as a server and the other as a client using a common protocol. That’s not what JNIPort is made for, and what you need for implementing it depends on the communication mechanism.

HTH,
Joachim





--

"Every thing has its own flow"
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Joachim Geidel
Am 31.03.2014 um 21:25 schrieb Tudor Girba <[hidden email]>:

> Now, the next question. I saw that it is possible to enable callbacks, but I could not find an example of how it works.
>
> For example, could we model this:
>
> - in a JavaClassOriginator class we have a method like
> execute(JavaClassTargetInterface target) { target.m() }
> - In Pharo we create PharoClassTargetImplementation as an implementation of JavaClassTargetInterface
> - passing an instance of PharoClassTargetImplementation to JavaClassOriginator results in calling PharoClassTargetImplementation>>m
>
> ?
>
>
> Cheers,
> Doru

Hi Doru,

it’s not completely straightforward, but also not really complicated. Chris Uppal’s JNIPort documentation contains examples, and you can also get some information from the test cases for callbacks. You will need the jniport.jar file which can be downloaded from http://jniport.wikispaces.com/Downloads (it is contained in JNIPort_Extras.zip). The Java classes needed for callback support have names starting with „Dolphin“ - they come directly from Chris’ implementation for Dolphin Smalltalk.

A simple example: To set up sending a simple notification without parameters to a Smalltalk object, you need a Java class similar to the following:

-----------------
package my.package;
import org.metagnostic.jniport.*;
public class MyClass
{
        private static final Object notifyTag = new String("MyClass.sendNotification()“);
        public static Object notifyTag () { return notifyTag; }
        public void sendNotification()
                throws RequestNotHandedException
                {
                        new DolphinNotification(notifyTag, this).send();
                }
}
-----------------

You have to install the callback in Smalltalk:

-----------------
NotificationHandler := … "the object which receives the notifications"
classStatic := jvm findClass: 'my.package.MyClass'.
jvm callbackRegistry
        setCallback: classStatic notifyTag "the tag can be an arbitrary String"
        handler: [:this :param | NotificationHandler handleNotificationFor: this].
-----------------

When you send sendNotification() to an instance of MyClass, NotificationHandler should receive the message #handleNotificationFor:.

In the example code, the tag is a static variable in MyClass. Of course, you can also give every instance of MyClass its own tag. In this case, you have to set up a callback in Smalltalk for every tag which is used.

The example is a short version of the test code for handling notifications in JNIPortCallbackNotificationsTest and the corresponding Java class org.metagnostic.jniport.test.regression.Notifications. The source code of this Java class is in the archive JNIPort-Tests.zip which is contained in JNIPort_Extras.zip.

If you need an example for a notification which has parameters and where the Smalltalk code returns  a result, have a look at JNIPortCallbackRequestsTest>>testCallbackWithOneParameterAndReturn and the corresponding Java class org.metagnostic.jniport.test.regression.Callbacks.

In the Java class, you need something like this (copied from Callbacks and simplified) which enables a callback taking an int parameter and returning an instance of the Java class Integer:

         private static final Object callbackTag = new String(„callback with parameters"),

        // callback with return value
        public int callbackAndReturn(int i)
        throws Throwable
        {
                Object returnValue = new DolphinRequest(callbackTag, this, i).value();
                return ((Integer) returnValue).intValue();
        }

A DolphinRequest is created with the tag which identifies the callback in Smalltalk, the object sending the callback (this), and an arbitrary number of parameters. For example, the following creates a DolphinRequest with two parameters:

                DolphinRequest dr = new DolphinRequest(
                                        s_callbackTag,
                                        this,
                                        new Integer(i),
                                        new Double(d));

Calling the value() method of the DolphinRequest sends the request to VisualWorks and returns the result of the Smalltalk callback block.

In Smalltalk, you can create callbacks accepting parameters like this (see JNIPortCallbackRequestsTest):

        "No parameters"
        jvm callbackRegistry setCallback: classStatic callbackTag
                        handler: [:this :param | self handleCallbackFor: this].

        "One parameter"
        jvm callbackRegistry setCallback: classStatic callbackTag
                        handler: [:this :param | self handleCallbackFor: this with: param].

        "Arbitrary number of parameters"
        jvm callbackRegistry setCallback: classStatic callbackTag
                        handler: [:this :params | self handleCallbackFor: this withArguments: params asArray].

If the callback has a result which should be passed from Smalltalk to Java, it must be a Java object. Here is an example from the test class (callbacksStatus is just an instance variable of JNIPortCallbackRequestsTest):

handleCallbackFor: aJavaObject with: anotherJavaObject

        | jliClass |

        jliClass := jvm findClass: #'java.lang.Integer'.

        callbacksStatus addLast: (aJavaObject = instance). "identity test on the Java object"
        callbacksStatus addLast: ((anotherJavaObject static = jliClass) and: [anotherJavaObject intValue = 1]).

        ^ jliClass new_int: 15. "Do not return a Smalltalk Integer. It must be a Java Integer“

Johan Brichau’s JavaConnect had a more direct way of creating callbacks, using Java’s dynamic proxies. However, it had an open issue, as it relied on different Java objects having different identity hashes, which is not true in all cases. JNIPort’s implementation is relatively complicated because it had to take into account that the callbacks can be triggered from a different thread than the Smalltalk thread. In VisualWorks, that’s not a problem, as the VM handles this, and Pharo simply does not support callbacks from foreign threads. So, it could be simplified in JNIPort as well.

Does this help?
Joachim


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Igor Stasenko
In reply to this post by Joachim Geidel



On 25 March 2014 19:59, Joachim Geidel <[hidden email]> wrote:
Hi everybody,

JNIPort for Pharo 3.0 alpha is now available at SmalltalkHub.

JNIPort is a Smalltalk library which allows Java code to be invoked from
Smalltalk. It acts as a bridge between the world of Smalltalk objects and a
Java Virtual Machine (JVM) where Java code is executing.

When I first ported JNIPort to Squeak and Pharo 1.x, I used Alien as the FFI
library. As NativeBoost has superseded Alien, the interface to the Java
Native Interface library had to be rewritten. There are still some
undocumented and obscure parts in NativeBoost, so this has taken some time.

If you want to try it, load it via the ConfigurationOfJNIPort. I hope this
works. If it does not, load the packages individually in the order in which
they appear in the ConfigurationOfJNIPort.
        http://www.smalltalkhub.com/#!/~JNIPort/JNIPort
The next step is to read the documentation at
        http://jniport.wikispaces.com/
Otherwise, you won't know what to do next. ;-)
Download the extra files from the download page at Wikispaces, you will need
two jar files from there.

Start a Java VM attached to Pharo by adapting and executing the following
code snippet:

----
| jvmSettings |
 "You can set the path to the Java VM library by editing the path as
needed."
JNIPortJNIInterface libraryFile:
'/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libclient.dylib'
.
"JNIPortJNIInterface libraryFile:
'C:\Programme\Java\jre7\bin\client\jvm.dll' ."

 jvmSettings := JVMSettings new.
 jvmSettings usesGhosts: true.
 jvmSettings supportsCallbacks: true.
 jvmSettings jniPortSettings  useJNIHelperLibrary: false.
jvmSettings ghostClassSettings retainMethodSource: true.

 "On Mac OS X and Linux, class path entries are separated by colons."
 "On Windows, you have to use semicolons instead. Edit the following line as
needed."
jvmSettings runtimeSettings classpath:
'.:/Users/myname/JNIPort.jar:/Users/myname/JNIPort-Tests.jar'.
" jvmSettings runtimeSettings classpath:
'.;.\JNIPort.jar;.\JNIPort-Tests.jar'."

 "Uncomment the following if you want the Java VM to emit verbose messages.
  How to access these messages depends on your platform.
  On Mac OS X, they are visible in the Console application."
"jvmSettings runtimeSettings addOption: '-verbose:jni'; addOption:
'-verbose:gc'; addOption: '-verbose:class'."
Cursor execute showWhile: [JVM newWithSettings: jvmSettings].
----

Then the fun starts:

----
| zfClass zipfile entries |
zfClass := JVM current findClass: #'java.util.zip.ZipFile'.
zipfile := zfClass new_String: 'JNIPort.jar'.
zipfile size. "--> answers an Integer"
entries := zipfile entries.
entries asAnEnumeration do: [:each | Transcript cr; print: each].
----

And now to the ugly little secret reason why I call it an alpha version:

While everything seems to work, it is *much* slower than it used to be in
Pharo 1.2 with Alien. And when I compare it with VisualWorks, I wonder if
the Pharo version secretly does some additional work for SETI:
- Starting the JVM:
        VisualWorks 0.7 seconds
        Pharo 7 to 8 seconds
- A benchmark using some methods of java.io.BufferedReader and
java.util.StringTokenizer:
        VisualWorks 114 milliseconds
        Pharo 12 to 13 seconds


profiled a bit.. this:
===================
| jvmSettings |
 "You can set the path to the Java VM library by editing the path as
needed."
JNIPortJNIInterface libraryFile:
'/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libclient.dylib'
.
"JNIPortJNIInterface libraryFile:
'C:\Programme\Java\jre7\bin\client\jvm.dll' ."

 jvmSettings := JVMSettings new.
 jvmSettings usesGhosts: true.
 jvmSettings supportsCallbacks: true.
 jvmSettings jniPortSettings  useJNIHelperLibrary: false.
jvmSettings ghostClassSettings retainMethodSource: true.

JVM newWithSettings: jvmSettings
==============
and got this:

**Leaves**
22.8% {925ms} StaticJavaLangClassLoader(JavaStatic)>>knownJavaSubclasses
19.9% {804ms} JVMWithCallbacks(JVM)>>findClassFor:
5.9% {240ms} OrderedCollection>>do:
5.1% {206ms} Metaclass(Behavior)>>registerLocalSelector:
3.0% {120ms} JNIPortJNIEnv>>return:onException:
2.2% {91ms} CompiledMethod>>methodClass:
2.2% {88ms} OrderedCollection>>add:
2.1% {84ms} Array(SequenceableCollection)>>do:
2.0% {81ms} WordArray class(Behavior)>>new:
2.0% {79ms} WeakArray class>>finalizationProcess
1.3% {52ms} JNIPortJNIInterfaceForMacOSX(JNIPortJNIInterface)>>checkReturnCode:
1.1% {46ms} Heap>>updateObjectIndex:

-------------
findClassFor: aJNIObject
    "private -- find/make the JavaStatic that will wrap aJNIObject"

    "we have to ensure that the ref is converted to global if necessary *before* the class
    lookup, since that might take considerable time during which callbacks might happen
    (especially if new ghost classes have to be constructed).
    Hence we convert it now, even though we will 'convert' again later (in #own:)"

    "NB: this will #become: the JNIObject into a global ref if necessary"
    self convertToGlobal: aJNIObject.

    ^ super findClassFor: aJNIObject.
----------

so, without going deep into implementation details, just by reading comment
i can already see potential bottleneck - using #become: operation which is veery slow.

also, by tracking senders of #knownJavaSubclasses , i see there's also uses of #become operation..

So, my first verdict is:
       - excessive use of #become ==> slow performance
:)

(sure, i have no idea if you can avoid using become or not, but my bet this  is main reason of low performance)

--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

pharo4Stef@free.fr
In reply to this post by Joachim Geidel
Joachim

would you be interested to write a little Chpater for the Pharo for the entreprise book?
I can help.

Ste

On 05 Apr 2014, at 14:32, Joachim Geidel <[hidden email]> wrote:

> Am 31.03.2014 um 21:25 schrieb Tudor Girba <[hidden email]>:
>> Now, the next question. I saw that it is possible to enable callbacks, but I could not find an example of how it works.
>>
>> For example, could we model this:
>>
>> - in a JavaClassOriginator class we have a method like
>> execute(JavaClassTargetInterface target) { target.m() }
>> - In Pharo we create PharoClassTargetImplementation as an implementation of JavaClassTargetInterface
>> - passing an instance of PharoClassTargetImplementation to JavaClassOriginator results in calling PharoClassTargetImplementation>>m
>>
>> ?
>>
>>
>> Cheers,
>> Doru
>
> Hi Doru,
>
> it’s not completely straightforward, but also not really complicated. Chris Uppal’s JNIPort documentation contains examples, and you can also get some information from the test cases for callbacks. You will need the jniport.jar file which can be downloaded from http://jniport.wikispaces.com/Downloads (it is contained in JNIPort_Extras.zip). The Java classes needed for callback support have names starting with „Dolphin“ - they come directly from Chris’ implementation for Dolphin Smalltalk.
>
> A simple example: To set up sending a simple notification without parameters to a Smalltalk object, you need a Java class similar to the following:
>
> -----------------
> package my.package;
> import org.metagnostic.jniport.*;
> public class MyClass
> {
> private static final Object notifyTag = new String("MyClass.sendNotification()“);
> public static Object notifyTag () { return notifyTag; }
> public void sendNotification()
> throws RequestNotHandedException
> {
> new DolphinNotification(notifyTag, this).send();
> }
> }
> -----------------
>
> You have to install the callback in Smalltalk:
>
> -----------------
> NotificationHandler := … "the object which receives the notifications"
> classStatic := jvm findClass: 'my.package.MyClass'.
> jvm callbackRegistry
> setCallback: classStatic notifyTag "the tag can be an arbitrary String"
> handler: [:this :param | NotificationHandler handleNotificationFor: this].
> -----------------
>
> When you send sendNotification() to an instance of MyClass, NotificationHandler should receive the message #handleNotificationFor:.
>
> In the example code, the tag is a static variable in MyClass. Of course, you can also give every instance of MyClass its own tag. In this case, you have to set up a callback in Smalltalk for every tag which is used.
>
> The example is a short version of the test code for handling notifications in JNIPortCallbackNotificationsTest and the corresponding Java class org.metagnostic.jniport.test.regression.Notifications. The source code of this Java class is in the archive JNIPort-Tests.zip which is contained in JNIPort_Extras.zip.
>
> If you need an example for a notification which has parameters and where the Smalltalk code returns  a result, have a look at JNIPortCallbackRequestsTest>>testCallbackWithOneParameterAndReturn and the corresponding Java class org.metagnostic.jniport.test.regression.Callbacks.
>
> In the Java class, you need something like this (copied from Callbacks and simplified) which enables a callback taking an int parameter and returning an instance of the Java class Integer:
>
> private static final Object callbackTag = new String(„callback with parameters"),
>
> // callback with return value
> public int callbackAndReturn(int i)
> throws Throwable
> {
> Object returnValue = new DolphinRequest(callbackTag, this, i).value();
> return ((Integer) returnValue).intValue();
> }
>
> A DolphinRequest is created with the tag which identifies the callback in Smalltalk, the object sending the callback (this), and an arbitrary number of parameters. For example, the following creates a DolphinRequest with two parameters:
>
> DolphinRequest dr = new DolphinRequest(
> s_callbackTag,
> this,
> new Integer(i),
> new Double(d));
>
> Calling the value() method of the DolphinRequest sends the request to VisualWorks and returns the result of the Smalltalk callback block.
>
> In Smalltalk, you can create callbacks accepting parameters like this (see JNIPortCallbackRequestsTest):
>
> "No parameters"
> jvm callbackRegistry setCallback: classStatic callbackTag
> handler: [:this :param | self handleCallbackFor: this].
>
> "One parameter"
> jvm callbackRegistry setCallback: classStatic callbackTag
> handler: [:this :param | self handleCallbackFor: this with: param].
>
> "Arbitrary number of parameters"
> jvm callbackRegistry setCallback: classStatic callbackTag
> handler: [:this :params | self handleCallbackFor: this withArguments: params asArray].
>
> If the callback has a result which should be passed from Smalltalk to Java, it must be a Java object. Here is an example from the test class (callbacksStatus is just an instance variable of JNIPortCallbackRequestsTest):
>
> handleCallbackFor: aJavaObject with: anotherJavaObject
>
> | jliClass |
>
> jliClass := jvm findClass: #'java.lang.Integer'.
>
> callbacksStatus addLast: (aJavaObject = instance). "identity test on the Java object"
> callbacksStatus addLast: ((anotherJavaObject static = jliClass) and: [anotherJavaObject intValue = 1]).
>
> ^ jliClass new_int: 15. "Do not return a Smalltalk Integer. It must be a Java Integer“
>
> Johan Brichau’s JavaConnect had a more direct way of creating callbacks, using Java’s dynamic proxies. However, it had an open issue, as it relied on different Java objects having different identity hashes, which is not true in all cases. JNIPort’s implementation is relatively complicated because it had to take into account that the callbacks can be triggered from a different thread than the Smalltalk thread. In VisualWorks, that’s not a problem, as the VM handles this, and Pharo simply does not support callbacks from foreign threads. So, it could be simplified in JNIPort as well.
>
> Does this help?
> Joachim
>
>


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Joachim Geidel
In reply to this post by Igor Stasenko
Hi Igor,

thanks a lot, your analysis is correct, and it helped.

Am 05.04.2014 um 17:05 schrieb Igor Stasenko:
> so, without going deep into implementation details, just by reading comment
> i can already see potential bottleneck - using #become: operation which is veery slow.

Yes, #become: is *very* slow in Pharo. No problem at all in VisualWorks or Dolphin Smalltalk or Pharo 1.2, though!

Time millisecondsToRun: [1000 timesRepeat: [String new become: String new ]]

Pharo 3.0 (and also in 2.0 and 1.4):
 3948 3495 2891 2532 3162

Pharo 1.2 with the Squeak 4.2.5beta1U VM:
 90 89 82 90 72

VisualWorks 7.9.1: note that this is measured in microseconds:
Time microsecondsToRun: [1000 timesRepeat: [String new become: String new ]]
 211 208 222 212 208

That’s a factor of more than 10.000! IMHO, someone should have a look at the primitives involved.

> also, by tracking senders of #knownJavaSubclasses , i see there's also uses of #become operation..
>
> So, my first verdict is:
>        - excessive use of #become ==> slow performance
> :)
>
> (sure, i have no idea if you can avoid using become or not, but my bet this  is main reason of low performance)

Well, given the measurements above, I wouldn’t say that the reason is excessive use of #become:, but the extremely slow implementation of #become: in Pharo since 1.4. However, I managed to remove the need for sending #become: in #findClassFor:, but not in the second place. This reduces the time to start a Java VM to 5-6 seconds on my aged machine (2.4 GHz Intel Core 2 Duo from early 2008). The benchmark which I mentioned in my announcement and which took 12 seconds came down to less than 0.2 seconds. That's a little more than the 0.11 seconds in VisualWorks, but at least in the same order of magnitude.

Thanks again!
Joachim


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

pharo4Stef@free.fr

On 05 Apr 2014, at 23:35, Joachim Geidel <[hidden email]> wrote:

> Hi Igor,
>
> thanks a lot, your analysis is correct, and it helped.
>
> Am 05.04.2014 um 17:05 schrieb Igor Stasenko:
>> so, without going deep into implementation details, just by reading comment
>> i can already see potential bottleneck - using #become: operation which is veery slow.
>
> Yes, #become: is *very* slow in Pharo. No problem at all in VisualWorks or Dolphin Smalltalk or Pharo 1.2, though!
>
> Time millisecondsToRun: [1000 timesRepeat: [String new become: String new ]]
>
> Pharo 3.0 (and also in 2.0 and 1.4):
> 3948 3495 2891 2532 3162
>
> Pharo 1.2 with the Squeak 4.2.5beta1U VM:
> 90 89 82 90 72

these numbers are strange. Because mariano used a lot become: and he did not report a factor like that.
Thanks for reporting them.

>
> VisualWorks 7.9.1: note that this is measured in microseconds:
> Time microsecondsToRun: [1000 timesRepeat: [String new become: String new ]]
> 211 208 222 212 208

this will be fixed with spur and body.

>
> That’s a factor of more than 10.000! IMHO, someone should have a look at the primitives involved.
>
>> also, by tracking senders of #knownJavaSubclasses , i see there's also uses of #become operation..
>>
>> So, my first verdict is:
>>       - excessive use of #become ==> slow performance
>> :)
>>
>> (sure, i have no idea if you can avoid using become or not, but my bet this  is main reason of low performance)
>
> Well, given the measurements above, I wouldn’t say that the reason is excessive use of #become:, but the extremely slow implementation of #become: in Pharo since 1.4. However, I managed to remove the need for sending #become: in #findClassFor:, but not in the second place. This reduces the time to start a Java VM to 5-6 seconds on my aged machine (2.4 GHz Intel Core 2 Duo from early 2008). The benchmark which I mentioned in my announcement and which took 12 seconds came down to less than 0.2 seconds. That's a little more than the 0.11 seconds in VisualWorks, but at least in the same order of magnitude.
>
> Thanks again!
> Joachim
>
>


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Tudor Girba-2
In reply to this post by Joachim Geidel
Hi Joachim,

Thanks for the explanations. It looks complicated but I am very happy it is possible!

I will give a try next week and get back to you.

Cheers,
Doru


On Sat, Apr 5, 2014 at 2:32 PM, Joachim Geidel <[hidden email]> wrote:
Am 31.03.2014 um 21:25 schrieb Tudor Girba <[hidden email]>:
> Now, the next question. I saw that it is possible to enable callbacks, but I could not find an example of how it works.
>
> For example, could we model this:
>
> - in a JavaClassOriginator class we have a method like
> execute(JavaClassTargetInterface target) { target.m() }
> - In Pharo we create PharoClassTargetImplementation as an implementation of JavaClassTargetInterface
> - passing an instance of PharoClassTargetImplementation to JavaClassOriginator results in calling PharoClassTargetImplementation>>m
>
> ?
>
>
> Cheers,
> Doru

Hi Doru,

it’s not completely straightforward, but also not really complicated. Chris Uppal’s JNIPort documentation contains examples, and you can also get some information from the test cases for callbacks. You will need the jniport.jar file which can be downloaded from http://jniport.wikispaces.com/Downloads (it is contained in JNIPort_Extras.zip). The Java classes needed for callback support have names starting with „Dolphin“ - they come directly from Chris’ implementation for Dolphin Smalltalk.

A simple example: To set up sending a simple notification without parameters to a Smalltalk object, you need a Java class similar to the following:

-----------------
package my.package;
import org.metagnostic.jniport.*;
public class MyClass
{
        private static final Object     notifyTag = new String("MyClass.sendNotification()“);
        public static Object notifyTag () { return notifyTag; }
        public void sendNotification()
                throws RequestNotHandedException
                {
                        new DolphinNotification(notifyTag, this).send();
                }
}
-----------------

You have to install the callback in Smalltalk:

-----------------
NotificationHandler := … "the object which receives the notifications"
classStatic := jvm findClass: 'my.package.MyClass'.
jvm callbackRegistry
        setCallback: classStatic notifyTag "the tag can be an arbitrary String"
        handler: [:this :param | NotificationHandler handleNotificationFor: this].
-----------------

When you send sendNotification() to an instance of MyClass, NotificationHandler should receive the message #handleNotificationFor:.

In the example code, the tag is a static variable in MyClass. Of course, you can also give every instance of MyClass its own tag. In this case, you have to set up a callback in Smalltalk for every tag which is used.

The example is a short version of the test code for handling notifications in JNIPortCallbackNotificationsTest and the corresponding Java class org.metagnostic.jniport.test.regression.Notifications. The source code of this Java class is in the archive JNIPort-Tests.zip which is contained in JNIPort_Extras.zip.

If you need an example for a notification which has parameters and where the Smalltalk code returns  a result, have a look at JNIPortCallbackRequestsTest>>testCallbackWithOneParameterAndReturn and the corresponding Java class org.metagnostic.jniport.test.regression.Callbacks.

In the Java class, you need something like this (copied from Callbacks and simplified) which enables a callback taking an int parameter and returning an instance of the Java class Integer:

         private static final Object callbackTag = new String(„callback with parameters"),

        // callback with return value
        public int callbackAndReturn(int i)
        throws Throwable
        {
                Object returnValue = new DolphinRequest(callbackTag, this, i).value();
                return ((Integer) returnValue).intValue();
        }

A DolphinRequest is created with the tag which identifies the callback in Smalltalk, the object sending the callback (this), and an arbitrary number of parameters. For example, the following creates a DolphinRequest with two parameters:

                DolphinRequest dr = new DolphinRequest(
                                        s_callbackTag,
                                        this,
                                        new Integer(i),
                                        new Double(d));

Calling the value() method of the DolphinRequest sends the request to VisualWorks and returns the result of the Smalltalk callback block.

In Smalltalk, you can create callbacks accepting parameters like this (see JNIPortCallbackRequestsTest):

        "No parameters"
        jvm callbackRegistry setCallback: classStatic callbackTag
                        handler: [:this :param | self handleCallbackFor: this].

        "One parameter"
        jvm callbackRegistry setCallback: classStatic callbackTag
                        handler: [:this :param | self handleCallbackFor: this with: param].

        "Arbitrary number of parameters"
        jvm callbackRegistry setCallback: classStatic callbackTag
                        handler: [:this :params | self handleCallbackFor: this withArguments: params asArray].

If the callback has a result which should be passed from Smalltalk to Java, it must be a Java object. Here is an example from the test class (callbacksStatus is just an instance variable of JNIPortCallbackRequestsTest):

handleCallbackFor: aJavaObject with: anotherJavaObject

        | jliClass |

        jliClass := jvm findClass: #'java.lang.Integer'.

        callbacksStatus addLast: (aJavaObject = instance).      "identity test on the Java object"
        callbacksStatus addLast: ((anotherJavaObject static = jliClass) and: [anotherJavaObject intValue = 1]).

        ^ jliClass new_int: 15. "Do not return a Smalltalk Integer. It must be a Java Integer“

Johan Brichau’s JavaConnect had a more direct way of creating callbacks, using Java’s dynamic proxies. However, it had an open issue, as it relied on different Java objects having different identity hashes, which is not true in all cases. JNIPort’s implementation is relatively complicated because it had to take into account that the callbacks can be triggered from a different thread than the Smalltalk thread. In VisualWorks, that’s not a problem, as the VM handles this, and Pharo simply does not support callbacks from foreign threads. So, it could be simplified in JNIPort as well.

Does this help?
Joachim





--

"Every thing has its own flow"
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Joachim Geidel
BTW, I have published an updated version of JNIPort which partly resolves the performance issue caused by using #become:.

Joachim
--
My OpenPGP Key: 29F88108 available from hkp://wwwkeys.de.pgp.net
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Sven Van Caekenberghe-2
In reply to this post by Joachim Geidel

On 05 Apr 2014, at 23:35, Joachim Geidel <[hidden email]> wrote:

> Yes, #become: is *very* slow in Pharo. No problem at all in VisualWorks or Dolphin Smalltalk or Pharo 1.2, though!
>
> Time millisecondsToRun: [1000 timesRepeat: [String new become: String new ]]
>
> Pharo 3.0 (and also in 2.0 and 1.4):
> 3948 3495 2891 2532 3162
>
> Pharo 1.2 with the Squeak 4.2.5beta1U VM:
> 90 89 82 90 72
>
> VisualWorks 7.9.1: note that this is measured in microseconds:
> Time microsecondsToRun: [1000 timesRepeat: [String new become: String new ]]
> 211 208 222 212 208

Yes, this is an extreme difference.

On my machine, the above takes between 1 and 2 seconds in Pharo 3 (Pharo VM) and Squeak 4.5 (Cog VM), while VW 7.1 takes just 100 to 200 microseconds.

Normally, #become: has to iterate over all memory, but this benchmark is a bit special, since it involves two new objects, maybe VW's memory manager somehow optimises this away.

Sven
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

pharo4Stef@free.fr
In VW there is the concept of object bodies and head now we will eventually have that with Spur. Maybe clement explained it somewhere in his blog (I understood the point once and of course I forgot).

Now I wonder what changed so much between 1.2 and 3.0

>
>> Yes, #become: is *very* slow in Pharo. No problem at all in VisualWorks or Dolphin Smalltalk or Pharo 1.2, though!
>>
>> Time millisecondsToRun: [1000 timesRepeat: [String new become: String new ]]
>>
>> Pharo 3.0 (and also in 2.0 and 1.4):
>> 3948 3495 2891 2532 3162
>>
>> Pharo 1.2 with the Squeak 4.2.5beta1U VM:
>> 90 89 82 90 72
>>
>> VisualWorks 7.9.1: note that this is measured in microseconds:
>> Time microsecondsToRun: [1000 timesRepeat: [String new become: String new ]]
>> 211 208 222 212 208
>
> Yes, this is an extreme difference.
>
> On my machine, the above takes between 1 and 2 seconds in Pharo 3 (Pharo VM) and Squeak 4.5 (Cog VM), while VW 7.1 takes just 100 to 200 microseconds.
>
> Normally, #become: has to iterate over all memory, but this benchmark is a bit special, since it involves two new objects, maybe VW's memory manager somehow optimises this away.
>
> Sven


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Joachim Geidel
In reply to this post by Joachim Geidel
Hi everbody,

I have published an update of JNIPort 3.0 alpha at SmalltalkHub.

Changes from the previous version:
- The Java classes needed for calling back from Java into Smalltalk and for executing the regression tests have been updated. I have shortened the Java package name from org.metagnostic.jniport to just jniport, and renamed those classes which had „Dolphin“ in their class name. JNIPort has been developed for Dolphin Smalltalk by Chris Uppal, but it is available for VisualWorks and Pharo, too. Therefore I decided that the references to Dolphin are obsolete. Some methods have been renamed for the same reason.
- The class files in the jars have been compiled with Java 1.6. I don’t think that the old class files compiled with Java 1.4 (or earlier?) would be a problem, but still... (and I don’t have anything earlier than Java 1.6 anyway).
- Several Smalltalk wrapper classes and methods for the renamed Java classes and methods have been renamed as well. The new names should be more obvious than the old ones.
- The performance problem from the first alpha version has been partly solved. The rest is caused by longer execution times for #become: in Pharo - I can’t do anything about it for the moment.

If you want to use the new version, download it from SmalltalkHub, and get the archive JNIPort30-Extras.zip containing the updated jar files from the JNIPort wiki (see below). The new jar files are called JNIPort30.jar and JNIPort30-Tests.jar instead of JNIPort.jar and JNIPort-Tests.jar, such that you can use the old and the new version in parallel, if there is any need for it.

For those who don’t know what JNIPort is:

> JNIPort is a Smalltalk library which allows Java code to be invoked from
> Smalltalk. It acts as a bridge between the world of Smalltalk objects and a
> Java Virtual Machine (JVM) where Java code is executing.
>
> If you want to try it, load it via the ConfigurationOfJNIPort. I hope this
> works. If it does not, load the packages individually in the order in which
> they appear in the ConfigurationOfJNIPort.
> http://www.smalltalkhub.com/#!/~JNIPort/JNIPort
> The next step is to read the documentation at
> http://jniport.wikispaces.com/
> Otherwise, you won't know what to do next. ;-)
> Download the extra files from the download page at Wikispaces, you will need
> two jar files from there.

Issues:
- Callbacks from „foreign“ threads, i.e. threads in the Java VM other than the one in which the Smalltalk VM runs, should be handled by the callback queueing mechanism implemented by the classes in JNIPort30.jar. This mechanism ensures that the callback into Smalltalk is executed in the Smalltalk thread. This works in VisualWorks and Dolphin, but in Pharo it leads to a crash of the VM when executing the Smalltalk callback block which is installed as a native method in Java space. I have as yet no idea why this does not work.
- The JNIPort wiki lacks documentation about the Pharo version and a recipe for using callbacks. The latter is hidden in the original documentation by Chris Uppal, which can be downloaded from the wiki.
- No tool support in Pharo yet. In VisualWorks, there is a settings editor, storage of settings in a „registry“ (on Windows, this is the „real“ registry), and there are menu items in the system browser for generating Smalltalk wrapper classes for Java classes. None of this exists for Pharo yet.

Best regards,
Joachim Geidel


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] JNIPort for Pharo 3.0 alpha

Esteban A. Maringolo
In reply to this post by pharo4Stef@free.fr
2014-04-08 16:04 GMT-03:00 Pharo4Stef <[hidden email]>:
> In VW there is the concept of object bodies and head now we will eventually have that with Spur. Maybe clement explained it somewhere in his blog (I understood the point once and of course I forgot).
>
> Now I wonder what changed so much between 1.2 and 3.0

Dolphin's #become: uses the same concept.

E.g. a become: b
Doesn't switch references, but instead "body" pointers in a and b. It
is, a becomes b, and b becomes a. i

Time microsecondsToRun: [1000 timesRepeat: [String new become: String new ]].
684 898 663 812 665


Also, there is a #oneWayBecome: which DOES an object table scan, and
makes all references to the receiver point to the argument object (it
is, a becomes b, and not the other way around). This gets slow
directly proportional to the size of the OT.

Time microsecondsToRun: [1000 timesRepeat: [String new become: String new ]].
10936532

Most proxies and stubs implementations in Dolphin uses #become:
because it is instantaneous, and the "old" object (b in this)
eventually gets garbage collected.

Regards.

Esteban A. Maringolo