X-Git-Url: http://git.madism.org/?p=~madcoder%2Fpwqr.git;a=blobdiff_plain;f=Documentation%2Fpwqr.adoc;h=d028a9ca400c8d8694e5e4c0cf875e14b66e8ba2;hp=0c04746773a8f32d6c3c9510fb18f12a30726108;hb=866e56c8f10d718c24e812335b107a05218dc339;hpb=170387f1b2fdd96e6271d658161926086a9c2586 diff --git a/Documentation/pwqr.adoc b/Documentation/pwqr.adoc index 0c04746..d028a9c 100644 --- a/Documentation/pwqr.adoc +++ b/Documentation/pwqr.adoc @@ -100,22 +100,14 @@ in kernel (poll solution):: + It sounds very easy, but it has one major drawback: it meaks the pwqfd must be somehow registered into the eventloop, and it's not very suitable for a -pthread_workqueue implementation. - -in kernel (hack-ish solution):: - The kernel could voluntarily unpark/unblock a thread with another - errno that would signal overcommiting. Unlike the pollable proposal, - this doesn't require hooking in the event loop. Though it requires - having one such thread, which may not be the case when userland has - reached the peak number of threads it would ever want to use. +pthread_workqueue implementation. In other words, if you can plug into the +event-loop because it's a custom one or one that provides thread regulation +then it's fine, if you can't (glib, libdispatch, ...) then you need a thread +that will basically just poll() on this file-descriptor, it's really wasteful. + -Is this really a problem? I'm not sure. Especially since when that happens -userland could pick a victim thread that would call `PWQR_PARK` after each -processed job, which would allow some kind of poor man's poll. -+ -The drawback I see in that solution is that we wake up YET ANOTHER thread at a -moment when we're already overcommiting, which sounds counter productive. -That's why I didn't implement that. +NOTE: this has been implemented now, but still it looks "expensive" to hook +for some users. So if some alternative way to be signalled could exist, it'd +be really awesome. in userspace:: Userspace knows how many "running" threads there are, it's easy to @@ -123,24 +115,21 @@ in userspace:: already accounted for. When "waiting" is zero, if "registerd - parked" is "High" userspace could choose to randomly try to park one thread. + -I think `PWQR_PARK` could use `val` to have some "probing" mode, that would -return `0` if it wouldn't block and `-1/EWOULDBLOCK` if it would in the non -probing mode. Userspace could maintain some global probing_mode flag, that -would be a tristate: NONE, SLOW, AGGRESSVE. +userspace can use non blocking read() to probe if it's overcommiting. + It's in NONE when userspace belives it's not necessary to probe (e.g. when the amount of running + waiting threads isn't that large, say less than 110% of the concurrency or any kind of similar rule). + It's in SLOW mode else. In slow mode each thread does a probe every 32 or 64 -jobs to mitigate the cost of the syscall. If the probe returns EWOULDBLOCK -then the thread goes to PARK mode, and the probing_mode goes to AGGRESSVE. +jobs to mitigate the cost of the syscall. If the probe returns '1' then ask +for down-commiting and stay in SLOW mode, if it returns AGAIN all is fine, if +it returns more than '1' ask for down-commiting and go to AGGRESSIVE. + When AGGRESSVE threads check if they must park more often and in a more controlled fashion (every 32 or 64 jobs isn't nice because jobs can be very long), for example based on some poor man's timer (clock_gettime(MONOTONIC) -sounds fine). As soon as a probe returns 0 or we're in the NONE conditions, -then the probing_mode goes back to NONE/SLOW. +sounds fine). State transition works as for SLOW. + The issue I have with this is that it sounds to add quite some code in the fastpath code, hence I dislike it a lot. @@ -172,7 +161,21 @@ with a concurrency corresponding to the number of online CPUs at the time of the call, as would be returned by `sysconf(_SC_NPROCESSORS_ONLN)`. `flags`:: - a mask of flags, currently only O_CLOEXEC. + a mask of flags among `O_CLOEXEC`, and `O_NONBLOCK`. + +Available operations on the pwqr file descriptor are: + +`poll`, `epoll` and friends:: + the PWQR file descriptor can be watched for POLLIN events (not POLLOUT + ones as it can not be written to). + +`read`:: + The file returned can be read upon. The read blocks (or fails setting + `EAGAIN` if in non blocking mode) until the regulator believes the + pool is overcommitting. The buffer passed to read should be able to + hold an integer. When `read(3)` is successful, it writes the amount of + overcommiting threads (understand: the number of threads to park so + that the pool isn't overcommiting anymore). RETURN VALUE ~~~~~~~~~~~~ @@ -213,9 +216,8 @@ Valid values for the `op` argument are: value is passed as the `val` argument. The requests returns the old concurrency level on success. + - A zero or negative value for `val` means 'automatic' and is recomputed - as the current number of online CPUs as - `sysconf(_SC_NPROCESSORS_ONLN)` would return. +A zero or negative value for `val` means 'automatic' and is recomputed as the +current number of online CPUs as `sysconf(_SC_NPROCESSORS_ONLN)` would return. `PWQR_REGISTER`:: Registers the calling thread to be taken into account by the pool @@ -258,6 +260,9 @@ If the concurrency level is below the target, then the kernel checks if the address `addr` still contains the value `val` (in the fashion of `futex(2)`). If it doesn't then the call doesn't block. Else the calling thread is blocked until a `PWQR_WAKE` command is received. ++ +`addr` must of course be a pointer to an aligned integer which stores the +reference ticket in userland. `PWQR_PARK`:: Puts the thread in park mode. Those are spare threads to avoid