Can you limit the CPU usage on a .NET Process Object?

前端 未结 2 2003
失恋的感觉
失恋的感觉 2020-12-29 11:54

An application I\'m contributing to fires up a component written in C.

The C process does some pretty heavy crunching and if your not careful can really hammer your

相关标签:
2条回答
  • 2020-12-29 12:25

    I had the same problem. I solved it by using SetInformationJobObject Kernel32 Win Api and JOBOBJECT_CPU_RATE_CONTROL_INFORMATION struct.

    My bigger problem was to represent this structure in c# (uses "union"). Hopefully, I found a "mono" description of this structure.

    [StructLayout(LayoutKind.Explicit)]
    //[CLSCompliant(false)]
    struct JOBOBJECT_CPU_RATE_CONTROL_INFORMATION
    {
        [FieldOffset(0)]
        public UInt32 ControlFlags;
        [FieldOffset(4)]
        public UInt32 CpuRate;
        [FieldOffset(4)]
        public UInt32 Weight;
    }
    

    To activate the Cpu limitation :

    ControlFlags = 0x00000001 | 0x00000004;
    CpuRate = percent of max usage  * 100 (ex 50 * 100 for a 50% limit)
    

    The sample below is fully functional.

    I hope that's help.

    Kind Regards

    -Thierry-

    [DllImport("kernel32.dll", EntryPoint = "CreateJobObjectW", CharSet = CharSet.Unicode)]
    public static extern IntPtr CreateJobObject(SecurityAttributes JobAttributes, string lpName);
    
    [DllImport("kernel32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);
    
    [DllImport("kernel32.dll")]
    static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
    
    public class SecurityAttributes
    {
    
        public int nLength; 
        public IntPtr pSecurityDescriptor; 
        public bool bInheritHandle;
    
        public SecurityAttributes()
        {
            this.bInheritHandle = true;
            this.nLength = 0;
            this.pSecurityDescriptor = IntPtr.Zero;
        }
    }
    
    public enum JOBOBJECTINFOCLASS
    {
        JobObjectAssociateCompletionPortInformation = 7,
        JobObjectBasicLimitInformation = 2,
        JobObjectBasicUIRestrictions = 4,
        JobObjectEndOfJobTimeInformation = 6,
        JobObjectExtendedLimitInformation = 9,
        JobObjectSecurityLimitInformation = 5,
        JobObjectCpuRateControlInformation = 15
    }
    
    [StructLayout(LayoutKind.Explicit)]
    //[CLSCompliant(false)]
    struct JOBOBJECT_CPU_RATE_CONTROL_INFORMATION
    {
        [FieldOffset(0)]
        public UInt32 ControlFlags;
        [FieldOffset(4)]
        public UInt32 CpuRate;
        [FieldOffset(4)]
        public UInt32 Weight;
    }
    
    public enum CpuFlags
    {
        JOB_OBJECT_CPU_RATE_CONTROL_ENABLE = 0x00000001,
        JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED = 0x00000002,
        JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP = 0x00000004
    }
    
    /// <summary>
    /// Launch the legacy application with some options set.
    /// </summary>
    static void DoExecuteProgramm()
    {
        // prepare the process to execute
        var startInfo = new ProcessStartInfo();
        . . . . . 
        // Start the process
        var process = Process.Start(startInfo);
    
        //Limit the CPU usage to 45%
        var jobHandle = CreateJobObject(null, null);
        AssignProcessToJobObject(jobHandle, process.Handle);
        var cpuLimits = new JOBOBJECT_CPU_RATE_CONTROL_INFORMATION();
        cpuLimits.ControlFlags = (UInt32)(CpuFlags.JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | CpuFlags.JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP);
        cpuLimits.CpuRate = 45 * 100; // Limit CPu usage to 45%
        var pointerToJobCpuLimits = Marshal.AllocHGlobal(Marshal.SizeOf(cpuLimits));
        Marshal.StructureToPtr(cpuLimits, pointerToJobCpuLimits, false);
        if (!SetInformationJobObject(jobHandle, JOBOBJECTINFOCLASS.JobObjectCpuRateControlInformation, pointerToJobCpuLimits, (uint)Marshal.SizeOf(cpuLimits)))
        {
            Console.WriteLine("Error !");
        }
    }
    
    0 讨论(0)
  • 2020-12-29 12:40

    Not in Windows. You can lower the process priority though, which will reduce the likelihood that the problematic process will be scheduled on the CPU and interfere with other (presumably higher priority) applications. For instance, from http://dotnet-concepts-queries-interviews.blogspot.com/2007/05/how-to-set-process-priority-in-net.html:

    Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal;
    

    Keep in mind, if you don't have anything else running on the box, you probably want this process to consume all of the available CPU.

    You can also set the CPU affinity if it is on a multi-processor box, limiting the processing to certain cores and leaving others free for other applications. Generally the OS does a good job of scheduling application threads though, so setting the process priority is likely to have a better overall result. See How Can I Set Processor Affinity in .NET?

    0 讨论(0)
提交回复
热议问题