R2020 Workers - Question and suggestion

First up, I want to say thank you for addressing multi-core processing Xojo team. I think this solution is a pretty reasonable implementation without having to make the framework thread safe.

Question:
The demo shows this being used as a non-blocking thread, but what if I want to use this for a step in a blocking thread? I.e. A have a complex function that I want the interface “paused” for while it’s doing it’s thing, but only one part of it requires multi-core processing? i.e. having a function that uses a variety of functions to process a huge block of memory, say some core image, vImage and then some manually reading/manipulation. The goal of this function is MAXIMUM performance.

Request:
Please add support for shared memory directly into this functionality. So we can create a shared memory block (which uses the correct APIs for each platform, if you want to check which ones are suitable for the Mac App Store, let me know). that each “worker” instance can share. Both @Peter Stys and I process images, sometimes huge images with high bit depths, so shared memory really is the only way to go (otherwise all the savings are eaten by unnecessary disk IO or IPC IO).

If you want or need anything from me for these, then please let me know.

1 Like

I may want to try that on my own if my time at home goes long enough (a chemist can’t do much work from home- or at least should not!! :wink: ), and others may as well… So maybe you could post what the correct API’s are in another thread?

Thanks,

  • karen

Running some more scenarios through my head.

  1. HDR processing; this probably won’t get much benefit as it’s mainly handled via Core Image (so either GPU or multi-core processing), not to mention that an HDR image is huge, so even with shared memory, there’d be copying data around to make this happen. HDR files are notoriously huge and slow to open/save, so making the helper read the file would just be terrible.

  2. 1-Click Styles preview generation. Same principle as above, except it uses a much smaller image to create bunch of thumbnails. This could probably benefit, in the sense that while it’s creating the previews, the main GUI can remove smooth. I can switch GPU processing to low priority, which will affect performance, but should prevent the GUI from jerking around while it’s doing it’s thang. I’d have to a create a large block of shared memory to be able to share the source image, and get back all the thumbnails. They’re CGImages, so they can be created directly from the shared memory, but I might copy the data back so that I can release the shared memory (incase the application crashes, otherwise the shared memory would remain allocated until the machine is restarted).

  3. Blackbird engine in App Wrapper. I’d like to make it so that Blackbird begins scanning the application the moment an application is added to App Wrapper, this way it can report directly in the GUI any show stopping issues that need to be addressed. A background thread is great for this, except that Blackbird would need to share all it’s collected data with the GUI. It currently uses a in-memory database (to minimize disk IO). But I don’t think that you can create an in-memory SQLite database on the mac from shared memory. I could use a memory based disk image (hidden from the Finder), it would add some overhead, but should be quicker than using the SSD/HDD. The GUI wouldn’t need to access this database, until the helper has completed populating, linking and doing it’s thing, so there’s no concern about locking here.

  4. Last but by no means the least, I have a video editing app in the works. I am hoping that by being able to use different threads I can improve performance. Right now it takes time to read a frame, processes the frame using Core Image, then it takes time to write a frame. Reading & Writing is bottlenecked by disk IO, processing is bottlenecked by the GPU. So I was thinking, I’d like to use a thread/worker to read in frames, it stacks them up (I don’t know, maybe up to a handful), the processor takes a frame and does it’s thang, when it’s done, it’s stacked up on the output pile. The writer then takes a frame from the pile and writes it to disk. I have no idea how much (if any performance can be gained from doing this), except that currently the program is halted while it’s reads a frame, it’s halted while it processes and again halted while writing. If it can do processing while reading or writing, that should save some time, again I don’t know how much. So probably need shared memory to exchange frames, hopefully it won’t add too much overhead. macOS 10.12 has the ability to use the GPU to exchange images via the GPU, but as I’m using the GPU to process images, and a vast majority of my customers don’t have GPUs with large amounts of memory (and there’s no way I know to test), I can’t rely on using that, although it would probably be the fastest way of exchanging frames.

Any thoughts / suggestions? I’m sharing this because I am hoping it helps Xojo engineers understand the immediate tasks I intend to do with this new Worker class, and any improvements they can make to simplify this.

I documented last year, which functions ARE NOT COMPATIBLE with the App Sandbox, but I didn’t update that with which ones that are.
https://forum.xojo.com/51306-shared-memory-app-sandbox

I’ll try to get to that soon.

Really?
https://www.youtube.com/watch?v=XXn4fP3CnJg

or you could just get the MBS plugins, which Peter uses, and skip passing anything to jobRun except maybe some cnofig params and use shared memory right away
Pretty sure Peter does this with helpers

[quote=480832:@Norman Palardy]or you could just get the MBS plugins, which Peter uses, and skip passing anything to jobRun except maybe some cnofig params and use shared memory right away
Pretty sure Peter does this with helpers[/quote]
My point is that the “Worker” class is a usable implementation to get multi-core processing, except for large amounts of data, which IMHO would really benefit.

If Xojo could add a shared memory block class as well, it would provide a out-of-the-box solution to make these “Worker” classes cover a broader range of tasks.

I’ve been very vocal in this forum recently, and I keep explaining what I want to accomplish, so that Xojo devs can take this all into consideration when supporting concurrency. I know a lot of time has been spent on this topic already, and I am really eager to get and start experimenting with “Workers”, but at the same time I see what I believe are concerns and I feel it would be better for everyone if Xojo could handle these at the same time.

I’ll admit, I honestly don’t know how many people this will benefit, and I simply don’t know how others will use this. But it would be a shame to see this limitation now, not handle it and watch people complain about it once Xojo has put in the work to provide this.

[quote=480841:@Sam Rowlands]My point is that the “Worker” class is a usable implementation to get multi-core processing, except for large amounts of data, which IMHO would really benefit.

If Xojo could add a shared memory block class as well, it would provide a out-of-the-box solution to make these “Worker” classes cover a broader range of tasks.
[/quote]
I understand this - all I’m suggesting is that you can combine the MBS plugin & workers to do this with shared memory the frist day workers ship and not have to wait for Xojo to do this (of course with shared memory and helpers you can do what workers do today just not as simply)

I get what you want to accomplish - I think I suggested shared memory to Peter many many many years back (and a few other things that I know he recently said to me “You were right” but …)

We havent even seen a release with this in it yet
So we really cant say what its limitations are - yet
And If Kems post about this is to be believed from a few days ago Workers arent in R1 anyway so we’ll have to wait longer to try this out at any rate

Its probably prudent to file a feature request about this IF you havent already
And when this ships then also press others during betas etc to add points to the FR

Shared memory is without doubt the most efficient means of IPC there is… It would be nice if for once an important feature was implemented in a way that allowed Xojo to be a as efficient as possible.

If one knows the size of shared area, all the laster and teh work need to know is the address to exchange data… and both sides could point a memoryblock at it…

To deal with concurrency (assuming such a special MB class) under the hood the framework could have memory locations where easy a UUID for a specific process to check for write or read lock…

Xojo in general has too many situations where data has to be copied (never mind IPC overhead) that can kill performance… at least for transferring data from helpers teh framework should help us avoid that.

  • karen

[quote=480842:@Norman Palardy]Its probably prudent to file a feature request about this IF you havent already
And when this ships then also press others during betas etc to add points to the FR[/quote]
Thank you for your suggestion, I have now done so <https://xojo.com/issue/59548>

As I understand the workers model now, it’s fire and return result. There is also the case of apps with needing long standing subprocesses with a lot of communication with the main app.
A good communication channel with simple standardised memory based IO is key then.

I would be interested to know if these workers are each compiled as their own console app beside the main app or if they are somehow spawned at runtime? If I have 10 worker classes, do I have 10 console apps sharing the same libraries? I assume they will work with desktop, web and console?

I would love to see a worker that has 2 way communication to the main app with a DataAvailable and Send or Write function that triggers the DataAvailable event on the worker class. I do this now with my own implementation using json to pass data back and forth but it would be the icing on the cake if Xojo could handle transferring primitives back and forth automagically.

I hope they make some kind of Job Object which encapsulates some values and gets serialized and send to to the other side.
e.g. a dictionary sent as JSON internally.

[quote=480865:@Christian Schmitz]I hope they make some kind of Job Object which encapsulates some values and gets serialized and send to to the other side.
e.g. a dictionary sent as JSON internally.[/quote]

My implementation (“IOSocket”) goes a bit further and has both sync and async sending functions and events that pass a dictionary. One calls an event that returns nothing and the other returns a dictionary. The dictionary you send is encapsulated one layer deeper in another dictionary for dealing with message order and timeouts.

Geoff can answer some of these questions at the Q&A today. And it’s a two way street, you can offer suggestions that he can bring to the engineers.

Q&A just wrapped up. Just to be clear, in v.1 the Worker won’t have access to anything in the main project, including your classes, modules, or methods. That will have to be included in the ProcessJob (or whatever it was called) event.

At least, for now.

And the question how to get classes, modules and methods to the worker as currently it looks like you are limited to one method.

I had been assuming from the original video that while we could not pass object instances, that the code in the worker job method would be able to call out to methods or create its own (temporary, non-global) class objects. In essence, that the generated console app would include whatever references were necessary to support the code in the job method. Just that it would not have direct access to anything in the mother ship.

If that will not be the case, I’ll have to continue with my current console helper app approach.

Incidentally, thanks for the shared memory classes and it seems to me they will likely be a way to “share” data with a Worker. In the Q&A when I asked about Workers and shared memory, the question really asked if there was any reason shared memory such as your classes would not work. Not asking if Xojo would have inherent built-in support for shared memory.

I suggested to Geoff that a “context” module whose contents are copied into the Worker app (along the same lines of how XojoScript works) would be a good compromise. But honestly, we’ll have to wait until the first release for any truly useful suggestions and critiques.

I assume you can just use the plugin for the shared memory.

For the main app it would be nice to have a checkbox per item whether a class/module would be included in the helper.

Or if the compiler could just do that for you by reference.