Closed ska80 closed 11 years ago
Thanks, I'll merge this soon. The queue I submitted to sbcl-devel might be faster even with precise gcs; I need to do some benchmarking. I might wind up code-generating all CAS queues.
The LispWorks documentation says,
"Confirm when quitting image" - Actions to be executed before the image quits. Every action must return non- nil as its first value, otherwise the quit will be aborted once the actions are complete.
"When quitting image" - Actions to be executed when the image quits, after success of the "Confirm when quitting image" actions.
I changed the action from "Confirm when quitting image" to "When quitting image", otherwise if LispWorks doesn't actually quit then lparallel will be in an invalid state. If you think the former is better then let me know.
I may have found a LispWorks bug related to CAS, so for now the lockless queue is not enabled by default. In any case I didn't see much improvement, did you? Since LispWorks doesn't achieve speedup for the Fibonacci benchmark, we may be dealing with time scales where lockless queues won't matter.
I changed the action from "Confirm when quitting image" to "When quitting image", otherwise if LispWorks doesn't actually quit then lparallel will be in an invalid state. If you think the former is better then let me know.
Actually, "When quitting image" didn't work for me because it calls all its actions (in our case TRACK-EXIT) AFTER multiprocessing is stopped and BEFORE quitting and as a result it blocks waiting for "kernel" threads to exit forever never having a chance to run TRACK-EXIT. By default, threads created with BT:MAKE-THREAD (calling MP:PROCESS-RUN-FUNCTION) are started without :INTERNAL-SERVER flag described below (from LW docs):
When true, this indicates that the process is an "internal server", which means that it responds to requests for work from other processes. The main effect of this is that if the only processes that remain are "internal servers", nothing is going to happen, so LispWorks quits. The system marks some of the processes that it creates as "internal server".
On the other hand, "Confirm when quitting image" works fine because it calls its actions (TRACK-EXIT) BEFORE stopping multiprocessing and properly stops all "kernel" threads before quitting.
"Confirm when quitting image" will work in server-side applications when we just need to shut down all services and quit but may not work in a GUI application if a user decides to cancel quitting image. :)
I may have found a LispWorks bug related to CAS, so for now the lockless queue is not enabled by default. In any case I didn't see much improvement, did you? Since LispWorks doesn't achieve speedup for the Fibonacci benchmark, we may be dealing with time scales where lockless queues won't matter.
Yes, I noticed that too after running benchmarks. It runs almost two times slower than without CAS. I should have run benchmarks first before sending the patch. The Fibonacci example from the tutorial is very slow comparing to CCL and SBCL.
"Confirm when quitting image" should not be used because if any action in that list returns nil then things will be broken, and worse, broken in a way that is not immediately obvious (worker threads will no longer be regenerated after being killed).
These exit hooks were intended for convenience only, to relieve the user of a final end-kernel
call. I wouldn't advise depending upon them in any serious sense. Do you have some situation where you cannot call end-kernel
?
I suppose the idiomatic LW solution here would be to mark worker threads as internal servers. If this is considered at all, it should probably be done by adding :implementation-args
to bordeaux-threads:make-thread
rather than having lparallel bypass bordeaux-threads:make-thread
.
"Confirm when quitting image" should not be used because if any action in that list returns nil then things will be broken, and worse, broken in a way that is not immediately obvious (worker threads will no longer be regenerated after being killed).
Agreed.
These exit hooks were intended for convenience only, to relieve the user of a final end-kernel call. I wouldn't advise depending upon them in any serious sense. Do you have some situation where you cannot call end-kernel?
I find it useful for debugging purposes in a server-side application and when I just wanted to quit the image without stopping "kernel" threads. Before sending the patch with 'define-action' I typed END-KERNEL before quitting and it worked. I guess I could just add END-KERNEL to my shutdown function.
I suppose the idiomatic LW solution here would be to mark worker threads as internal servers. If this is considered at all, it should probably be done by adding :implementation-args to bordeaux-threads:make-thread rather than having lparallel bypass bordeaux-threads:make-thread.
I actually have a branch of bordeaux-threads (dev branch) to implement this feature that sets :internal-server flag and it works fine with lparallel, I can't just figure out how to make or name or pass it properly for other implementations that don't have this feature.
I had in mind
(bordeaux-threads:make-thread #'f :implementation-args (or #+lispworks '(:internal-server t)))
though I'm ambivalent about it. I think LW should behave as I expected, with "When quitting image" being run before multiprocessing shuts down, or otherwise LW should provide another hook. All other popular implementations have such a hook.
I think LW should behave as I expected, with "When quitting image" being run before multiprocessing shuts down, or otherwise LW should provide another hook. All other popular implementations have such a hook.
I am going to report this as a bug tomorrow.
Hi James,
LW guys will consider adding extra action lists to handle starting and stopping multiprocessing in the following releases.
If you still wish to avoid the end-kernel
call, the aforementioned addition to bordeaux-threads seems reasonable if you wanted to pursue it.
It would have been nice if the define-action
in lparallel turned into a prescient fix, but I didn't expect it due to backward compatibility with the current hooks.
Hi James,
Thank you for your support.
In a delivered app I always call END-KERNEL explicitly so there is no problem. As for development stage I ended up using "Confirm when quitting image" action as it works for my use case when I just need to quit an image without canceling :) Quicklisp allows to keep local custom systems that override the installed ones so I just use my local git branch. I hope LW guys will fix the issue and "When quitting image" action will work as expected.
Tested with LispWorks Pro 6.1.1 (32 bit, linux).
This implementation is based on ccl-spin-queue.lisp using LispWorks SYSTEM:COMPARE-AND-SWAP.
Passes all tests with and without :LPARALLEL.WITH-STEALING-SCHEDULER pushed.