Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C#中测量给定进程的CPU周期?_C#_Performance_Cpu Usage - Fatal编程技术网

如何在C#中测量给定进程的CPU周期?

如何在C#中测量给定进程的CPU周期?,c#,performance,cpu-usage,C#,Performance,Cpu Usage,我有一些不同的模型,它们使用不同的算法执行相同的任务。我想通过测量CPU周期来比较这些模型的性能(我尝试使用System.Diagnostics.StopWatch来计算滴答声,但结果不够准确) 我发现了一种通过使用p/Invoke测量CPU周期的方法,如下所示: IModel model; CodeTimer.Time(true, model.ToString(), totalTime, model.TimeStep); 上面的方法按N乘以方法model.TimeStep进行迭代。我注意到,

我有一些不同的模型,它们使用不同的算法执行相同的任务。我想通过测量CPU周期来比较这些模型的性能(我尝试使用
System.Diagnostics.StopWatch
来计算滴答声,但结果不够准确)

我发现了一种通过使用
p/Invoke
测量CPU周期的方法,如下所示:

IModel model;
CodeTimer.Time(true, model.ToString(), totalTime, model.TimeStep);
上面的方法按
N
乘以方法
model.TimeStep
进行迭代。我注意到,
CodeTimer.Time
的结果变化很大(至少有一个数量级,从
58 KCycles
890 KCycles
)。因此,如果我错了,请纠正我的错误,但由于
CodeTimer
类标记了进程前后的周期,因此它还可以统计在执行
model.TimeStep
方法(我要测量性能的方法)期间发生的任何其他进程(甚至是操作系统进程)所使用的周期

