One thing I've been able to play with as of late is multi-processing support, or taking into account the presence of multiple CPUs. While I can't say much as it relates to "best practices" to make efficient use of multi-processing, I can describe some basics related to what you would need to do to take it into account. So call this a "preliminary FAQ" or a discussion or what you will, I thought I would share these things. Maybe something more can be shaped in terms of specifics to be able to make it a FAQ here.
Something that supports multi-processing generally implies supporting multi-threading. Multi-threaded apps are beyond the scope of what I intend to cover.
Multi-processing options are expressed in the OS through the setting of affinities. You can do this through task-manager to indicate which CPUs you want an application to run on. Task manager controls things at the process level.
You can also do this at the code level, as seen in the unit example. If you have access to a multi-core system running an NT based OS (under 9X the only valid affinity is $01), you will see that the OS defaults to using any of the CPUs present.
At the code level, an affinity tag is a DWord which represents a bit array, indicating which CPUs you want. You will see those tagged within the code below. A 0 bit indicates the CPU in that position is not to be used, and a 1 bit indicates the CPU is to be used. As described above, any of the valid CPUs can be tagged. We can find that out by getting an affinity mask for the process. As well, this API function will return the allowable system affinity mask - meaning the system will only support a variation of the mask that is returned. In other words, this allowable system mask represents the number of CPUs present. For convienence sake, a function is provided in the sample that will provide a quantitative value representing the number of CPUs on the system (i.e. 4 instead of $1111).
Setting of the process affinity mask is illustrated in the code. This means presenting the process handle, along with an affinity mask. Using the defined constants will be more descriptive. This sets the current process to run on either CPU3 or CPU4.
Affinities can also be set on specific threads. Setting this does not relate much to the main thread, since it is connected to the process. But if you create threads, then you can set them to run on a specific CPU. Valid thread affinities are a subset of the process affinity. In other words, I can not create a thread to run on CPU 3 in a process which is only set to run on CPU 1 or CPU 2. This sample sets a created TThread descendent named MyThread to run on CPU 2:
Code Sample below:
Measurement is not management.
Something that supports multi-processing generally implies supporting multi-threading. Multi-threaded apps are beyond the scope of what I intend to cover.
Multi-processing options are expressed in the OS through the setting of affinities. You can do this through task-manager to indicate which CPUs you want an application to run on. Task manager controls things at the process level.
You can also do this at the code level, as seen in the unit example. If you have access to a multi-core system running an NT based OS (under 9X the only valid affinity is $01), you will see that the OS defaults to using any of the CPUs present.
At the code level, an affinity tag is a DWord which represents a bit array, indicating which CPUs you want. You will see those tagged within the code below. A 0 bit indicates the CPU in that position is not to be used, and a 1 bit indicates the CPU is to be used. As described above, any of the valid CPUs can be tagged. We can find that out by getting an affinity mask for the process. As well, this API function will return the allowable system affinity mask - meaning the system will only support a variation of the mask that is returned. In other words, this allowable system mask represents the number of CPUs present. For convienence sake, a function is provided in the sample that will provide a quantitative value representing the number of CPUs on the system (i.e. 4 instead of $1111).
Setting of the process affinity mask is illustrated in the code. This means presenting the process handle, along with an affinity mask. Using the defined constants will be more descriptive. This sets the current process to run on either CPU3 or CPU4.
Code:
SetProcInfo(CPUID[3] or CPUID[4]);
Affinities can also be set on specific threads. Setting this does not relate much to the main thread, since it is connected to the process. But if you create threads, then you can set them to run on a specific CPU. Valid thread affinities are a subset of the process affinity. In other words, I can not create a thread to run on CPU 3 in a process which is only set to run on CPU 1 or CPU 2. This sample sets a created TThread descendent named MyThread to run on CPU 2:
Code:
SetThreadInfo(mythread.handle, CPUID[2]);
Code Sample below:
Code:
unit multiproc;
interface
uses windows;
{ presents code to manipulate affinity masks for current processes or current threads, developed in Delphi 3 }
const
CPUID: Array[1..32] of Longint =
($01, $02, $04, $08, $10, $20, $40, $80, $100, $200, $400, $800,
$1000, $2000, $4000, $8000, $10000, $20000, $40000, $80000,
$100000, $200000, $400000, $800000, $1000000, $2000000, $4000000,
$8000000, $10000000, $20000000, $40000000, $80000000);
procedure getprocinfo(var procaffmask, sysaffmask: DWord);
function setprocinfo(procmask: DWord): boolean;
function setthreadinfo(handle: THandle; value: DWord): boolean;
function GetNumberOfProcessors : Integer;
implementation
procedure getprocinfo(var procaffmask, sysaffmask: DWord);
// get process affinity mask and allowable system mask for current process
begin
GetProcessAffinityMask(GetCurrentProcess, procaffmask, sysaffmask);
end;
function setprocinfo(procmask: DWord): boolean;
// set process affinity mask for current process, boolean indicates success
begin
Result := SetProcessAffinityMask(GetCurrentProcess, procmask);
end;
function setthreadinfo(handle: THandle; value: DWord): boolean;
// set thread affinity mask for current process. Boolean indicates success
begin
Result := (SetThreadAffinityMask(handle, value) = 0);
end;
function GetNumberOfProcessors : Integer;
// returns the number of processors in the system
var
Info : TSystemInfo;
begin
GetSystemInfo(Info);
result := Info.dwNumberOfProcessors;
end;
end.
Measurement is not management.