[ome-devel] Bio-Formats Ice bindings

Curtis Rueden ctrueden at wisc.edu
Tue Jul 5 17:29:40 BST 2011


Hi Mario,

Thanks for the summary of issues.

So the full payoff only comes if the main application is ignorant of Java,
> and communicates only via sockets (or something).
>

Many of the reasons you cite are very similar to what the ITK (
http://itk.org/) developers listed regarding the Bio-Formats ITK plugin (
http://www.loci.wisc.edu/bio-formats/itk). Essentially, compiling bf-cpp
cross-platform is a substantial burden, and produces an unnecessarily large
library with many compile-time dependencies (Java and Boost in particular).

Nonetheless, using Ice instead, while powerful, is not the simplest
solution. Though Ice is cross-platform, it constitutes another library
dependency and complexifies the build process. What we decided to do instead
for the ITK plugin is to use pipes, which address all the issues you listed,
and are surprisingly efficient (slightly faster than JNI, in our tests). We
actually wrote functional implementations of the Bio-Formats ITK plugin with
three different approaches:

  1. Jace -- using bf-cpp as you know it
  2. raw JNI -- using JNI directly without Jace
  3. pipes -- using system calls to invoke Java and pass data

For code, see:

http://git.openmicroscopy.org/?p=bioformats.git;a=tree;f=components/native;hb=HEAD

We found that #3 was much easier to compile cross-platform (no dependencies)
and also faster than #2.

Once we have Bio-Formats Ice bindings again, it would be interesting to
implement the Bio-Formats ITK plugin using them as well, to compare
performance with the others.

For XuvTools, you might consider using a similar approach, rather than
waiting for an Ice-based solution that would still be more complex to
compile than the pipes approach. (One major advantage of Ice is that it can
be run client/server on different machines, but that doesn't seem necessary
for XuvTools.)

Thanks Curtis for this awesome first test, I will try to compile it cross-
> platform and see how that works for me! I'll let you know how it goes, and
> possibly we can compare some runtimes of ICE versus Jace/JNI.
>

No problem. If you do end up playing with the code, one thing I realized is
that the entry point into the Ice server should not be an IFormatReader
instance. It should probably be a utility class "Main" or something that
provides all the constructors for the various objects. As such, it would
provide hooks into the entire Bio-Formats Java API (or a specific subset, to
limit the size and complexity of the resultant library).

Based on our discussions, I filed a few tickets relating to the Bio-Formats
C++ and Ice bindings, and related tasks:

  http://dev.imagejdev.org/trac/imagej/ticket/653
  http://dev.imagejdev.org/trac/imagej/ticket/654
  http://dev.imagejdev.org/trac/imagej/ticket/655
  http://dev.imagejdev.org/trac/imagej/ticket/656
  http://dev.imagejdev.org/trac/imagej/ticket/657
  http://dev.imagejdev.org/trac/imagej/ticket/658
  http://dev.imagejdev.org/trac/imagej/ticket/659

If any of these are of interest, let me know and I can add you to the CC
list.

Unfortunately, I am swamped with ImageJ2 tasks, and will probably not have
time to work on the Bio-Formats Ice bindings further for a few months, as
much as I wish I could.

Regards,
Curtis

On Fri, Jul 1, 2011 at 7:15 AM, Mario Emmenlauer <mario at emmenlauer.de>wrote:

>
> Hi,
>
> sorry for my late reply, I was on holidays for a while :-)
> Thanks Curtis for the quick followup! Below my comments:
>
> On 06/30/2011 10:38 PM, Curtis Rueden wrote:
> > Hi Josh,
> >
> >     Was your and Mario's primary goal to get away from the in-process
> issues of
> >     the JVM? Would it be an option to fork, create the JVM, and then use
> Ice
> >     rather than raw sockets for the communication? In that case would you
> need
> >     all objects? Or does the API that Mario is already using come close
> to
> >     sufficing? What are the other features/requirements that need to be
> added?
> >
> >
> > I believe the goal was to have an inter-process solution to decouple the
> JVM a
> > bit from the C++ program. However, I admit that I am fuzzy on the
> specifics of
> > why Mario wants an inter-process solution. In his talk, he mentioned one
> problem
> > with allocating memory to the JVM a priori, and how to deal with
> > OutOfMemoryError, but I am not clear on why an inter-process solution
> would
> > improve on that situation. Mario, any comments?
>
> Yes, the main goal is to get away from the in-process issues of the JVM,
> especially the memory problem, but in addition one goal is to avoid a
> library
> problem with Java. Here a more detailed description:
> (1) Java memory hog: the JVM does not free memory back to the System,
>    even when calling the gc() explicitly. Memory becomes available to
>    other JVM usage, but not available to the OS (and neither to C++)
>    anymore, so its "lost" for the main application.
> (2) Insufficient Java memory: When creating the JVM, an appropriate
>    upper memory limit has to be set. If later during runtime this turns
>    out to be insufficient, the JVM can not be re-created (its a singleton).
>    Therefore, the main application needs to exit and re-start for the JVM
>    memory to be increased.
> (3) Java library path: The application that uses Bio-Formats needs to
>    resolve at invocation libjvm.so (jvm.dll on Windows). On Windows,
>    this is typically done by setting the PATH for the application in
>    the registry. If a system-wide Java is used, this path is unknown.
>    Therefore, XuvTools ships its own, private Java (an 1200% increase
>    in installer size). If the Bio-Formats would be a separate executable
>    started via system() or similar, the library path (to the system-wide
>    Java) could be dynamically resolved by the main application before-
>    hand.
> (4) Increasing modularity: Compiling C++ against Java cross-platform is
>    painfull. If C++-Bio-Formats would be a separate executable, developers
>    of the main application would not have to care (it could come with a
>    separate installer).
>
> So the full payoff only comes if the main application is ignorant of Java,
> and communicates only via sockets (or something). Note that (1) and (2)
> together create a chicken-egg-problem of setting a good initial JVM memory
> size :-)
>
>
> >     Curtis, I assume your plan is to turn everything into an Ice Prx?
> e.g. would
> >     you have an IRandomAccessPrx? If so, I'm skeptical that this would
> work as
> >     well as you want.
> >
> >
> > Yep, everything would be exposed as proxies. So sure, there would be an
> > IRandomAccessPrx, but it's not like most consumers of the API would
> actually
> > make use of it (since I agree, it would be awful performance-wise). Most
> people
> > would interact with the Java library at a less fine-grained level—e.g.,
> calling
> > IFormatReader.openBytes to grab one plane at a time. There is still
> overhead at
> > that level, but much less.
>
> This would translate 1:1 to my current interface, sounds great! Anyways I
> should mention that pixel access with Jace/JNI has horrible performance -
> copying one image plane pixel-by-pixel was on the order of several seconds,
> whereas memcopy() or GetArrayRegion() take milliseconds. So ICE would
> likely
> not do much worse, at least on localhost :-)
>
>
> >     I can't remember the specific problem we were having, Curtis. To you
> have
> >     that email still and/or link on ome-devel? I found only
> >
> http://lists.openmicroscopy.org.uk/pipermail/ome-devel/2010-October/001733.html
> >
> >
> > I couldn't find it on the mailing list either; perhaps we discussed it
> over chat.
> >
> > To understand the problem again after so long, I mocked up a Slice
> interface for
> > a small subset of the Bio-Formats API. In so doing, I found the solution
> to the
> > previous issue on this page of the Ice manual:
> >
> >   http://doc.zeroc.com/display/Ice/Object+Incarnation+in+Java
> >
> > To describe briefly, say we have the following Slice definition:
> >
> >   interface CoreMetadata;
> >   interface IMetadata;
> >   interface IFormatReader {
> >     CoreMetadata* getCoreMetadata();
> >     IMetadata* getMetadataStore();
> >   };
> >
> > When implementing servants on the server side, you must implement methods
> that
> > return proxies of other servants; e.g.:
> >
> >     public CoreMetadataPrx getCoreMetadata(Current current);
> >     public IMetadataPrx getMetadataStore(Current current);
> >
> > I was stumped on how to translate a server-side Java object into a proxy
> of a
> > servant that wraps that object. The solution (from the Ice page linked
> above) is:
> >
> >   CoreMetadataPrx proxy = CoreMetadataPrxHelper.uncheckedCast(
> >     current.adapter.addWithUUID(new CoreMetadataI(coreMetadata)));
> >
> > (Assuming that the CoreMetadataI servant implementation has a constructor
> that
> > takes a CoreMetadata object, of course.)
> >
> > Personally, I would describe that invocation as "horribly unintuitive"
> and
> > perhaps "needlessly complex" (why not "current.adapter.createProxy(new
> > CoreMetadataI(coreMetadata))"), but at least there is a way to do it!
> >
> > I have posted my full solution at:
> >
> >   http://dev.loci.wisc.edu/curtis/bf-ice/
> >
> > There are shell scripts for launching the server and the client, and a
> small
> > test to verify that information is being communicated properly. All
> works, so I
> > think my proposal to autogenerate a Slice file from a Java JAR file is
> doable.
> > The only question is: when will I find the time?
>
> Thanks Curtis for this awesome first test, I will try to compile it cross-
> platform and see how that works for me! I'll let you know how it goes, and
> possibly we can compare some runtimes of ICE versus Jace/JNI.
>
> All the best,
>
>    Mario
>
>
>
> >
> > Regards,
> > Curtis
> >
> > On Tue, Jun 21, 2011 at 7:12 AM, Josh Moore <josh at glencoesoftware.com
> > <mailto:josh at glencoesoftware.com>> wrote:
> >
> >
> >     On Jun 17, 2011, at 11:17 AM, Curtis Rueden wrote:
> >
> >     > Hi everyone,
> >
> >     Hi,
> >
> >     > Yesterday Mario Emmenlauer and I discussed the Bio-Formats Ice
> bindings, and
> >     > how it would be nice to resurrect them so that Bio-Formats has an
> >     > inter-process, cross-language integration solution.
> >     >
> >     > I started looking at how best to resurrect them. The way they were
> being
> >     > done before was very ad hoc. We generated them from a Velocity
> template that
> >     > was quite hard-coded in many ways compared to the way the way the
> C++
> >     > bindings work. See:
> >     >
> >     >
> >     >
> >
> http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/autogen/src/ice/bio-formats.vm;hb=HEAD
> >     >
> >     > In contrast, the C++ bindings wrap every method of every Java class
> in
> >     > bio-formats.jar, loci-common.jar and ome-xml.jar.
> >     >
> >     > We could do something similar for the Bio-Formats Ice
> bindings—generate a
> >     > Slice file mirroring the Bio-Formats API as fully as possible—but
> it would
> >     > require a bit of work. And of course it results in a very granular
> remoting
> >     > API compared to how people often use Ice. Nonetheless, it would
> make for an
> >     > intuitive API, as long as people exercise some care not to make too
> many
> >     > remote calls as Mario mentioned in his XuvTools talk yesterday.
> >     >
> >     > Do others agree that such a thing would be useful? If so, I am
> thinking
> >     > about how best to implement it. My initial inclination is to write
> some Java
> >     > code that takes a JAR file as input, and generates a Slice file
> with
> >     > interfaces mirroring each class in the JAR, as well as the Java
> server
> >     > implementation code that simply delegates to the wrapped JAR.
> >
> >     Was your and Mario's primary goal to get away from the in-process
> issues of
> >     the JVM? Would it be an option to fork, create the JVM, and then use
> Ice
> >     rather than raw sockets for the communication? In that case would you
> need
> >     all objects? Or does the API that Mario is already using come close
> to
> >     sufficing? What are the other features/requirements that need to be
> added?
> >
> >     > My questions, mostly to those who know more about Ice, are:
> >     >
> >     > 1) Is there already a tool out there for doing this? Or a better
> way in
> >     > general?
> >
> >     None that I know of.
> >
> >     > 2) Are there any roadblocks you can foresee with this approach,
> aside from
> >     > bad performance in some cases?
> >
> >     Curtis, I assume your plan is to turn everything into an Ice Prx?
> e.g. would
> >     you have an IRandomAccessPrx? If so, I'm skeptical that this would
> work as
> >     well as you want.
> >
> >     > One potential roadblock: years ago I had trouble with methods of
> one
> >     > interface returning objects of a different interface. At the time,
> Josh
> >     > Moore and I concluded that it was sort of infeasible to have these
> sorts of
> >     > methods. E.g., IFormatReader.getCoreMetadata() returns a
> CoreMetadata
> >     > object, but this is difficult to implement properly in the
> server-side
> >     > implementation due to how Ice proxies work. But my intuition is
> that there
> >     > may be a clever workaround...
> >
> >     I can't remember the specific problem we were having, Curtis. To you
> have
> >     that email still and/or link on ome-devel? I found only
> >
> http://lists.openmicroscopy.org.uk/pipermail/ome-devel/2010-October/001733.html
> >
> >     > Thoughts welcome!
> >     > -Curtis
> >
> >     Cheers,
> >     ~Josh
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openmicroscopy.org.uk/pipermail/ome-devel/attachments/20110705/2cf7aeb8/attachment-0001.html>


More information about the ome-devel mailing list