gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 15:53:01 25 4
gpt4 key购买 nike

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

我找到了一个 class,它使用 P/Invoke 测量 CPU 周期,如下所示:

IModel model;
CodeTimer.Time(true, model.ToString(), totalTime, model.TimeStep);

上述方法迭代N 次方法model.TimeStep。我注意到 CodeTimer.Time 的结果差异很大(至少相差一个数量级,从 58 KCycles890 KCycles)。因此,如果我错了,请纠正我,但是由于 CodeTimer 类标记了进程前后的周期,它还可以计算在执行期间发生的任何其他进程(甚至操作系统进程)使用的周期model.TimeStep 方法(我想测量性能的方法)。

所以两个问题:

  1. 我的上述假设是否正确?如果是,那么我需要想出另一种解决方案来测量 CPU 周期,这引出了我的主要问题:

然后我想到了在不同的 System.Threading.Thread 中迭代 model.TimeStep() 并使用 QueryProcessCycleTime 测量给定线程的周期。但是,由于 QueryProcessCycleTime 接收到一个 System.Threading.WaitHandle(或一个 IntPtr)作为输入,我不知道如何告诉它我想测量我刚刚创建的特定 Thread 周期的方法。换句话说,我不知道如何将我创建的用于迭代模型的 threadWaitHandleQueryProcessCycleTime 放在一起,尽管我已经阅读了一些关于使用 WaitHandleexamples(我只是不能将所有内容混合在一起)。

  1. 我怎样才能做到这一点?

应该是这样的:

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
}

PS:我的不是 this question 的副本,因为我需要一些更具体的答案,但那里没有...我的问题可以作为该问题的补充。

最佳答案

正如@ShlomiBorovitz 所建议的,可以使用 GetCurrentThread() 为了识别Thread这是运行的过程。可能的解决方案是在 CodeTimer.cs 中进行非常简单的修改.可以在此答案的末尾找到所需的修改。我添加了一个名为 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;
}
}

关于c# - 如何测量 C# 中给定进程的 CPU 周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24984922/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com