-
Notifications
You must be signed in to change notification settings - Fork 7
Issue #26: Scope stats on running, completed and panicked threads #27
base: master
Are you sure you want to change the base?
Issue #26: Scope stats on running, completed and panicked threads #27
Conversation
…completed and panicked threads + some basic tests
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.
Thank you for the PR!
Instead of introducing Sentinel<'s>
, you can tweak the invocation of builder_spawn_unchecked
instead:
builder_spawn_unchecked(self.builder, move || {
self.scope.stats.running.fetch_add(1, Ordering::SeqCst);
let mut result = Box::from_raw(result as *mut ManuallyDrop<T>);
let res = panic::catch_unwind(panic::AssertUnwindSafe(f));
self.scope.stats.running.fetch_sub(1, Ordering::SeqCst);
match res {
Ok(r) => {
self.scope.stats.completed.fetch_add(1, Ordering::SeqCst);
*result = r;
mem::forget(result);
}
Err(e) => {
self.scope.stats.panicked.fetch_add(1, Ordering::SeqCst);
panic::resume_unwind(e),
}
}
})
But it works either way. :)
There seems to be a small window of time between decrementing running
and incrementing panicked
/completed
, which means polling the counts might give inconsistent results.
An easy way of fixing this would be to put the stats inside a Mutex
rather than have them as three independent atomic variables. Another solution might be to try squeezing the three counters into a single AtomicUsize
.
But maybe it'd be best to do the following. Have three atomic counters, panicked
, completed
, and spawned
. They are only incremented, never decremented. Then we can compute the number of running threads like this:
fn running_threads(&self) -> usize {
loop {
let p1 = self.stats.panicked.load(SeqCst);
let c1 = self.stats.completed.load(SeqCst);
let s = self.stats.spawned.load(SeqCst);
let p2 = self.stats.panicked.load(SeqCst);
let c2 = self.stats.completed.load(SeqCst);
if p1 == p2 && c1 == c2 {
return s - p1 - c1;
}
}
}
This method would give fully consistent results.
I just wonder -- are stats necessary to be very precise? I think the use case in #26 only requires that the stats are eventually consistent, i.e. the stats will be saturated. |
Maybe not - perhaps I'm just being overly pedantic. :) |
@oliver-giersch First of all, thanks for the PR! It's very fast :) I just want to say I hope stats are implemented as an add-on, rather than by default. Because maintaining stats costs a little bit, while very small, so I'd like users can opt-out. |
@jeehoonkang I don't think stats have any measurable cost. :) Spawning a thread is a very costly operation by itself (we also allocate some memory for the destructor chain and so on...) so the cost of three atomic operations per spawned thread is basically zero. |
@jeehoonkang coincidentally I had been doing some reading of the scoped thread code for the last two days to get a better understanding, so when I saw the issue I just went ahead and tried my hands on it ;) @stjepang I could go ahead and drop the sentinel struct in favor of a catch_unwind() approach, not sure what the benefits are. I also had the following solution for true consistent atomic stats in mind (not tested yet):
This has the obvious issue of not being portable, and the limitation of Also, I do have some questions regarding a bunch of details the code for the scoped thread, would it be OK if I sent you an email or something? |
The benefit is somewhat simpler code, but in the end it's the same thing.
This will work, except the result needs to be shifted right in Mutexes are fine, but polling counters (using the three public methods) might be a bit slower than necessary due to locking. If we want consistency, I think it's best to just implement
You can open an issue here, hop into #crossbeam at irc.mozilla.org, or send me an email. Whatever works for you. :) |
OK will change these things then accordingly, probably tomorrow (and yeah, I forgot the right shift). I'll also open a ticket for my questions/suggestions so others may chime in. |
…ount + removing the Sentinel struct)
Why close this PR? I'm OK with merging the current changes. :) |
Huh, I must have closed it by accident |
I see. Can you restore the deleted branch and reopen the PR? |
I'll See what I can do tomorrow. |
I'm concerned with the generality of the stats. Different people have different requirements, and I think it's a little bit hard to justify a particular choice of stats. For example. I think it's enough to provide a querying method to check if there are any panicked threads, and based on it, you can implement the feature #26 wants (and a part of what this PR wants, too). In that case, I'd like to make the scoped thread library kinda minimal and provides other functionalities (such as stats) as add-ons. |
Also, I'd just like to remind that currently it isn't even possible to access |
# Conflicts: # src/thread.rs
I think I'll try to rewrite the code to allow for opt-in stats keeping. I have something in mind like iterator adapters, so you turn the regular scope into a stat keeping scope which exposes the same functionality as a scope but with stats. Also, I do have some concerns about the current
This probably another issue altogether and would require |
Just for comparison, the The only two uses of |
If you create a new inner scope, then all threads spawned inside it will be joined before the inner scope ends. Some users would like to spawn such inner threads without this restriction. |
…sing derived trait
# Conflicts: # src/thread.rs
Summary of the latest commits:
I have decided against the loop based solution for the running count for now, because I didn't see what purpose it is meant to achieve. If the goal is to return the running count at the exact moment the function is called, a mutex for the entire |
I implemented the three method signatures suggested in issue #26 using three atomic counters which are updated each time a thread is spawned or exits using a guard/sentinel struct.
I also implemented two very basic test to be somewhat able to ensure their functionality.