所以有两个问题:

  • 我的上述假设正确吗?如果是,那么我需要想出另一个解决方案来测量CPU周期,这就引出了我的主要问题:
  • 然后我想到了在不同的
    系统.Threading.Thread
    中迭代
    model.TimeStep()
    ,并使用。然而,当
    QueryProcessCycleTime
    接收到一个
    System.Threading.WaitHandle
    (或者一个
    IntPtr
    )作为输入时,我不知道如何告诉这个方法我想测量我刚刚创建的特定
    线程的周期。换句话说,我不知道如何将我创建的用于迭代模型的
    线程
    WaitHandle
    QueryProcessCycleTime
    组合在一起,尽管我读过一些使用
    WaitHandle
    的文章(我只是不能将所有内容混合在一起)

  • 我怎样才能做到这一点
  • 应该是这样的:

    class ModelSimulator
    {
        public Model1 model1 { get; private set; } // implements IModel
        public Model2 model2 { get; private set; } // implements IModel
    
    /* other methods */
    
        public void RunModel(object obj)
        {
            IModel model = (IModel)obj;
            Int32 t = model.maxTime;
            while (t-- > 0)
                model.TimeStep();
        }
    }
    
    main
    方法中,我执行以下操作:

    [DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern Boolean QueryProcessCycleTime(SafeWaitHandle processHandle, out UInt64 CycleTime);
    
    static void Main(string[] args)
    {
        ModelSimulator ms = new ModelSimulator();
        Thread thread = new Thread(ms.RunModel);
        thread.Start(ms.model1);
        // here I start the thread, but how can I use QueryProcessCycleTime to measure
        // the thread execution
    }
    

    附言:我的答案不是重复的,因为我需要一些更具体的答案,这是不存在的。。。我的问题可能是对这个问题的补充。

    正如@ShlomiBorovitz所建议的,可以使用来识别运行进程的
    线程。可能的解决方案是对模型进行非常简单的修改。所需的修改可在本答案末尾找到。我添加了一个名为
    PerformanceStatus
    的类,以便在用于测量性能的
    CodeTimer.Time()
    方法的结果中获得级别0、1和2的垃圾收集量。因此,我们还可以知道垃圾收集器在这个过程中是否收集了任何东西

    然后您只需要像这样使用它:

    ModelSimulator nm = new ModelSimulator();
    CodeTimer c = new CodeTimer(nm.RunModel, model); // model implements IModel
    UInt64 time = c.Time().CPUCycles;
    Console.WriteLine("{0:0.000e+000} KCy", (Double)time / 1000.0D);
    
    问题中给出了类
    ModelSimulator
    ,该类带有一个方法
    ModelSimulator.RunModel(IModel model)
    ,该方法接收类型为
    IModel
    的对象

    下面是衡量性能所需的
    CodeTimer.cs

    public sealed class CycleTime
    {
        private Boolean m_trackingThreadTime;
        private SafeWaitHandle m_handle;
        private UInt64 m_startCycleTime;
    
        private CycleTime(Boolean trackingThreadTime, SafeWaitHandle handle)
        {
            m_trackingThreadTime = trackingThreadTime;
            m_handle = handle;
            m_startCycleTime = m_trackingThreadTime ? Thread() : Process(m_handle);
        }
    
        [CLSCompliant(false)]
        public UInt64 Elapsed()
        {
            UInt64 now = m_trackingThreadTime ? Thread(/*m_handle*/) : Process(m_handle);
            return now - m_startCycleTime;
        }
    
        public static CycleTime StartThread(SafeWaitHandle threadHandle)
        {
            return new CycleTime(true, threadHandle);
        }
    
        public static CycleTime StartProcess(SafeWaitHandle processHandle)
        {
            return new CycleTime(false, processHandle);
        }
    
        public static UInt64 Thread(IntPtr threadHandle)
        {
            UInt64 cycleTime;
            if (!QueryThreadCycleTime(threadHandle, out cycleTime))
                throw new Win32Exception();
            return cycleTime;
        }
    
        /// <summary>
        /// Retrieves the cycle time for the specified thread.
        /// </summary>
        /// <param name="threadHandle">Identifies the thread whose cycle time you'd like to obtain.</param>
        /// <returns>The thread's cycle time.</returns>
        [CLSCompliant(false)]
        public static UInt64 Thread(SafeWaitHandle threadHandle)
        {
            UInt64 cycleTime;
            if (!QueryThreadCycleTime(threadHandle, out cycleTime))
                throw new Win32Exception();
            return cycleTime;
        }
    
        [CLSCompliant(false)]
        public static UInt64 Thread()
        {
            UInt64 cycleTime;
            if (!QueryThreadCycleTime((IntPtr)(-2), out cycleTime))
                throw new Win32Exception();
            return cycleTime;
        }
    
        /// <summary>
        /// Retrieves the sum of the cycle time of all threads of the specified process.
        /// </summary>
        /// <param name="processHandle">Identifies the process whose threads' cycles times you'd like to obtain.</param>
        /// <returns>The process' cycle time.</returns>
        [CLSCompliant(false)]
        public static UInt64 Process(SafeWaitHandle processHandle)
        {
            UInt64 cycleTime;
            if (!QueryProcessCycleTime(processHandle, out cycleTime))
                throw new Win32Exception();
            return cycleTime;
        }
    
        /// <summary>
        /// Retrieves the cycle time for the idle thread of each processor in the system.
        /// </summary>
        /// <returns>The number of CPU clock cycles used by each idle thread.</returns>
        [CLSCompliant(false)]
        public static UInt64[] IdleProcessors()
        {
            Int32 byteCount = Environment.ProcessorCount;
            UInt64[] cycleTimes = new UInt64[byteCount];
            byteCount *= 8;   // Size of UInt64
            if (!QueryIdleProcessorCycleTime(ref byteCount, cycleTimes))
                throw new Win32Exception();
            return cycleTimes;
        }
    
        [DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern Boolean QueryThreadCycleTime(IntPtr threadHandle, out UInt64 CycleTime);
    
        [DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern Boolean QueryThreadCycleTime(SafeWaitHandle threadHandle, out UInt64 CycleTime);
    
        [DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern Boolean QueryProcessCycleTime(SafeWaitHandle processHandle, out UInt64 CycleTime);
    
        [DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern Boolean QueryIdleProcessorCycleTime(ref Int32 byteCount, UInt64[] CycleTimes);
    
        [DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
        public static extern IntPtr GetCurrentThread();
    }
    
    public sealed class CodeTimer //: IDisposable
    {
        private Int32 m_collectionCount0;
        private Int32 m_collectionCount1;
        private Int32 m_collectionCount2;
    
        private Thread m_thread;
        private IModel m_model;
        private Action<IModel> m_performanceMethod;
    
        private UInt64 outThreadCycles;
    
        public CodeTimer(Action<IModel> perfMethod, IModel model)
        {
            PrepareForOperation();
    
            m_performanceMethod = perfMethod;
            m_model = model;
            m_thread = new Thread(PerformanceTest);
        }
    
        private void PerformanceTest()
        {
            PrepareForOperation();
            IntPtr p = CycleTime.GetCurrentThread();
            UInt64 t = CycleTime.Thread(p);
            m_performanceMethod(m_model);
            outThreadCycles = CycleTime.Thread(p) - t;
        }
    
        public PerformanceStatus Time()
        {
            m_thread.Start();
            m_thread.Join();
            return new PerformanceStatus(GC.CollectionCount(0) - m_collectionCount0, GC.CollectionCount(1) - m_collectionCount1, GC.CollectionCount(2) - m_collectionCount2, outThreadCycles);
        }
    
        private void PrepareForOperation()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            m_collectionCount0 = GC.CollectionCount(0);
            m_collectionCount1 = GC.CollectionCount(1);
            m_collectionCount2 = GC.CollectionCount(2);
        }
    }
    
    public class PerformanceStatus
    {
        public Int32 GCCount1;
        public Int32 GCCount2;
        public Int32 GCCount3;
        public UInt64 CPUCycles;
        public PerformanceStatus(Int32 gc1, Int32 gc2, Int32 gc3, UInt64 cpuCycles)
        {
            this.GCCount1 = gc1;
            this.GCCount2 = gc2;
            this.GCCount3 = gc3;
            this.CPUCycles = cpuCycles;
        }
    }
    
    公共密封类周期时间
    {
    私有布尔m_trackingThreadTime;
    私人保险箱手柄Mu手柄;
    私有UInt64 m_开始周期;
    私有CycleTime(布尔跟踪线程时间,SafeWaitHandle句柄)
    {
    m_trackingThreadTime=trackingThreadTime;
    m_handle=手柄;
    m_startCycleTime=m_trackingThreadTime?Thread():进程(m_句柄);
    }
    [CLSCompliant(false)]
    公共UInt64已用()
    {
    UInt64 now=m_trackingThreadTime?Thread(/*m_handle*/):进程(m_handle);
    立即返回-m_startCycleTime;
    }
    公共静态CycleTime StartThread(SafeWaitHandle threadHandle)
    {
    返回新的CycleTime(true,threadHandle);
    }
    公共静态CycleTime StartProcess(SafeWaitHandle processHandle)
    {
    返回新的CycleTime(false,processHandle);
    }
    公共静态UInt64线程(IntPtr threadHandle)
    {
    UInt64周期时间;
    如果(!QueryThreadCycleTime(threadHandle,out cycleTime))
    抛出新的Win32Exception();
    返回周期时间;
    }
    /// 
    ///检索指定线程的周期时间。
    /// 
    ///标识要获取其周期时间的线程。
    ///线程的循环时间。
    [CLSCompliant(false)]
    公共静态UInt64线程(SafeWaitHandle threadHandle)
    {
    UInt64周期时间;
    如果(!QueryThreadCycleTime(threadHandle,out cycleTime))
    抛出新的Win32Exception();
    返回周期时间;
    }
    [CLSCompliant(false)]
    公共静态UInt64线程()
    {
    UInt64周期时间;
    if(!QueryThreadCycleTime((IntPtr)(-2),out cycleTime))
    抛出新的Win32Exception();
    返回周期时间;
    }
    /// 
    ///检索指定进程的所有线程的周期时间之和。
    /// 
    ///标识要获取其线程周期时间的进程。
    ///进程的周期时间。
    [CLSCompliant(false)]
    公共静态UInt64进程(SafeWaitHandle进程句柄)
    {
    UInt64周期时间;
    if(!QueryProcessCycleTime(processHandle,out cycleTime))
    抛出新的Win32Exception();
    返回周期时间;
    }
    /// 
    ///检索系统中每个处理器的空闲线程的周期时间。
    /// 
    ///每个空闲线程使用的CPU时钟周期数。
    [CLSCompliant(false)]
    公共静态UInt64[]IDleProcessor()
    {
    Int32字节计数=Environment.ProcessorCount;
    UInt64[]周期时间=新UInt64[字节计数];
    字节计数*=8;//UInt64的大小
    if(!QueryIdleProcessorCycleTime(参考字节计数,Cycletime))
    抛出新的Win32Exception();
    返回周期;
    }
    [DllImport(“内核32”,ExactSpelling=true,SetLastError=true)]
    [返回:Marshallas(UnmanagedType.Bool)]
    私有静态外部布尔QueryThreadCycl