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

Linux SCHED_IDLE support seems to be broken #33

Open
nhoyle opened this issue Oct 11, 2023 · 3 comments
Open

Linux SCHED_IDLE support seems to be broken #33

nhoyle opened this issue Oct 11, 2023 · 3 comments

Comments

@nhoyle
Copy link

nhoyle commented Oct 11, 2023

From what I can tell, after reviewing the docs, and the code, the SCHED_IDLE support is either only partially implemented, or broken. Can this be confirmed? Alternately, can you provide a stub example (that doesn't use private methods) that shows correct usage?

@iddm
Copy link
Owner

iddm commented Oct 11, 2023

Hi @nhoyle and thank you for your response.

May I ask what exactly is not working properly?

@nhoyle
Copy link
Author

nhoyle commented Oct 11, 2023

I have attempted two paths to set Idle scheduling class. The first is not actually "valid" (possibly):


    #[cfg(target_os = "linux")]
    {
        print!("Linux detected. Setting idle scheduling class...");
        let thread_id = thread_priority::thread_native_id();
        let result = thread_priority::set_thread_priority_and_policy(
            thread_id,
            thread_priority::ThreadPriority::Min,
            thread_priority::ThreadSchedulePolicy::Normal(
                thread_priority::unix::NormalThreadSchedulePolicy::Idle,
            ),
        );
        match result {
            Ok(_) => { // we set idle priority
                println!(" done.");
            },
            Err(e) => {
                eprintln!("Warning: Unable to reduce thread priority. Continuing to run at default thread priority. Other application performance may be affected. {:?}", e);
            }
        }
    }

I say this may not be valid, because it specifies ThreadPriority::Min. Assuming it isn't mapped to the valid range for the scheduler policy, this is invalid, because, per man sched(7), the static priority 0 must be used with SCHED_IDLE. If ::Min is being mapped to 0 here, then this is in fact valid, if not, it's invalid usage. When I try like this, everything compiles, and runs, without error. Note that the above "Ok(_)" match arm is used, and "done" is emitted. However, usage of "chrt" on the running process reveals it is still SCHED_OTHER (the default).

I have also attempted to specify 0 as the priority, which runs into not being able to specify 0 directly (the method that would allow that is private). When I use get_current_thread_priority(), I get a "Crossplatform(ThreadPriorityValue(0))" which is rejected by the subsequent set_thread_priority_and_policy() call with "PriorityNotInRange(0..=0)".

In reading the sources (https://docs.rs/thread-priority/latest/src/thread_priority/unix.rs.html#1-795) it seems as though only Realtime is treated specially, and everything else is left to be done via "niceness" - which won't achieve setting the SCHED_IDLE policy.

Am I totally missing something?

@iddm
Copy link
Owner

iddm commented Oct 12, 2023

I have attempted two paths to set Idle scheduling class. The first is not actually "valid" (possibly):


    #[cfg(target_os = "linux")]
    {
        print!("Linux detected. Setting idle scheduling class...");
        let thread_id = thread_priority::thread_native_id();
        let result = thread_priority::set_thread_priority_and_policy(
            thread_id,
            thread_priority::ThreadPriority::Min,
            thread_priority::ThreadSchedulePolicy::Normal(
                thread_priority::unix::NormalThreadSchedulePolicy::Idle,
            ),
        );
        match result {
            Ok(_) => { // we set idle priority
                println!(" done.");
            },
            Err(e) => {
                eprintln!("Warning: Unable to reduce thread priority. Continuing to run at default thread priority. Other application performance may be affected. {:?}", e);
            }
        }
    }

I say this may not be valid, because it specifies ThreadPriority::Min. Assuming it isn't mapped to the valid range for the scheduler policy, this is invalid, because, per man sched(7), the static priority 0 must be used with SCHED_IDLE. If ::Min is being mapped to 0 here, then this is in fact valid, if not, it's invalid usage. When I try like this, everything compiles, and runs, without error. Note that the above "Ok(_)" match arm is used, and "done" is emitted. However, usage of "chrt" on the running process reveals it is still SCHED_OTHER (the default).

I have also attempted to specify 0 as the priority, which runs into not being able to specify 0 directly (the method that would allow that is private). When I use get_current_thread_priority(), I get a "Crossplatform(ThreadPriorityValue(0))" which is rejected by the subsequent set_thread_priority_and_policy() call with "PriorityNotInRange(0..=0)".

In reading the sources (https://docs.rs/thread-priority/latest/src/thread_priority/unix.rs.html#1-795) it seems as though only Realtime is treated specially, and everything else is left to be done via "niceness" - which won't achieve setting the SCHED_IDLE policy.

Am I totally missing something?

Thank you for your example and for providing a clear description.

The part about having two different priorities (niceness and scheduling priority) was very difficult to abstract into a single interface, so the user would just use something else while under the hood it would translate to niceness or a scheduling priority. This is why I made a decision to rewrite the crate to

  1. Allow to specifically work with niceness and not if that was the intention of the user.
  2. Still abstract away the priority much better (I thought I found a way).

Unfortunately, I have never released the new version of the crate since it is unfinished, even though it works properly in some cases already.

The part you are referring to is a bit confuses me: the code should have resulted in either just changing niceness to a minimum (so SCHED_OTHER with niceness 20), or returning an error since there was a check for SCHED_IDLE to only have a value of priority set between 0 and 0. Another question is why the tests pass, I'll need to take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants