lowleveldesign / process-governor

This application allows you to put various limits on Windows processes.
MIT License
626 stars 62 forks source link

The question isn't about procgov. #48

Closed Aspector1 closed 2 years ago

Aspector1 commented 2 years ago

The question isn't about procgov.

Guys, can you help me? Because you're the only people I know who are so fking good at working with Windows processes.

I'm working on a program that needs to set Affinity for each thread in a process according to the value in IdealProcessor. But the SetThreadAffinityMask just seems to be ignored.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace ThreadAffinity
{
    class Program
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);

        [DllImport("kernel32.dll")]
        static extern bool SetThreadAffinityMask(IntPtr hThread, IntPtr dwThreadAffinityMask);

        [DllImport("kernel32.dll")]
        static extern bool GetThreadIdealProcessorEx(IntPtr hThread, ref PROCESSOR_NUMBER lpIdealProcessor);

        [DllImport("kernel32.dll")]
        static extern bool CloseHandle(IntPtr hObject);

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESSOR_NUMBER
        {
            public ushort Group;
            public byte Number;
            public byte Reserved;
        }

        [Flags]
        public enum ThreadAccess : int
        {
            TERMINATE = (0x0001),
            SUSPEND_RESUME = (0x0002),
            GET_CONTEXT = (0x0008),
            SET_CONTEXT = (0x0010),
            SET_INFORMATION = (0x0020),
            QUERY_INFORMATION = (0x0040),
            SET_THREAD_TOKEN = (0x0080),
            IMPERSONATE = (0x0100),
            DIRECT_IMPERSONATION = (0x0200),
            THREAD_ALL_ACCESS = (0x1F03FF)
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Enter process id:");
            int processId = Convert.ToInt32(Console.ReadLine());
            Process process = Process.GetProcessById(processId);
            foreach (ProcessThread thread in process.Threads)
            {
                IntPtr hThread = OpenThread(ThreadAccess.QUERY_INFORMATION, false, (uint)thread.Id);
                PROCESSOR_NUMBER processorNumber = new PROCESSOR_NUMBER();
                GetThreadIdealProcessorEx(hThread, ref processorNumber);
                Console.WriteLine("Thread {0} ideal processor is {1}", thread.Id, processorNumber.Number);
                SetThreadAffinityMask(hThread, (IntPtr)(processorNumber.Number));
                CloseHandle(hThread);
            }
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}

I can''t deny that with 99% probability I'm an idiot, so I came here to ask for your help.

upd1: The program properly detects idealprocessor, but doesn't set affinity to the thread.

lowleveldesign commented 2 years ago

The affinity mask is a binary mask and you are sending a processor number as its value. You need to convert the processor number to a CPU mask. Something like:

        ulong mask = 1;
        for (int i = 0; i < processorNumber.Number; i++)
        {
            mask <<= 1;
        }

The thread affinity mask is always a subset of the process affinity mask. If you set any limits on the process level, you will need to adjust them in the thread mask. Additionally, this approach will work for machines with less than 64 cores. If your server/desktop has more then you need to take care of processor group.

Aspector1 commented 2 years ago
 static void Main(string[] args)
        {
            Console.WriteLine("Enter process id:");
            int processId = Convert.ToInt32(Console.ReadLine());
            Process process = Process.GetProcessById(processId);
            foreach (ProcessThread thread in process.Threads)
            {
                IntPtr hThread = OpenThread(ThreadAccess.QUERY_INFORMATION, false, (uint)thread.Id);
                PROCESSOR_NUMBER processorNumber = new PROCESSOR_NUMBER();
                GetThreadIdealProcessorEx(hThread, ref processorNumber);
                ulong mask = 1;
                for (int i = 0; i < processorNumber.Number; i++)
                {
                    mask <<= 1;
                }
                Console.WriteLine("Thread {0} ideal processor is {1}", thread.Id, processorNumber.Number);
                SetThreadAffinityMask(hThread, (IntPtr)mask);
                CloseHandle(hThread);

Why am I so dumb? ^ Btw, can't I just write SetThreadAffinityMask(hThread, (IntPtr)(1 << processorNumber.Number)) ? upd1: it doesn't work.

lowleveldesign commented 2 years ago

ah, yeah, (IntPtr)(1 << processorNumber.Number) looks much better :)