-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Lightweight task scheduler #5964
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
Conversation
src/scheduler.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work when the timestamp of the first item in the queue is in the past?
|
concept ACK
|
src/scheduler.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.wait() may wake spuriously, so it's better to turn the surrounding if into a while loop. I believe that means you also won't have to deal with the queue-empty case in the loop below.
|
Agree with @jgarzik; threadimport should not run in the scheduler, as it is expected to take up to hours - blocking several other operations. Wallet flushing is a good candidate. |
166bb79 to
c7922ac
Compare
|
Fixed @sipa's nits, including running scheduler.cpp/.h through clang-format. And reverted the ThreadImport change, so it is it's own thread again. |
|
Otherwise, we'll need to enforce >= 1.50 as a build requirement. |
|
They're easy to work with using timed_wait, I think. |
|
ut ACK latest rev |
0ceb336 to
e395785
Compare
|
Three changes:
I think I'm all done tweaking this now. |
src/scheduler.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wrong earlier. If you want to support multiple runner threads, you need to do this check inside the while loops above, as the item can disappear while they wait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm. I convinced myself an empty check isn't necessary there, but belt&suspenders says I should just put it back.
(not needed because: if the queue is emptied during timeout, then the wait loop is timed out and exited and the empty queue is caught here. And since there is no unschedule-task, the only other way the wait can exit is if a new task is added to the queue, which wakes up only one thread and so the queue can't be empty).
I'll add the empty condition to the wait loops.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, you convinced me... but indeed, belt & suspenders.
You could even combine the two loops: while (taskQueue.empty() || wait_until(taskQueue.begin()->first)) ?
EDIT: nevermind. Sorry, ignore my nits here, I'm not thinking clearly.
|
extremely-lightly-tested ACK (as in: does not crash). |
|
Final (?) nits picked (got rid of the obsolete run from the .h, added belt&suspenders checks for empty queue, ran through clang-format again), this should be ready for merge. I also did some more testing, writing a stress-test that created 4,000 tasks serviced by 100 threads over a couple of milliseconds ( https://github.com/gavinandresen/scheduler/blob/master/main.cpp ), and all is well, including running under valgrind. |
|
lightly tested ACK |
|
Debian 7: |
|
@luke-jr : fixed. I'd fixed that before, I think it got lost in a rebase / shuffle between working on home/work trees. The fix is in the unit test commit, and is: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy to see that this gets rid of the awful LoopForever() in util.h.
|
ACK apart from the nit |
- replaces some hard-coded values for the default confirmation target - also simplify code that is using the new constant
Simple class to manage a task queue that is serviced by one or more threads.
previously it was only used with certain boost versions. Now all versions require it.
|
Nits picked, will merge as soon as Travis gives the green light. |
Instead of starting Yet Another Thread to dump addresses, use CScheduler to do it.
|
Travis was unhappy-- one of the builds was taking more than 50 minutes to complete. I toned down the unit test by a factor of ten, in case that is what was causing the problem (it now services hundreds of tasks using 10 threads, instead of thousands using 100 threads).... if the builds STILL take longer than normal I'll have to recruit @theuni to help debug. |
|
@gavinandresen It initially failed; so I merged #6136 and tried again. It's expected to take somewhat longer but should at least succeed. |
|
@gavinandresen I think it's partially bad timing. #6136 forced travis to rebuild all dependencies and build up a new cache. Should be back to normal in an hour or so. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tiny nit, is the indenting here off?
9a1dcea Use CScheduler for net's DumpAddresses (Gavin Andresen) ddd0acd Create a scheduler thread for lightweight tasks (Gavin Andresen) 68d370b CScheduler unit test (Gavin Andresen) cfefe5b scheduler: fix with boost <= 1.50 (Cory Fields) ca66717 build: make libboost_chrono mandatory (Cory Fields) 928b950 CScheduler class for lightweight task scheduling (Gavin Andresen) e656560 [Qt] add defaultConfirmTarget constant to sendcoinsdialog (Philip Kaufmann)
|
Build and unit tests pass on Debian 7: ACK |
|
@gavinandresen I got this earlier on an unrelated PR, looks very related/suspicious: https://travis-ci.org/bitcoin/bitcoin/jobs/62615004#L1344 . |
|
Hmmm... Looks like the threads were interrupted before finishing (slow VM maybe). I'll try to rework the test tomorrow so it doesn't interrupt the threads.
|
808ef36 [doc] Update thread information in developer docs (John Newbery) Pull request description: - DumpAddresses thread was removed in #5964 - Shutdown thread was removed in #5679 - Add new threads (scheduler, RPC worker, indexer, tor control) - Small changes to documentation of other threads ACKs for top commit: MarcoFalke: ACK 808ef36 hebasto: ACK 808ef36. Tree-SHA512: 85b6ace7bcc4dee030c63461bef1ded1a9581d4fa249c59f6fcd5d33d89c4357a6b8b35888ce0960f276d397b5e38a21e6c5d4b7b79544827a28c950e097b36d
808ef36 [doc] Update thread information in developer docs (John Newbery) Pull request description: - DumpAddresses thread was removed in bitcoin#5964 - Shutdown thread was removed in bitcoin#5679 - Add new threads (scheduler, RPC worker, indexer, tor control) - Small changes to documentation of other threads ACKs for top commit: MarcoFalke: ACK 808ef36 hebasto: ACK 808ef36. Tree-SHA512: 85b6ace7bcc4dee030c63461bef1ded1a9581d4fa249c59f6fcd5d33d89c4357a6b8b35888ce0960f276d397b5e38a21e6c5d4b7b79544827a28c950e097b36d
Threads have noticeable overhead on 32-bit systems, so using fewer threads for simple tasks is better than starting up threads willy-nilly.
The first commit implements a simple task queue class (CScheduler) which can be serviced by one or more threads.
The second and third port the networking code's DumpAddresses thread to be a task instead.
Porting other threads (ThreadFlushWalletDB is a good candidate) is left as an exercise for future pull requests.
The CScheduler class was developed and tested with code here: https://github.com/gavinandresen/scheduler (see main.cpp)
I tested the DumpAddresses change running with -debug=net and a hacked DEBUG_ADDRESS_INTERVAL, and made sure I got more than one "Flushed %d addresses to peers.dat" in my debug.log.