Skip to content
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

Investigate avoiding lifecycle_lock traffic in task::unkillable() #3213

Closed
bblum opened this issue Aug 17, 2012 · 5 comments
Closed

Investigate avoiding lifecycle_lock traffic in task::unkillable() #3213

bblum opened this issue Aug 17, 2012 · 5 comments
Labels
A-runtime Area: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows C-enhancement Category: An issue proposing an enhancement or a PR with one.

Comments

@bblum
Copy link
Contributor

bblum commented Aug 17, 2012

task::unkillable is used a bunch in task, some in sync, and I suspect it really should be used in other places where we have unsafe code, like pipes.

Currently it hammers on lifecycle_lock every time:

void rust_task::inhibit_kill() {
    scoped_lock with(lifecycle_lock);
    disallow_kill++;
}
void rust_task::allow_kill() {
    scoped_lock with(lifecycle_lock);
    disallow_kill--;
}

The reason is to protect it from racing a killer (this code is approximate):

void rust_task::kill() {
    scoped_lock with(lifecycle_lock);
    killed = true;
    if (blocked && disallow_kill == 0) {
        // Point A
        punt_awake();
    }
}

If we just removed the lock in inhibit_kill, the race could be that at point A, the unkillable task increments its flag and promptly goes to sleep, only to get punted awake from what it thought was an unkillable sleep.

If we removed the lock in allow_kill, the race would be that the killer sees the task is not killable, and at point A it then becomes killable and goes to sleep, but the killer doesn't punt it awake, and it blocks forever.

I believe the following version should be safe (though not helgrind-clean), and reduce traffic on lifecycle_lock:

void rust_task::inhibit_kill() {
    disallow_kill++;
    if (killed) {
        scoped_lock with(lifecycle_lock);
    }
}
void rust_task::allow_kill() {
    disallow_kill--;
    if (killed) {
        scoped_lock with(lifecycle_lock);
    }
}

Try this and see what it does to task and sync performance. This is pretty fragile code (i.e. might start racing if something changes elsewhere), so only actually use it if it's a clear win.

@ghost ghost assigned bblum Aug 17, 2012
@bblum
Copy link
Contributor Author

bblum commented Aug 17, 2012

Actually, I don't believe we should have to bounce off the lock at all in the proposed fix. The reason is because rust_task::block() itself takes the lifecycle lock and checks the killed flag.

@bblum
Copy link
Contributor Author

bblum commented Aug 17, 2012

The other things to consider would be yield() / wait_event(), which are where else the disallow_kill flag gets accessed. But all those functions are always run by the same task, so there would be no race among them.

@bblum
Copy link
Contributor Author

bblum commented Aug 21, 2012

I ran the tests. On task-perf-jargon-metal-smoke there was a 5.5% average speedup and on task-perf-linked-failure there was a 3% average speedup. Here are some graphs:

http://bblum.net/images/perf-removing-lifecycle-lock/100-generations.svg
http://bblum.net/images/perf-removing-lifecycle-lock/100-generations-load.svg
http://bblum.net/images/perf-removing-lifecycle-lock/linked-failure.svg
http://bblum.net/images/perf-removing-lifecycle-lock/linked-failure-load.svg

Electing to go ahead with the change.

@bblum bblum closed this as completed in 47cca22 Aug 21, 2012
@bblum
Copy link
Contributor Author

bblum commented Aug 22, 2012

In honesty, the dubious change (i.e. removing it around inhibit_kill/allow_kill) is probably responsible for half the speedup. The rest is from inhibit_yield/allow_yield, which never even looked like they needed the locks in the first place.

@bblum
Copy link
Contributor Author

bblum commented Aug 24, 2012

Also see 5ba7434. Removing the locks in yield() may be possible.

@bblum bblum removed their assignment Jun 16, 2014
bors pushed a commit to rust-lang-ci/rust that referenced this issue May 15, 2021
RalfJung pushed a commit to RalfJung/rust that referenced this issue Dec 17, 2023
…s, r=RalfJung

remove unnecesary `-Zunstable-options`

AFAIK `-Zunstable-options` is for `cargo --config` CLI, which was stabilized in 1.63

https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#config-cli
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-runtime Area: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows C-enhancement Category: An issue proposing an enhancement or a PR with one.
Projects
None yet
Development

No branches or pull requests

1 participant