Automating the Modification of a Windows Process’s Affinity: the Wrong Ways and the PowerShell Way

I just built a workstation that runs an ongoing set of computations on Windows 7 Professional x64. A main program spawns one process for each physical and virtual core as well as each GPU. I have a hyperthreaded four-core i7 which makes for eight total cores and thus eight individual processes. I also have a single GTX 465 graphics card which requires a single process on the CPU to communicate tasks to the CUDA cores. I noticed almost immediately that my GPU was rarely ever more than 50% utilized. I wondered if it was simply an inefficiency with the original application but wasn’t able to figure out why until I happened upon a forum post that spoke to virtually the same problem. Apparently if a CPU is completely saturated it can’t keep up with the demands of communicating instructions to and from the GPU.

With this new information in mind I played around with setting the processor affinity for each process. Opening up task manager I saw that I had 8 process for the CPU computations and one for the GPU computation. I selected each process that was for the CPU and only allowed it to use cores 1 – 7, leaving core 0 free. I then set the process that controlled the GPU’s task to use only CPU 0. I then checked my GPU and it’s utilization was at near 100%.

The problem with my situation is that after a matter of minutes or hours, each of the CPU processes has finished its calculations and a new set is launched with all new affinity. This chokes out the ability of the CPU to keep up with the GPU which drops back down to only 50% utilization and wastes a huge amount of processing power. Furthermore, the waste will be compounded when I install a second GTX 465 in the near future. I don’t even want to think about beyond when I venture into 4 or more GTX 500 series cards. I sat and pondered.

Unfortunately, since I’m not running a server operating system on this workstation, using WSRM is not an option. I either need a script to run on a schedule or some way of editing the executable to impart affinity at execution time. I was leery of using a script at first because it would need to be run on a short schedule. Perhaps only a few seconds. I don’t want to wait too much longer than that and lose time on a GPU task that could be running at 100%, so I would likely consider running the script every 15 seconds or so. However, that seems a bit inefficient by taking up precious cycles. Not many, but still some.

Behold the /affinity switch!

I searched around and found a drop-dead simple way for me to change the affinity of an application at run-time. It’s a matter of using the ‘start’ command with the /affinity switch. Going back to my specific scenario, a main application launches one of two executables to begin performing the calculations (one .exe for CPU instructions and one .exe for GPU instructions). The CPU-based .exe is launched one time per core. I had the simple idea to replace the .exe files with shortcuts that had the following path:

C:windowssystem32cmd.exe /C start /affinity 2,3,4,5,6,7,8 “C:program filesapplicationCPUexecutable.exe”

Unfortunately, that did not work. The main application did not spawn any processes. I wondered if it was due to the shortcuts being detected as links and not actual .exe files. My next idea was to create a batch file with the command listed above and then convert the .bat to a .exe. That should take care of the problem if it was a simple matter of not liking the .link file type. I did so with this bat to exe converter. It worked liked a charm! Sort of. At least, the executables that were created from the batch files were functioning well and properly modified processor affinity for the spawned process. However, it only worked when I manually launched the .exe files. The parent program did not like the new executables so much. I didn’t have a set of running processes like I would have expected and no computations were being performed.

Checking the error logs of the parent program showed that it threw errors concerning the executable’s size so it must have been performing some kind of verification check. Even sneakier, it pulls down the latest version of the executable from the internet and copies over anything in the directory with that name. My converted batch files were erased over. I briefly considered changing permissions on the file to prevent it from being deleted, but that was unlikely to work. If the executables were being checked for size there was probably no way it was going to start it even if it couldn’t remove it.

Behold ImageCfg!

ImageCfg is an old school application from the days of yore. That’s right. The days when Windows 2000 roamed the earth. In those days ImageCfg could be found on the Windows 2000 Server Resource Kit (Supplement One) CD. It is intended to change the headers in the executable itself and modify the options for process affinity at launch time.

However, I had my reservations. The revelation about the parent app checking the file size made the use of ImageCfg seem less likely to work. Would changing the headers change the file’s overall size? Then again, perhaps changing the affinity on the binary won’t actually change the overall size since the bits likely already exist just at different values. The second thing troubling me was that there is some disagreement on if ImageCfg works on 64 bit executables. It just so happens that one of the .exe’s I need to modify is 64 bit.

I forged ahead and gave ImageCfg a try. Sadly, after messing with my executables, I discovered that indeed ImageCfg cannot modify a native 64-bit application. Of the two executables that I needed to modify, ImageCfg spat out an error on the 64-bit version but happily tweaked the 32-bit one. Interestingly, there was absolutely no change to the file’s footprint in size. I did not bother calculating before and after checksums, however, since the parent application doesn’t seem to base its judgmental off of checksum values.

Behold PowerShell!

At this point I was ready to take the scripted route and hope that I didn’t lose too much performance. In reality, it was probably the better option from the start. I’m beginning to think that any solution on Windows that does not involve PowerShell is not the true solution.

In PowerShell, it’s a relatively simple matter of getting the list of processes that you’re interested in via Get-Process using the -name mask and then stuffing them into a variable like this:

$proclist = Get-Process -name mask

Once in that list, I simply iterate through a foreach loop and set the ProcessorAffinity value:

foreach ($proc in $proclist) {$proc.ProcessorAffinity=0xFE}

The hex value “FE” is the value used to single out cores 1 – 7 and assign the process to them only. Hexadecimal codes used to choose cores are calculated like this:

Core 0 = Decimal 1
Core 1 = Decimal 2
Core 2 = Decimal 4
Core 3 = Decimal 8
Core 4 = Decimal 16 (hexadecimal 10)
Core 5 = Decimal 32 (hexadecimal 20)
Core 6 = Decimal 64 (hexadecimal 30)
Core 7 = Decimal 128 (hexadecimal 60)

To choose multiple cores, add up the decimal numbers and convert the total to hex (or just add them up in hex if you’re hardcore). My scenario of having 8 cores but wanting to leave core 0 free makes the equation look like this:

2 + 4 + 8 + 16 + 32 + 64 + 128 = 254 = 0xFE

In my situation I didn’t need a second search of processes to find the CUDA process and assign it to core 0. Once core 0 was freed up from the other eight processes the GPU process could run as normal and in fact saturated the entire 0 core.

Behold Task Scheduler!

After the above was performed all that remained was to make the two-liner into a scheduled task. I set the scheduled task to run every 1 minute (the lowest interval that a scheduled task can run) and ran the following command:

C:Windowssystem32WindowsPowershellv1.0powershell.exe -nonInteractive -executionPolicy unrestricted -File “C:Pathtoscript.ps1”

If I decide that I absolutely need to run the script more than just once per minute, I’ll need to handle that in a loop within the script. So far, that doesn’t seem to be necessary.



The original article that gave me a large list of options for setting affinity. Thanks Wayne!

Good article on affinity setting.

This is a good article on ImageCfg and it also includes a place where you can download the application since it’s rather hard to come by these days unless you have the original Windows 2000 Server Resource Kit (Supplement One) CD.

Leave a Reply

Follow TheNubbyAdmin!

follow us in feedly

Raw RSS Feed:

Contact Me!

Want to hire me as a consultant? Have a job you think I might be interested in? Drop me a line:

Contact Me!

Subscribe via Email

Your email address is handled by Google FeedBurner and never spammed!

The Nubby Archives

Circle Me on Google+!

Photos from Flickr

Me on StackExchange

The IT Crowd Strava Group

%d bloggers like this: