Coverage Report

Created: 2026-05-23 21:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/build/source/nativelink-worker/src/qos.rs
Line
Count
Source
1
// Copyright 2024 The NativeLink Authors. All rights reserved.
2
//
3
// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    See LICENSE file for details
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
//! Darwin `QoS` (Quality of Service) helpers for worker scheduling.
16
//!
17
//! Apple Silicon (M-series) CPUs have a heterogeneous topology with
18
//! performance ("P") and efficiency ("E") cores. XNU's scheduler routes
19
//! threads to P or E cores in part based on the thread's `QoS` class. The
20
//! default class assigned to long-running background daemons is typically
21
//! `UTILITY` or `BACKGROUND`, both of which the scheduler may park on
22
//! E-cores.
23
//!
24
//! Single-thread-bursty workloads such as `swift-frontend` and `clang`
25
//! invocations (typical in iOS RBE builds) can run 2x–3x slower when
26
//! pinned to an E-core. Tagging the worker process with
27
//! `QOS_CLASS_USER_INITIATED` tells the scheduler to treat its threads
28
//! as foreground-equivalent and bias placement toward P-cores.
29
//!
30
//! On Linux and Windows these helpers compile away to nothing — they are
31
//! intentionally not behind a runtime branch so non-macOS builds never
32
//! emit a call.
33
34
/// Sets the calling thread's `QoS` class to `USER_INITIATED` on macOS.
35
///
36
/// Returns `true` if the underlying `pthread_set_qos_class_self_np`
37
/// call succeeded; returns `false` if it failed.
38
///
39
/// Safe to call from any thread, including tokio runtime worker threads
40
/// via `Builder::on_thread_start`.
41
#[cfg(target_os = "macos")]
42
#[inline]
43
pub fn set_user_initiated() -> bool {
44
    // SAFETY: `pthread_set_qos_class_self_np` is a thread-local
45
    // setter with no preconditions on the caller; passing a valid
46
    // enum variant and relative priority 0 is always defined.
47
    let ret = unsafe {
48
        libc::pthread_set_qos_class_self_np(libc::qos_class_t::QOS_CLASS_USER_INITIATED, 0)
49
    };
50
    ret == 0
51
}
52
53
/// Compile-time no-op on non-macOS targets.
54
///
55
/// Always returns `true`. The call site expands to nothing after
56
/// inlining / dead-code elimination, so non-macOS builds never emit
57
/// a runtime branch or a libc call.
58
#[cfg(not(target_os = "macos"))]
59
#[inline]
60
1
pub const fn set_user_initiated() -> bool {
61
1
    true
62
1
}
63
64
#[cfg(all(test, target_os = "macos"))]
65
mod macos_tests {
66
    use super::set_user_initiated;
67
68
    /// Reads the current thread's `QoS` class via `pthread_get_qos_class_np`.
69
    /// Panics with a contextual message on failure (only called from tests).
70
    fn current_qos_class() -> libc::qos_class_t {
71
        let mut class: libc::qos_class_t = libc::qos_class_t::QOS_CLASS_UNSPECIFIED;
72
        let mut rel_prio: libc::c_int = 0;
73
        // SAFETY: out-pointers point to stack-allocated, properly sized
74
        // and aligned storage owned by this thread.
75
        let ret = unsafe {
76
            libc::pthread_get_qos_class_np(
77
                libc::pthread_self(),
78
                core::ptr::from_mut(&mut class),
79
                core::ptr::from_mut(&mut rel_prio),
80
            )
81
        };
82
        assert_eq!(ret, 0, "pthread_get_qos_class_np failed: {ret}");
83
        class
84
    }
85
86
    /// Proves the `QoS` call is wired up on macOS and the underlying
87
    /// Darwin symbol resolves at link time. A failure here means the
88
    /// worker would silently keep running on E-cores.
89
    #[test]
90
    fn sets_user_initiated_on_current_thread() {
91
        assert!(
92
            set_user_initiated(),
93
            "pthread_set_qos_class_self_np(USER_INITIATED) returned non-zero",
94
        );
95
        // `qos_class_t` is a `#[repr(u32)]` C enum that does not derive
96
        // `PartialEq` in libc, so compare the underlying discriminants.
97
        assert_eq!(
98
            current_qos_class() as u32,
99
            libc::qos_class_t::QOS_CLASS_USER_INITIATED as u32,
100
            "`QoS` class did not update; thread will be eligible for E-core scheduling",
101
        );
102
    }
103
104
    /// Validates the load-bearing claim that tokio worker threads created
105
    /// with a `Builder::on_thread_start` hook calling `set_user_initiated`
106
    /// observe `QOS_CLASS_USER_INITIATED` from inside spawned tasks. This
107
    /// mirrors the wiring in `src/bin/nativelink.rs::main`. Without this
108
    /// test the entire `QoS` scheme is unverified at the integration level.
109
    ///
110
    /// This is the one place in the worker crate that must construct a
111
    /// fresh `tokio::runtime::Builder::new_multi_thread()` and drive it
112
    /// with `block_on` — the unit under test *is* the `on_thread_start`
113
    /// hook on a custom-built runtime, which `nativelink-util::task` and
114
    /// `#[nativelink_test]` do not expose. The `#[expect]` mirrors the
115
    /// same justified escape used in `src/bin/nativelink.rs::main`.
116
    #[test]
117
    #[expect(
118
        clippy::disallowed_methods,
119
        reason = "test exercises `Builder::on_thread_start` + `block_on`; \
120
                  no util wrapper exposes a custom-built runtime with a thread-start hook"
121
    )]
122
    fn tokio_worker_threads_inherit_user_initiated_via_on_thread_start() {
123
        // Deliberately build a fresh runtime in-test (do not reuse a
124
        // global one) so the hook is exercised on freshly-spawned
125
        // worker threads with whatever class they were born with.
126
        let rt = tokio::runtime::Builder::new_multi_thread()
127
            .worker_threads(2)
128
            .on_thread_start(|| {
129
                assert!(set_user_initiated(), "hook failed in worker thread");
130
            })
131
            .enable_all()
132
            .build()
133
            .expect("build tokio runtime");
134
135
        let observed: u32 = rt.block_on(async {
136
            // Force execution on a worker thread (not the caller).
137
            tokio::spawn(async { current_qos_class() as u32 })
138
                .await
139
                .expect("join spawned task")
140
        });
141
142
        assert_eq!(
143
            observed,
144
            libc::qos_class_t::QOS_CLASS_USER_INITIATED as u32,
145
            "tokio worker thread did not inherit USER_INITIATED from on_thread_start",
146
        );
147
    }
148
}
149
150
#[cfg(all(test, not(target_os = "macos")))]
151
mod non_macos_tests {
152
    use super::set_user_initiated;
153
154
    /// On Linux/Windows the function must be a true no-op that always
155
    /// reports success — there is no runtime cost and no platform call.
156
    #[test]
157
1
    fn is_a_noop_on_non_macos() {
158
1
        assert!(set_user_initiated());
159
1
    }
160
}
161
162
/// Compile-time assertion: when `target_os` is not `macos`, this module
163
/// must not reference any libc symbol. Reviewers can `grep "extern crate
164
/// libc"` or inspect this constant to verify the no-op story.
165
#[cfg(not(target_os = "macos"))]
166
pub const NON_MACOS_IS_NOOP: () = ();