Use shared memory to avoid copying data

Hi,

From a program written in C++ on Windows, I have to launch ImageJ (Fiji) in headless mode to execute a script. I searched for some solutions to improve performance and time consumption and for now i use a ram disk software. Data that i have to send are already loaded in the ram when i have to send them. I copy them on the ram disk and then ImageJ will copy them in its memory (I guess). So there are lot’s of useless copies.

Are there some solutions to avoid these copies like using shared memory between both processes ?

Thank you in advance

2 Likes

Hi @Loic_Balleydier,

Welcome to the forum.

Yes, it’s possible using the Java Native Interface (JNI), but might be difficult.

For tips, I recommend looking into pyimagej, which might make your life easier if you make python wrappers for your c++ code. Just a thought.

@hanslovsky, @ctrueden will know details.

Good luck,
John

Thank you for the quick answer, I will look at links you mentionned.

1 Like

It will depend on the data structures you are using: ImageJ1 data structures (ImagePlus, ImageProcessor) do not support native memory, ImageJ2/ImgLib2 data structures can read and write native memory. But even without shared memory, you would save a few copies and I/O.

Do you have a Python wrapper around your C++ code? Then it would be fairly easy to just call the imagey or pyimagej API to wrap your C++ data as ImgLIb2 data structure.

No, I have no python wrapper today. I use the Qt framework to launch directly ImageJ in headless mode. I never had the chance to use python to wrap my C++ code until now.

So if I well understood, the shared memory will be between the C++ program and the python wrapper. The python wrapper will build a structure (ImageJ2/ImgLib2) around my data and use functions from pyimagej or imagey to execute the ImageJ script.
Is it that ?

Thanks for your answers.

Let me explain in a little more detail:

Java data structures live in the JVM and the memory layer is an abstraction that is different from native memory. As a consequence, Java programs cannot read from or write into native memory in contrast to other programming languages such as C, C++, Python. There are workarounds to do that, e.g. through the Java Native Interface or through sun.misc.Unsafe. None of these options are trivial and require careful considerations, but it is definitely possible. In principle, you will need to three major components:

  1. A way to start a Java Virtual Machine from within a native process (you will need JNI for that)
  2. Make Java methods and classes available in the native programming language (JNI)
  3. Add support for reading native memory addresses in your Java data structures (Unsafe).

PyJNIus takes care of (1) and (2) for Python through the JNI with Cython. To address (3), I created

  • imglib2-unsafe to expose native memory to ImgLib 2 data structures
  • imglib2-imglyb for data structures that can understand numpy meta data, such as strides or offsets into native memory and other meta data, and
  • imglyb the Python library that wraps numpy.ndarray into ImgLib2 data structures with shared memory access.

In order to have shared memory between your C++ code and ImgLib2 data structures, there are two options:

  1. Write your own wrapper for (1) and (2) from above and then use imglib2-unsafe to wrap around your C++ native memory
  2. Write a shared memory Python/numpy.ndarray wrapper for your C++ data structures and then use imglyb to handle shared memory between Python and ImgLib2. To fully use the capabilities of imglyb, your C++ data structures need to be wrapped as numpy.ndarray.

From my perspective, option (2) seems a lot easier and I think it’s generally a good idea to expose C++ code and data structures to Python but I have not written a Python wrapper in a long time. If you are looking for a good starting point, I would recommend pybind11 to create the Python wrapper.

3 Likes

Thank you @hanslovsky for all these details.
I will follow your advices and choose the second option.

1 Like