Skip to content

Commit 2c02a6e

Browse files
committed
chore: QoS settings for mac m series.
1 parent 65a0f67 commit 2c02a6e

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package dev.suresh.qos
2+
3+
import dev.suresh.downcallHandle
4+
import java.lang.foreign.FunctionDescriptor
5+
import java.lang.foreign.ValueLayout.JAVA_INT
6+
import java.util.concurrent.Executors
7+
import java.util.concurrent.SynchronousQueue
8+
import java.util.concurrent.ThreadFactory
9+
import java.util.concurrent.ThreadPoolExecutor
10+
import java.util.concurrent.TimeUnit
11+
import kotlinx.coroutines.asCoroutineDispatcher
12+
13+
/** Constrain JVM threads and coroutines to the efficiency cores available on M-series Macs */
14+
object FFMQosSetter {
15+
fun setQosClass(qosClass: QosClass, relativePriority: Int = 0): Int {
16+
val result =
17+
downcallHandle(
18+
"pthread_set_qos_class_self_np",
19+
FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT))
20+
?.invokeExact(qosClass.raw, relativePriority) as Int
21+
22+
when (result != 0) {
23+
true -> System.err.println("Failed to set QoS class, error code: $result")
24+
else -> println("QoS class set successfully.")
25+
}
26+
return result
27+
}
28+
}
29+
30+
/**
31+
* Refer to the
32+
* [Energy Efficiency Guide for Mac Apps](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/PrioritizeWorkAtTheTaskLevel.html#//apple_ref/doc/uid/TP40013929-CH35-SW5)
33+
*/
34+
enum class QosClass(val raw: Int) {
35+
QOS_CLASS_USER_INTERACTIVE(0x21),
36+
QOS_CLASS_USER_INITIATED(0x19),
37+
QOS_CLASS_DEFAULT(0x15),
38+
QOS_CLASS_UTILITY(0x11),
39+
QOS_CLASS_BACKGROUND(0x09),
40+
QOS_CLASS_UNSPECIFIED(0x00),
41+
}
42+
43+
val BackgroundQosCoroutineDispatcher by lazy {
44+
ThreadPoolExecutor(
45+
/* corePoolSize = */ 0,
46+
/* maximumPoolSize = */ Runtime.getRuntime().availableProcessors(),
47+
/* keepAliveTime = */ 60L,
48+
/* unit = */ TimeUnit.SECONDS,
49+
/* workQueue = */ SynchronousQueue(),
50+
/* threadFactory = */ object : ThreadFactory {
51+
52+
override fun newThread(r: Runnable): Thread {
53+
val fact = Executors.defaultThreadFactory()
54+
return fact.newThread(r).apply {
55+
FFMQosSetter.setQosClass(QosClass.QOS_CLASS_BACKGROUND)
56+
name = "QosThreadPool-${threadId()}"
57+
}
58+
}
59+
})
60+
.asCoroutineDispatcher()
61+
}

0 commit comments

Comments
 (0)