Faster single-threaded game performance on HyperThreaded CPU

Discuss anything not covered by any of the other categories.
Post Reply
Posts: 924
Joined: Fri Jul 04, 2008 3:02 am

Faster single-threaded game performance on HyperThreaded CPU

Post by mankrip »

This is useful for old games, and sometimes may be useful as a temporary workaround during development of some engines:

The engine I'm currently developing has some really big sets of instructions in its inner rendering loops, which makes it very cache-intensive on the CPU. When CPU HyperThreading is enabled, the same cache space is shared between both virtual cores of each physical core; when the instructions for a virtual core fills the cache entirely, there's no cache space for the instructions that should be run on the other virtual core, and this forces the CPU to clear the cache and copy the instructions again and again, which results in the engine stuttering quite badly.

To work around this, we must disable HyperThreading. Some people even created a tool called CPUCores specifically for this, but its usability is quite limited for my purposes. Then I've found another way.

Some computers don't have an option to disable HT in the BIOS. Also, optimally, you may want to disable HT on a single physical core only, leaving HT enabled on the other physical cores; this is possible through Windows' Control panel -> Administrative tools -> System configuration.
In the System initialization tab, click on the Advanced options button to open a dialog box that will allow you to set the amount of "processors" to be used. The maximum should be an even number, like 4 or 8, the same as the amount of virtual cores in the system.
The trick is to reduce this by only 1, which will disable a single virtual core, effectively neutering HT on its physical core. Note: After rebooting the system, that last virtual core will have vanished from the drop-down list, so the maximum number of processors shown will be the odd number you set last time (but it should be restored if you clear the checkbox above).

Now, you must make your game run on the specific non-hyperthreaded physical core you have set. In a CPU with 4 hyperthreaded cores (two physical cores, which we'll call A and B, containing two virtual cores each, which we'll call 1 and 2), Windows enumerates cores by following a pattern of "virtual core 1 of physical core 1, virtual core 1 of physical core 2, virtual core 2 of physical core 1, virtual core 2 of physical core 2" (A1, B1, A2, B2). This means that when you reduce the maximum amount of processors from 4 to 3, you end up with cores "A1, B1, A2", which means that the core B1 is the one that had HT effectively disabled.

To run the game at the highest priority in that core, you can create a .bat file containing this line:

Code: Select all

@start /high /affinity 2 /b "Quake" winquake.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
The /affinity parameter takes a power-of-two parameter as the number of the processor that should be used. 1 is the first processor, 2 is the second, 4 is the third, 8 is the fourth, etc.

Now, for an addendum: Some engines (e.g. mine) still supports only CD audio tracks for music playback, so you may need to patch them to play OGG/MP3 music through _inmm.dll.
This brings an additional problem: by default, Windows constrains external DLLs to the same cores of the program that called them, but with normal priority; this means that if you launch the game through the .bat file above, the music playback almost never gets enough free cache space for its instructions and ends up not playing. However, it's possible to start _inmm.dll separately, and in doing so, we can make it run the music playback in another core.

Open the .bat file you had created before, and add these first two lines to the top:

Code: Select all

@start /affinity 1 /b "_inmm.dll" _inmm238\_inmmserv.exe


@start /high /affinity 2 /b "Quake" winquake.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
The first line assumes that you've installed _imm.dll to a subfolder named "_inmm238"; modify if needed.
The TIMEOUT line pauses the .bat file for 1 second to give time for _inmm.dll to finish loading before the game executable is launched.

In systems prior to Windows 7, the TIMEOUT command doesn't exist. You can replace its line with this, which also makes the .bat file execution wait 1 second before launching the game:

Code: Select all

@PING -n 1 -w 1000 >NUL
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
Dev blog / Twitter / YouTube
Post Reply