Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-Threaded LoopBuilder #250

Merged
merged 18 commits into from
Jun 11, 2019
Merged

Multi-Threaded LoopBuilder #250

merged 18 commits into from
Jun 11, 2019

Conversation

maarzt
Copy link
Contributor

@maarzt maarzt commented Apr 8, 2019

This PR improves the performance of LoopBuilder by adding two features:

  1. LoopBuilder now supports multi-threading. This example copies an image using multiple threads:
LoopBuilder.setImages(imageA, imageB).multiThreaded().forEachPixel(
    (a, b) -> b.set(a)
);
  1. In certain circumstances LoopBuilder uses Cursor instead of RandomAccess to iterate over an image. This happens when all images are NativeImg like ArrayImg, PlanarImg and CellImg.

The multiThreaded() method in the example above optionally accepts a MultiThreadSetting argument:

MultiThreadSetting mts = MultiThreadSettings.multi();
LoopBuilder.setImages(imageA, imageB).multiThreaded(mts).forEachPixel(
    (a, b) -> b. set(a)
);

Using the MultiThreadSetting one can specify how LoopBuilder does the multi-threading. MultiThreadedSettings.single() will make the algorithm run without multi-threading, this is also the default. MultiThreadSettings.multi() does multi-threading. It's also possible to specify the ExecutorService to be used MultiThreadSettings.multi(16, Executors.newFixedThreadPool(8)). MultiThreadSetting is a very simple interface, have a look. If you want LoopBuilder to use a specific thread pool, an custom implementation of MultiThreadSetting is the solution.

I think MultiThreadSetting can be very useful for image processing algorithms, so I'm happy to discuss it.

*/
public static MultiThreadSetting single()
{
return SINGLE_THREAD_SETTINGS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the plural S here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a typo, should be without the S ;)

@ctrueden
Copy link
Member

ctrueden commented Apr 9, 2019

Is it worth looking at using ForkJoinPool instead, as discussed in imglib/imglib2-algorithm#81?

The discussion on MultiThreadSetting is planned to be held in June 2019.
For now MultiThreadSetting is only used package-privately inside
LoopBuilder.
@maarzt
Copy link
Contributor Author

maarzt commented May 2, 2019

MultiThreadSetting is now package-private, and therefore hidden to the user.
We can now merge this PR, to get the multi-threaded LoopBuilder. And after the discussion
about a unified strategy for multi-threading, we can easily change MultiThreadSetting and LoopBuilder.

@tpietzsch How do you feel about merging this PR?

The benchmark is now simpler. It now shows a situation where cursors
are faster that LoopBuilder.
@maarzt maarzt force-pushed the multithreaded-loop-builder branch from 7bfb634 to 0913540 Compare May 10, 2019 13:35
…ses.

LoopBuilder will use Cursors to iterate over the image if all cursors
classes are in the following list:
* AbstractArrayCursor
* SlicingCursor
* PlanarCursor
* CellCursor
@maarzt
Copy link
Contributor Author

maarzt commented May 15, 2019

@tpietzsch What do you think. Can we merge this?

@acardona
Copy link
Contributor

acardona commented May 15, 2019

Hi @maarzt,
Question: does this partition the tasks by pixels, that is, two consecutive pixels are processed by different threads? If so, does performance degrade substantially from a larger partitioning approach, whereby instead of processing each pixel independently, a contiguous chunk of the source image is processed by a single thread, so the whole source image is split into as many partitions as there are threads? I suspect the latter has far better performance, given that memory may not be contiguous in large images.

This increases the performance of LoopBuilder if used with many different
image classes.
@maarzt
Copy link
Contributor Author

maarzt commented May 21, 2019

@acardona

Question: does this partition the tasks by pixels, that is, two consecutive pixels are processed by different threads?

No, consecutive pixels are usually processed by the same thread. The PR also contains a benchmark that shows multi-threading performance: https://github.com/imglib/imglib2/blob/multithreaded-loop-builder/src/test/java/net/imglib2/loops/LoopPerformanceBenchmark.java
I get a multi-threading speedup of 3.8 on my 4 core machine.

@acardona
Copy link
Contributor

acardona commented May 21, 2019 via email

@maarzt maarzt merged commit 62287fb into master Jun 11, 2019
@maarzt maarzt deleted the multithreaded-loop-builder branch September 19, 2019 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants