.netpowershellcpu-cores

PowerShell, setting affinity to CPU 63 (the 64th logical processor)


So it turns out that PowerShell doesn't seem to have a native way to switch "Processor Groups" when you have more than 64 logical processors.

Okay, but even without processor groups I encountered a problem when I wanted to set the affinity of a process to CPU 63 (i.e. the 64th logical processor) with .ProcessorAffinity, which is the last logical processor that can fit into a "normal" system without having to use processor groups.

Maybe I'm missing something, but this gives me an integer overflow, resp. it cannot convert the values to IntPtr.

The affinity value for CPU 63 would be 2^63, which is 9223372036854775808. The max value for a signed 64 bit integer [Int64] however is 9223372036854775807, so 1 less. And I cannot pass [UInt64] or [BigInt] to .ProcessorAffinity, as it will fail converting to IntPtr (even if using small numbers).

As an example:

> (Get-Process 'notepad').ProcessorAffinity = [UInt64] [Math]::Pow(2, 63)


Exception setting "ProcessorAffinity": "Cannot convert the "9223372036854775808" value of type "System.UInt64" to type
"System.IntPtr"."
At line:1 char:1
+ (Get-Process 'notepad').ProcessorAffinity = [UInt64] [Math]::Pow(2, 6 ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenSetting

And even executing (Get-Process 'notepad').ProcessorAffinity = [UInt64] 3 does not work, with the same error.

Removing the type cast to [UInt64] doesn't work either (similar error message, just with [Double] this time), and casting to [Int64] instead causes an "Arithmetic operation resulted in an overflow." error. Of course, since it's larger than its maximum value.

So then, is there a way to set the processor affinity with PowerShell's native .ProcessorAffinity property to CPU 63 at all (or a combination of CPU 63 with any other CPU, which would certainly exceed the 64 bit integer limit)?


Solution

  • The thing to remember is that the Processor Affinity is a bitmask, and not a number (See Processor Affinity).

    Indeed, the max value is: 9223372036854775807

    PS C:\> [System.IntPtr]::MaxValue
    9223372036854775807
    

    Which works out to a bit value of:

    PS C:\> [System.Convert]::ToString('9223372036854775807',2)
    111111111111111111111111111111111111111111111111111111111111111
    

    This has been correctly pointed out (wink wink) that this is only 63 bits. But we want the 64th bit set. e.g.:

    1000000000000000000000000000000000000000000000000000000000000000
    

    or

    9223372036854775807 + 1 = 9223372036854775808
    

    Yes, we can store this value in an Unsigned Int, but the decimal "number" is bigger than the MaxValue of 9223372036854775807, and so, yes, as you found out, Unsigned Int's won't work.

    But, remember, the way that Integers work is that 64th bit is the sign value, so we were thinking about it wrong. It's not 9223372036854775807 + 1 that we want, it's actually counter-intuitively, a negative value that we want:

    PS C:\> [System.Convert]::ToInt64('1000000000000000000000000000000000000000000000000000000000000000',2)
    -9223372036854775808
    

    And we can verify that this negative number is a valid value because the minimum value for IntPtr is not 0 it is -9223372036854775808:

    PS C:\> [System.IntPtr]::MinValue
    -9223372036854775808
    

    And we can set it to that negative value:

    (Get-Process 'notepad').ProcessorAffinity = -9223372036854775808