Skip to content

Instantly share code, notes, and snippets.

@adamsitnik
Created November 24, 2021 07:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamsitnik/3e8d1e3cb50c7b517184edb23fb6547c to your computer and use it in GitHub Desktop.
Save adamsitnik/3e8d1e3cb50c7b517184edb23fb6547c to your computer and use it in GitHub Desktop.
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace CpuSet
{
internal class Program
{
const int bufferSize = 1024;
const int TRUE = 1;
const int ERROR_INSUFFICIENT_BUFFER = 122;
static unsafe void Main(string[] args)
{
using Process current = Process.GetCurrentProcess();
PrintCpuSets(current.SafeHandle); // Print current
uint[] cputSetIds = GetCpuSetIds(current.SafeHandle); // Get CPU set IDs (they are not indexed from 0 or 1)
fixed(uint* pinnedIds = cputSetIds)
{
if (HasFailed(SetProcessDefaultCpuSets(current.SafeHandle, pinnedIds, (uint)cputSetIds.Length), nameof(SetProcessDefaultCpuSets)))
{
return;
}
}
PrintCpuSets(current.SafeHandle);
if (HasFailed(SetProcessDefaultCpuSets(current.SafeHandle, (uint*)IntPtr.Zero, 0), nameof(SetProcessDefaultCpuSets))) // clear out any assignment
{
return;
}
PrintCpuSets(current.SafeHandle);
}
static unsafe uint[] GetCpuSetIds(SafeProcessHandle processHandle)
{
if (HasFailed(GetSystemCpuSetInformation(IntPtr.Zero.ToPointer(), 0L, out ulong ReturnedLength, processHandle, 0L), nameof(GetSystemCpuSetInformation),
ERROR_INSUFFICIENT_BUFFER)) // "If the Information buffer was NULL or not large enough, the error code ERROR_INSUFFICIENT_BUFFER is returned"
{
Environment.Exit(0);
}
void* bufferPtr = stackalloc byte[(int)ReturnedLength];
if (HasFailed(GetSystemCpuSetInformation(bufferPtr, ReturnedLength, out ulong _, processHandle, 0L), nameof(GetSystemCpuSetInformation)))
{
Environment.Exit(0);
}
List<uint> ids = new ();
ReadOnlySpan<byte> buffer = new ReadOnlySpan<byte>(bufferPtr, (int)ReturnedLength);
do
{
SYSTEM_CPU_SET_INFORMATION info = MemoryMarshal.Read<SYSTEM_CPU_SET_INFORMATION>(buffer);
ids.Add(info.Id);
buffer = buffer.Slice((int)info.Size);
} while (!buffer.IsEmpty);
return ids.ToArray();
}
static unsafe void PrintCpuSets(SafeProcessHandle processHandle)
{
uint* buffer = stackalloc uint[bufferSize];
if (HasFailed(GetProcessDefaultCpuSets(processHandle, buffer, bufferSize, out uint RequiredIdCount), nameof(GetProcessDefaultCpuSets)))
{
return;
}
if (RequiredIdCount == 0)
{
Console.WriteLine("If no default CPU Sets are set for a given process, then the RequiredIdCount is set to 0 and the function succeeds.");
return;
}
Console.WriteLine($"The ids: {string.Join(", ", new Span<uint>(buffer, (int)RequiredIdCount).ToArray())}");
}
static bool HasFailed(int returnedValue, string syscallName, int expectedErrorCode = -1)
{
if (returnedValue != TRUE)
{
int errorCode = Marshal.GetLastWin32Error();
if (errorCode != expectedErrorCode)
{
Console.WriteLine($"{syscallName} failed with {errorCode/*:X*/}");
return true;
}
}
return false;
}
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern unsafe int GetSystemCpuSetInformation(void* Information, ulong BufferLength, out ulong ReturnedLength, SafeProcessHandle Process, ulong Flags);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern unsafe int GetProcessDefaultCpuSets(SafeProcessHandle Process, uint* CpuSetIds, uint CpuSetIdCount, out uint RequiredIdCount);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern unsafe int SetProcessDefaultCpuSets(SafeProcessHandle Process, uint* CpuSetIds, uint CpuSetIdCount);
#pragma warning disable CS0649 // unused fields
internal struct SYSTEM_CPU_SET_INFORMATION
{
internal uint Size;
internal uint Type;
internal uint Id;
// the structure defines more fields, but they were not needed
}
#pragma warning restore CS0649
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment