Nar Jovan
Nar Jovan

Reputation: 204

Reduce CPU usage asp net mvc

I want my Process does not cross 70% of CPU usage. And i found solution in here: How can I programmatically limit my program's CPU usage to below 70%? . Here is the class I am trying to use from that link:

public class ProcessManager
    {
        [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)
        }

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

        [DllImport("kernel32.dll")]
        static extern uint SuspendThread(IntPtr hThread);

        [DllImport("kernel32.dll")]
        static extern int ResumeThread(IntPtr hThread);

        [DllImport("kernel32.dll")]
        static extern int CloseHandle(IntPtr hThread);
        public static void ThrottleProcess(int processId, double limit)
        {
            var process = Process.GetProcessById(processId);
            var processName = process.ProcessName;

            var p = new PerformanceCounter("Process", "% Processor Time", processName);

            while (true)
            {
                var interval = 100;
                Thread.Sleep(interval);

                var currentUsage = p.NextValue() / Environment.ProcessorCount;

                if (currentUsage < limit) continue; // Infinant loop ?

                var suspensionTime = (currentUsage-limit) / currentUsage * interval;
                SuspendProcess(processId);
                Thread.Sleep((int)suspensionTime);
                ResumeProcess(processId);
            }
        }

        private static void SuspendProcess(int pid)
        {
            var process = Process.GetProcessById(pid);

            if (process.ProcessName == string.Empty)
                return;

            foreach (ProcessThread pT in process.Threads)
            {
                IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);

                if (pOpenThread == IntPtr.Zero)
                {
                    continue;
                }

                SuspendThread(pOpenThread);

                CloseHandle(pOpenThread);
            }
        }

        private static void ResumeProcess(int pid)
        {
            var process = Process.GetProcessById(pid);

            if (process.ProcessName == string.Empty)
                return;

            foreach (ProcessThread pT in process.Threads)
            {
                IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);

                if (pOpenThread == IntPtr.Zero)
                {
                    continue;
                }

                var suspendCount = 0;

                do
                {
                    suspendCount = ResumeThread(pOpenThread);
                } while (suspendCount > 0);

                CloseHandle(pOpenThread);
            }
        }
    }

The author of this code under his post left the comment that says, use ThrottleProcess after Process.Start(). I did it, but it seems like right after Process has started, it gets inside ThrottleProcess and get stucks inside While loop. And i can't figure out what to do with it, maybe it should run method asynchronously? Like Process should run independently of Throttle isn't it? Here's my Process method:

private string startProcess(string fileName, string args)
        {
            // Create Process manager
            var ProcessManager = new ProcessManager();

            string result = "";

            Process p;

            ProcessStartInfo psi = new ProcessStartInfo();

            psi.FileName = fileName;

            psi.Arguments = args;

            psi.WorkingDirectory = "...\\TempFolder";

            psi.UseShellExecute = false;

            psi.CreateNoWindow = true;

            psi.StandardOutputEncoding = System.Text.Encoding.UTF8;

            psi.RedirectStandardInput = true;

            psi.RedirectStandardOutput = true;

            psi.RedirectStandardError = true;

            p = Process.Start(psi);

            // After it gots here, process get stuck inside while loop
            ProcessManager.ThrottleProcess(p.Id , 1);

            try
            {
                string output = p.StandardOutput.ReadToEnd();

                p.WaitForExit();

                if (p.ExitCode != 0)
                    throw new Exception("Program returned with error code " + p.ExitCode);

                result = output.ToString();
            }
            catch (Exception ex)
            {
                result = ex.ToString();
            }
            finally
            {
                p.Close();
                p.Dispose();
            }

            return result;
        }

Upvotes: 1

Views: 431

Answers (1)

Nar Jovan
Nar Jovan

Reputation: 204

Turns out you can set affinity for a process. Affinity it is the quantity of cores that your process will use. The only thing you need, is just to add for your Process method this string:

Process p = new Process();
p.ProcessorAffinity = (IntPtr)1; // or any number (your cores)

It decreased CPU overload to minimum for my case.

Upvotes: 1

Related Questions