Skip to content

Wine NSPA: Realtime Scheduling, Policies and Prioritization

jrdnjhnstn edited this page Jul 15, 2024 · 11 revisions

Thread Scheduling, Policies and Priorities

One of the focuses of Wine-NSPA is to make Wine highly-Preemptive. This fork has additional scheduling and RT capabilities; leveraging out-or-tree scheduling patches and other modifications to do so. It contains some stark differences from Wine-Staging's wine-rt patch and other attempts at making wine more RT capable.

First, nice priorities can/are setup for all threads in Wine-NSPA. Second, Real-Time priorities AND policies can also be setup for Wine's threads / application threads. In fact, the majority of threads in Wine-NSPA can be made RT and many of the threads are set to Real-Time without Wineserver. Ntdll has been modified to filter and set pthread && fsync related threads to RT.

Have a look below;

Here, we can see wine's own process threads are running as Real-Time. What you can't see here is that these threads are mostly futex-related and are running with SCHED_RR policy, while the highest RT priority threads are FIFO. -- Some threads are hardcoded to be SCHED_FIFO, as they do not want SCHED_RR behaviour. -- These include Wineserver, kernel-mode APCs and all THREAD_PRIORITY_TIME_CRITICAL threads. However, the main process threads do not run as Real-Time...

Next, let's have a look at application threads;

The very highest priority RT threads are FIFO (winAPI THREAD_PRIORITY_TIME_CRITICAL = -78); while all lower RT priority threads are SCHED_RR. Notably, the very lowest RT priority threads are important; these are worker threads and the Wine-rt patch can't set them as RT properly. <- Have you ever ran into a multi-processor mode in a plugin that causes xruns and glitching? Well, it's likely because the plugin's worker threads weren't running with Real-Time priorities...

RT Scheduling in Wine-NSPA is controlled via Environment Variables. These are;

  • WINE_RT_PRIO=80 : Set RT thread Prioties from Wineserver -> Sets highest priority, then decrements by 2.
  • WINE_RT_POLICY="RR" : Set RT Policy from Wineserver. -> FF(SCHED_FIFO) and RR(SCHED_RR) policies.
  • NTDLL_RT_PRIO=5 : Set RT thread priorities from Ntdll -> NT threads: fsync'd APCs or non-winAPI pthreads.
  • NTDLL_RT_POLICY="RR" : Set NTDLL scheduling policy. -> supports FF(SCHED_FIFO), RR(SCHED_RR) and TS(SCHED_OTHER).

note: Setting NTDLL_RT_POLICY=TS will make all non-WinAPI threads SCHED_OTHER, but will not affect APCs / Fsync threads. This basically sets up Wine-NSPA's RT threads to behave like the Wine-RT patch in Wine-Staging.

Wineserver SHMEM Per Thread:

It's important to note that Wineserver ends up being heavily multi-threaded, due to the SHMEM Per Thread patch. This patch creates shared memory per thread for server requests and replies ~ this is actually super helpful for proaudio / RT apps, because it means that wineserver (single-threaded usually) doesn't get hammered by realtime requests, as much. Instead these are deferred to the SHMEM threads...

In practice, this means that some plugins/apps that may use a large threadpool and/or support Multi-threaded Mode will likely run better. U-he plugins such as Ace & Diva are two examples. But even NI Kontakt will scale better using this code/patchwork.