Skip to content

Instantly share code, notes, and snippets.

@BrettRToomey
Last active May 24, 2024 15:22
Show Gist options
  • Save BrettRToomey/a1e32c2f99fbb9d34dd4bec8566e6d00 to your computer and use it in GitHub Desktop.
Save BrettRToomey/a1e32c2f99fbb9d34dd4bec8566e6d00 to your computer and use it in GitHub Desktop.
Apple Thread Priorities
#include <pthread.h>
typedef struct Thread_Desc {
qos_class_t qos;
int relative_priority;
int sched_policy;
void *userdata;
} Thread_Desc;
pthread_t create_thread( void *(*callback)(void *), Thread_Desc *desc )
{
pthread_t thread_id;
pthread_attr_t attr;
pthread_attr_init(&attr);
void *userdata = NULL;
if (desc) {
int relative_priority = desc->relative_priority;
relative_priority = relative_priority < 0 ? relative_priority : 0;
relative_priority = relative_priority > QOS_MIN_RELATIVE_PRIORITY ? relative_priority : QOS_MIN_RELATIVE_PRIORITY;
pthread_attr_set_qos_class_np(&attr, desc->qos, relative_priority);
pthread_attr_setschedpolicy(&attr, desc->sched_policy);
userdata = desc->userdata;
}
pthread_create(&thread_id, &attr, callback, userdata);
return thread_id;
}
void *thread_entry( void *userdata )
{
return NULL;
}
int main( void )
{
/*
Most information from
"Tune CPU job scheduling for Apple silicon games"
https://developer.apple.com/videos/play/tech-talks/110147/
Choosing a QoS class:
When choosing a QoS class, you automatically get the max priority
for the class. You can use the `relative_priority` to lower the
priority. `relative_priority` must be within [ 0, QOS_MIN_RELATIVE_PRIORITY (-15) ].
Priority
Recommended usage Def/Max Min
-----------------------------------------
QOS_CLASS_USER_INTERACTIVE Per-frame work 47 -- 38
QOS_CLASS_USER_INITIATED Async/inter-frame work 37 -- 32
QOS_CLASS_DEFAULT Streaming/Longer deadline 31 -- 21
QOS_CLASS_UTILITY Background download/compute 20 -- 5
QOS_CLASS_BACKGROUND Might not run for long time! 4 -- 0
Assigning QoS class to threads:
// Create thread with a given QoS class
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_set_qos_class_np(&attr, QOS_CLASS_..., relative_priority);
pthread_create(&thread_id, &attr, entry_point, userdata);
pthread_attr_destroy(&attr);
// Change the QoS class for the current thread
pthread_set_qos_class_self_np(QOS_CLASS..., relative_priority);
Choosing a scheduling policy
When choosing a scheduling policy you need to decide if the
thread should be realtime or not. You need to be careful with
realtime threads to not starve the OS.
Realtime Description
-------------------------------------------------------------------------
SCHED_FIFO YES First come first serve, not time limited. Easy to starve the OS!
SCHED_RR YES Round-robin, time limited, tries to be fair
SCHED_OTHER NO Default behaviour on macOS, most fair
Example Configurations:
Realtime:
Policy QoS Class
----------------------------------------------------
Main Thread SCHED_OTHER QOS_CLASS_USER_INTERACTIVE (prio 47)
Render Thread SCHED_RR QOS_CLASS_USER_INTERACTIVE (prio 45)
Workers (High prio.) SCHED_RR QOS_CLASS_USER_INTERACTIVE (prio 39-41)
Workers (Medium/low prio.) SCHED_OTHER QOS_CLASS_USER_INTERACTIVE (prio 38)
Long duration
Policy QoS Class
-----------------------------------------------
Workers (High prio.) SCHED_OTHER QOS_CLASS_USER_INITIATED (prio 37)
Prefetching/streaming SCHED_OTHER QOS_CLASS_DEFAULT (prio 31)
Other low priority tasks SCHED_OTHER QOS_CLASS_UTILITY (prio 20)
*/
pthread_t thread = create_thread(thread_entry, &(Thread_Desc) {
.qos = QOS_CLASS_USER_INTERACTIVE,
.sched_policy = SCHED_OTHER,
});
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment