Example usage of SetProcessAffinityMask in C++?
Asked Answered
M

2

19

I need to pin various c/c++ processes to specific cores on a machine for benchmarking only on Windows 7 64-bit. My machine has 16 cores (2x8). I'm trying to do this by calling SetProcessAffinityMask from within the code for a given process. Assuming that's correct I am unsure of how exactly to use this function. I've seen the documentation but am unable to understand its description of what the second argument needs to be. I also haven't found any example c/c++ usage either on SO or on Google having searched.

Question1: Taking a 16 core machine (2cpux8) for example and a c/c++ project would you please provide an illustrative example for how to use SetProcessAffinityMask to pick each of the 16 cores and an explanation of the second argument for my understanding? How would I translate a core id from 0-15 to its equivalent bitmask?

Question2: Does it make a difference to the usage if there are 2x8 cores as opposed to 16 cores on one cpu? Or is it the same usage?

Many thanks. Here's what I have so far.

#include <Windows.h>
#include <iostream>

using namespace std;

int main () {

    HANDLE process = GetCurrentProcess();

    DWORD_PTR processAffinityMask = 0; /// What to do here?

    BOOL success = SetProcessAffinityMask(process, processAffinityMask);

    cout << success << endl;

    return 0;

}
Marilla answered 9/10, 2012 at 15:36 Comment(0)
G
19

The second parameter is a bitmask, where a bit that's set means the process can run on that proceesor, and a bit that's clear means it can't.

In your case, to have each process run on a separate core you could (for one possibility) pass a command line argument giving each process a number, and use that number inside the process to determine the processor to use:

#include <Windows.h>
#include <iostream>

using namespace std;

int main (int argc, char **argv) {
    HANDLE process = GetCurrentProcess();
    DWORD_PTR processAffinityMask = 1 << atoi(argv[1]);

    BOOL success = SetProcessAffinityMask(process, processAffinityMask);

    cout << success << endl;
    return 0;
}

Then you'd run this with something like:

for %c in (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) do test %c
Goldwin answered 9/10, 2012 at 15:45 Comment(10)
Thanks. Did you mean to go up to 15 in the last code snippet?Marilla
Ok np. So I tested this out. After your code I added code to create an int array of size 10^8, populate it with randoms and sort it to take up some cpu time. When I run this main method with one particular core selected, even though setprocessaffinitymask returns non-zero value, the process appears to take up 2-3 cores in task manager > performance visualisation judging by 100% utilisation spikes whenever I kick off the main method. Any idea why this may not be working or am I testing this wrong? I can post the updated code if you want.Marilla
Actually ignore what I said. Although multiple cores were spiked only one was being used. I increased the computation time 10 fold from before and only one core sustained load for that time. The other cores being spiked were being used for program setup but not for the program execution. So thanks. I'll accept your answer as it was what I originally tried and it worked and also for its simplicity. In case I come across core access issues I'll try paquetp's response.Marilla
One more quick question Jerry assuming it's still closely related to the original question. How can I set more than one core to run?Marilla
@junkie: Set more than one bit in the mask. E.g., using a mask value of 3 would let the process run on processors 0 and 1.Goldwin
You mean just using 3 as the second argument to that call? I suppose I can't even test this unless I'm running more than one thread in the process right? Currently I'm just sorting large int arrays. I'm not sure that would utilise multiple cores at all.Marilla
@junkie: Yes, just using 3 as the second argument is what I meant. Yes, to use more than one core (at a time) you'd need multiple threads (though that can be indirect, such as using a thread pool or an I/O completion port).Goldwin
Is DWORD_PTR 64-bit? What if I want to use processor number 65?Coda
@Trejkaz: Yes, it's 64 bits. Windows only currently supports up to 64 processors (at least per node--I'd have to check to be sure about NUMA and such).Goldwin
Yeah, OK... in the end, the answer turns out to be "there's a newer API if you want to use processor 65", as is typical of these APIs.Coda
E
3

As already mentioned, it's a bitmask. You may want to use the result of GetProcessAffinityMask, incase your process or system doesn't have access to all the cores already. Here's what I came up with.

#include <Windows.h>
#include <iostream>
using namespace std; 
 
int main () { 
 
    HANDLE process = GetCurrentProcess(); 
 
    DWORD_PTR processAffinityMask;
    DWORD_PTR systemAffinityMask;

    if (!GetProcessAffinityMask(process, &processAffinityMask, &systemAffinityMask))
        return -1;

    int core = 2; /* set this to the core you want your process to run on */
    DWORD_PTR mask=0x1;
    for (int bit=0, currentCore=1; bit < 64; bit++)
    {
        if (mask & processAffinityMask)
        {
            if (currentCore != core)
            {
                processAffinityMask &= ~mask;
            } else
            {
                if ( !(systemAffinityMask & mask) )
                {
                    cerr << "Core " << core << " not enabled in system." << endl;
                }
            }
            currentCore++;
        }
        mask = mask << 1;
    }

    BOOL success = SetProcessAffinityMask(process, processAffinityMask & systemAffinityMask); 
 
    cout << success << endl; 
 
    return 0; 
 
} 
Ezarras answered 9/10, 2012 at 16:5 Comment(4)
Thanks. Though I have the same problem with this that I did with jerry's answer. For some reason when I do some intensive computation after your code the process appears to spike on more than one core in task manager > performance tab. Somewhere between 2-4 cores are spiked at 100%. I feel there's something very wrong here. Any ideas?Marilla
Never mind. Ignore what I said. This was a red herring. I've explained further in response to jerry's post. Please have a look there.Marilla
your code does not use the value of systemAffinityMask?Anthropoid
@Anthropoid thanks for catching that - quick cleanup, untested.Ezarras

© 2022 - 2024 — McMap. All rights reserved.