Title: Using the Affinity Mask in multi-CPU environments
Question: When writing applications that are designated to tun in multi-CPU environments, it is very useful to be able to control which CPU's the application executes on. By optimizing the CPU usage one can dramatically increase the performance of the application
Answer:
Introduction
When writing applications that are designated to tun in multi-CPU
environments, it is very useful to be able to control which CPU's the
application executes on.
By optimizing the CPU usage one can dramatically increase the
performance of the application.
Affinity Masks - Background
When a process is created in windows, an affinity mask is passed to it.
This is usually the system affinity mask, since the system is launching
the process.
Also by default each thread created by this process is now assigned
the current affinity mask for the process. This means that the
thread is executed in any of the available CPU's.
If the "Process Affinity Mask" is changed, all threads created after
that will only be allowed to execute in any of the available CPU's,
also the whole process is limited to the same CPU's.
Getting the Affinity Mask
Windows provides us with an API call that help us get the affinity
mask.
The API call is:
GetProcessAffinityMask( hProcess: Cardinal; var procAFMask, sysAFMask );
The hProcess parameter is the current process handle, and the
procAFMask and sysAFMask variables are cardinals.
Before we change the affinity mask, we first need to get the current
affinity mask for the whole system. This is because we do not want
to try to set an affinity mask that is not possible.
When the API call returns it puts the BitMASK for the CPU's in each
of the parameters.
The bits are encoded as followes:
BitMask CPU's
========= =========
00000001 1st CPU
00000010 2nd CPU
00000100 3rd CPU
00001000 4th CPU
00010000 5th CPU
00100000 6th CPU
01000000 7th CPU
10000000 8th CPU
By combining these BIT values one can determine the CPU count/mask.
The BitMask is 32 bits in size, so theoretically the BitMask supports
up to 32 CPU's.
Example: BitMask=00000011 would mean 2 CPU's, number 1 and 2.
Changing the Affinity Mask of a Process
Windows provides us with an API call that help us set the affinity
mask.
The API call is:
SetProcessAffinityMask( hprocess: Cardinal; ProcessAffinityMask: Cardinal );
The hProcess parameter is the current process handle, and the
ProcessAffinityMask variable is a cardinal.
To obtain the current process handle we need another API call
named "GetCurrentProcess()". This API call returns the handle
of the current process.
The ProcessAffinityMask variable contains the BitMASK of the
CPU's we want this process to execute on. (see the BitMask table
above).
Example:
Var
ProcAFMask,
SysAFMask : Cardinal;
Begin
{ Get the current values }
GetProcessAffinityMask( GetCurrentProcess, ProcAFMask, SysAFMask);
{ Manipulate }
SysAFMAsk := $00000001; // Set this process to run on CPU 1 only
{ Set the Process Affinity Mask }
SetProcessAffinityMask( GetCurrentProcess, SysAFMAsk);
End;
A realworld example
Now that I have shown how to get and set the affinity masks for
processes, I'd like to show a real-world example of how to utilize
this.
I had a situation where our customer had a 4 CPU server, and used
it for some heavy processing about 80% of the time.
The customer wanted us to create an application for them, but they
didn't want to invest in the hardware, since they already had a
good server running. They where unsure of the total load on the
server so we investigated, and found that the server only used
the 2 first CPU's when under heavy load. This meant that there were
2 CPU's available for us !
So we implemented the Affinity Mask API calls, and concluded that
our application was executing nicely on CPU's number 3 and 4 only,
leaving the 2 other CPU's free for the other application on the
server.
Our application used alot of Threads, but since the master affinity
for the whole process was changed, the threads followed the set
parameters without problems.
What about the affinity masks for the Threads ?
If you want to read more about the affinity masks for Threads
there is an excellent article at:
http://www.delphi3000.com/articles/article_2605.asp.
Enjoy !