Extend Phlex algorithm lifecycle to include pre- and post-execution phases "initialize" and "finalize". #764
Replies: 6 comments 5 replies
The barriers are conceptual: adding these entry points would mean that graph execution would need to be informed by not only data dependencies and the available concurrency, but it would also depend on algorithms that are used (presumably) only for establishing state...making some of the dependencies implicit. We are very hesitant to go this route until we can understand specifically what necessitates it. We have not yet seen a compelling case to add such hooks (although they have been considered). Some options you might consider are below. Those options assume that the purpose of the "initialize" and "finalize" are to handle state used by the algorithm1. Happy to follow up on anything. Phlex support for functions bound to stateful objectsFunctions bound to stateful objects can be registered with the framework. See here for an example of calling This approach means no changes to Phlex proper, and it keeps stateful classes local to the Phlex module. Recasting the "initialize" and "finalize" as data dependenciesDepending on what the initialize and finalize are for, it may be possible to introduce algorithms that prepare the state and pass that state explicitly as an in-memory-only data product to a downstream algorithm that requires it. This keeps the data dependencies explicit, thus making it easier to understand the flow of the program. How a "finalize" is implemented would depend on what it is for. ResourcesWe have a reasonably mature design for Phlex resources. These can be helpful when needing to coordinate the execution of algorithms that depend on a shared resource that may not be thread-safe. Depending on what you need to do with the "initialize" and "finalize", these may be reasonable approaches. Footnotes
|
|
Another problem I just hit with the lack of a main-thread serial "configure" phase of Phlex's life cycle: calling go-jsonnet to parse WCT configuration file from each WCT-graph-as-Phlex-node crashes the go runtime ("fatal error: traceback did not unwind completely"). The immediate "fix" is to only run Phlex with a single thread. Next work-around would be that wcphlex nodes can add a mutex around Jsonnet parsing. But, this is a general class of problem. I really think that Phlex need to support a single, post-construction, pre-execution, main-thread Algorithm class entry point. I had opus analyze Phlex 0.3.2 to come up with a minimally invasive way to execute an Generated by Opus 4.8Proposal: opt-in main-thread
|
|
It looks like setting env var I still think Phlex should provide deterministic, main-thread entries to Algorithms. |
|
This lack of main-thread initialization continues to cause me serious headaches. I now get segfault due to races between mutex-protected initialization that I had to wedge in to first-time execution of a Phlex algorithm and the non-mutex protected subsequent executions. I only went down this mutex hack to try to satisfy the ability to inject a Phlex "resource" into a WCT "service like" component. This same workaround was actually the cause of the go-jsonnet problem. I understand I can maybe use a shared mutex to perpetuate this ugly hack. Working around Phlex's lack of flexibility in this matter is very frustrating. |
|
Hi @knoepfel
Yes. I think I can disentangle somewhat now. The original title of this discussion is no longer correctly describing the problem that remains. A few new understandings:
But, the
I confirmed this with some actual code that uses both So, this actually solves my initial problem. Running WCT as "introverted" Phlex algorithms is fine. The problem comes when I try to add some extroversion so that WCT can implement a WCT service using information from a Phlex resource data product. WCT assumes services are all ready to use after the "initialize" phase, but Phlex resource products are only available at each "execute" phase. The initial solution was to delay all WCT initialization to the first execute call of each WCT island. But, that fell apart once I scaled tests up to multiple events, multiple WCT islands and multiple threads. The mutex that I placed around the WCT initialization was not enough. This is due to execute-time access to WCT's "named factory" was not mutex-protected so some WCT islands got there while others were inside the initialize mutex. A shared lock for the execution phase should fix this, (and perhaps fixing WCT NamedFactory to be thread safe for read-only queries). But, at that point I had given up and backed out support for Phlex resources in hopes that Phlex 0.4.0 might help something. But, perhaps this relative scheduling problem is more endemic. If so, I can bring back the delayed first-execute and add the shared mutex. |
|
One more wrinkle before I forget it: the solution I describe at the end: to do WCT initialization from the first Phlex execution (even with shared mutex added) will initialize WCT on a non-MAIN thread. This allows the class of thread problems that Geant4 tickles. Ie, it will construct objects on a non-MAIN thread and destruct them on the MAIN thread. I don't know yet if this will tickle problems or not. |
Uh oh!
There was an error while loading. Please reload this page.
I'd like Phlex to consider to add support for calling two methods on an algorithm:
initialize()andfinalize()before and after the DFP graph execution (just after start and just before end of job) and from the main thread.A templated compile-time check can be used so that algorithms that are simple functions or classes that lack one or both of these methods could be exempt from attempting to call their non-existent methods and without the need for inheritance.
This would help support Wire-Cell Toolkit and Geant4 in Phlex and probably other future integrations.
Are there any barriers to adding these two algorithm entry points?
All reactions