Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reserve a core for one thread on windows?

I am working on a very time sensitive application which polls a region of shared memory taking action when it detects a change has occurred. Changes are rare but I need to minimize the time from change to action. Given the infrequency of changes I think the CPU cache is getting cold. Is there a way to reserve a core for my polling thread so that it does not have to compete with other threads for either cache or CPU?

like image 638
Samwise99 Avatar asked Mar 17 '11 23:03

Samwise99


People also ask

Can you only have one thread per core?

Each CPU has 1 or many cores. Some cores have a feature called SMT (Simultaneous Multi Threading) where one core could have 2 or more threads. For example most x86 today (Intel started Hyperthreading in 2002) are dual thread but IBM PowerPC could have up to 8 threads per core! Btw Intel name for SMT is Hyperthreading.


2 Answers

Thread affinity alone (SetThreadAffinityMask) will not be enough. It does not reserve a CPU core, but it does the opposite, it binds the thread to only the cores that you specify (that is not the same thing!).

By constraining the CPU affinity, you reduce the likelihood that your thread will run. If another thread with higher priority runs on the same core, your thread will not be scheduled until that other thread is done (this is how Windows schedules threads).
Without constraining affinity, your thread has a chance of being migrated to another core (taking the last time it was run as metric for that decision). Thread migration is undesirable if it happens often and soon after the thread has run (or while it is running) but it is a harmless, beneficial thing if a couple of dozen milliseconds have passed since it was last scheduled (caches will have been overwritten by then anyway).

You can "kind of" assure that your thread will run by giving it a higher priority class (no guarantee, but high likelihood). If you then use SetThreadAffinityMask as well, you have a reasonable chance that the cache is always warm on most common desktop CPUs (which luckily are normally VIPT and PIPT). For the TLB, you will probably be less lucky, but there's nothing you can do about it.

The problem with a high priority thread is that it will starve other threads because scheduling is implemented so it serves higher priority classes first, and as long as these are not satisfied, lower classes get zero. So, the solution in this case must be to block. Otherwise, you may impair the system in an unfavorable way.

Try this:

  • create a semaphore and share it with the other process
  • set priority to THREAD_PRIORITY_TIME_CRITICAL
  • block on the semaphore
  • in the other process, after writing data, call SignalObjectAndWait on the semaphore with a timeout of 1 (or even zero timeout)
  • if you want, you can experiment binding them both to the same core

This will create a thread that will be the first (or among the first) to get CPU time, but it is not running. When the writer thread calls SignalObjectAndWait, it atomically signals and blocks (even if it waits for "zero time" that is enough to reschedule). The other thread will wake from the Semaphore and do its work. Thanks to its high priority, it will not be interrupted by other "normal" (that is, non-realtime) threads. It will keep hogging CPU time until done, and then block again on the semaphore. At this point, SignalObjectAndWait returns.

like image 119
Damon Avatar answered Nov 17 '22 04:11

Damon


Using the Task Manager, you can set the "affinity" of processes.

You would have to set the affinity of your time-critical app to core 4, and the affinity of all the other processes to cores 1, 2, and 3. Assuming four cores of course.

like image 30
OrangeDog Avatar answered Nov 17 '22 05:11

OrangeDog