使用代理类进行自我分析
给定一个接口
public interface IValueProvider
{
object GetValue(int index);
}
和 IValueProvider 实例的树结构,类似于数学表达式树。 我想在没有外部分析器的情况下测量运行时每个节点的 GetValue 方法所花费的时间。
GetValue 可以做任何我在设计时不知道的事情:从其他 IValueProvider 收集值、运行 IronPython 表达式,甚至是一个外部插件。 我想向用户提供有关节点计时的统计数据。
为此,我可以创建一个包装 IValueProvider 的代理类:
public class ValueProviderProfiler : IValueProvider
{
private IValueProvider valueProvider;
public object GetValue(int index)
{
// ... start measuring
try
{
return this.valuepProvider.GetValue(index);
}
finally
{
// ... stop measuring
}
}
}
测量节点所花费时间的最佳方法是什么,而不会因外部进程而造成失真,并且具有良好的准确性并尊重节点并行评估的事实?
仅使用 Stopwatch 类是行不通的,并且查看进程的处理器时间并不考虑 CPU 时间可能已在另一个节点上消耗的事实。
Given an interface
public interface IValueProvider
{
object GetValue(int index);
}
and a tree structure of instances of IValueProvider similar to a math expression tree.
I want to measure the time that is spent in the GetValue method of each node at runtime without an external profiler.
GetValue could do anything that i don't know at design time: Collecting values from other IValueProviders, running a IronPython expression or even be an external plugin. I want to present statistics about the node-timings to the user.
For this i can create a proxy class that wraps an IValueProvider:
public class ValueProviderProfiler : IValueProvider
{
private IValueProvider valueProvider;
public object GetValue(int index)
{
// ... start measuring
try
{
return this.valuepProvider.GetValue(index);
}
finally
{
// ... stop measuring
}
}
}
What is the best way to measure the time that is spend in a node without distortions caused by external processes, with good accuracy and respect to the fact that the nodes are evaluated in parallel?
Just using the Stopwatch class won't work and having a look at the process' processor time doesn't respect the fact that the cpu time could have been consumed on another node.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您尝试分析性能而不是从给定的方法开始,请获取像 Ants profiler 这样的实际配置文件,并查看真正的瓶颈在哪里。 很多时候,当您假设应用程序性能不佳的原因时,您最终会查找并优化所有错误的地方,并且浪费大量时间。
If you're trying to analyze performance instead of starting with a given method get an actual profile like Ants profiler and see where the real bottlenecks are. Many times when you assume why your application isn't being performant you end up looking and optimizing all of the wrong places and just waste a lot of time.
您没有说明您期望每个
GetValue
调用多快完成,因此很难给出任何明确的建议......对于需要一些毫秒的事情(磁盘访问、填充控件、网络传输等)我使用过
DateTime.Ticks.Now
。 它似乎工作得相当好,并且声称的每秒 10,000,000 次滴答的分辨率听起来相当不错。 (我怀疑它是否真的那么精确;我不知道它是由什么设施支持的。)我不知道有什么方法可以避免执行其他进程所带来的扭曲。 我通常只取运行我感兴趣的每个特定部分所花费的平均时间,在尽可能多的运行中进行平均(以消除由其他进程和任何计时器不准确引起的变化)。
(在本机代码中,为了分析执行时间不长的内容,我通过 RDTSC 指令使用 CPU 周期计数器。因此,如果您正在计时的内容对于其他计时器来说结束得太快了为了获得有用的读数,但完成得不够快,调用开销是一个问题,并且您不介意以 CPU 周期而不是任何标准时间单位来获取读数,可能值得编写一个返回的本地函数
UInt64
中的周期计数器值,但我不需要自己在托管代码中执行此操作...)You don't say how quickly you expect each
GetValue
call to finish, so it's hard to give any definite advice...For things that take some number of milliseconds (disk accesses, filling in controls, network transfers, etc.) I've used
DateTime.Ticks.Now
. It seems to work reasonably well, and the claimed resolution of 10,000,000 ticks per second sounds pretty good. (I doubt it's really that precise though; I don't know what facility it is backed by.)I'm not aware of any way of avoiding distortions introduced by execution of other processes. I usually just take the mean time spent running each particular section I'm interested in, averaged out over as many runs as possible (to smooth out variations caused by other processes and any timer inaccuracies).
(In native code, for profiling things that don't take long to execute, I use the CPU cycle counter via the
RDTSC
instruction. So if you're timing stuff that is over too soon for other timers to get a useful reading, but doesn't finish so quickly that call overhead is an issue, and you don't mind getting your readings in CPU cycles rather than any standard time units, it could be worth writing a little native function that returns the cycle counter value in aUInt64
. I haven't needed to do this in managed code myself though...)