Running systemd Units Only If Certain CPU Features Are Available

systemd's logo (C) https://brand.systemd.io/
systemd’s logo

Do you have some kind of application that should only be executed when the user’s CPU has a certain feature? Or maybe your application has horrible performance unless some certain instructions are available? As you might know already, the Linux kernel exposes this information via /proc/cpuinfo:

processor       : 15
vendor_id       : AuthenticAMD
cpu family      : 23
model           : 96
model name      : AMD Ryzen 7 PRO 4750U with Radeon Graphics                                                                                                                                                                                  
...
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd _apicid aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce to poext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xge tbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif umip rdpid overflow_recov succor smca

Where does this data come from? One source of information is the cpuid instruction. On the x86 architecture systemd starting from v248 is now able to start or stop an unit based on the features exposed by the CPUID instruction. Enter ConditionCPUFeature. On CPUs that do not have the CPUID instruction i.e. ARM CPUs, it is assumed that the CPU implements no features and thus any potential CPUFeature conditions will fail.

The feature strings that systemd understands could be found here. So, for example to ensure that your service only runs when SSE 4.2, you should add this to your unit file:

[Unit]
ConditionCPUFeature=sse4_2

To negate this condition, put a exclamation mark in front. So, the same example but inverted would look like this:

[Unit]
ConditionCPUFeature=!sse4_2

This would ensure that the unit could only run if SSE 4.2 is not available.

Finally, it is worth mentioning that this assumes a homogenous system – i.e. all of the available CPU cores implement the same CPU features. In fact, the Intel CPU manuals & other manuals only typically assume that this is case because that’s true in most of the cases, as far as I can tell.

This could be improved in the future by checking all of the available CPU’s CPUID flags. On Linux this could be implemented by reading /dev/cpu/*/cpuid or explicitly scheduling a process on different CPUs & reading the CPU flags then. Or maybe systemd could even provide a feature where a unit could be scheduled only on CPUs which provide one or more provided features. If you are interested to know more then this article here provides good information.

I liked working on this feature in my own free time because I wanted to learn more about how these things work. I knew a bit about CPUID in the past however I never delved deep into it. Implementing this gave me valuable information about how stuff like identifying CPU’s features functions.