在测量性能时是不是需要防止抢占
Posted
技术标签:
【中文标题】在测量性能时是不是需要防止抢占【英文标题】:Do I need to prevent preemption while measuring performance在测量性能时是否需要防止抢占 【发布时间】:2017-03-12 12:47:38 【问题描述】:我想在 Windows 中使用 QueryPerformanceCounter 来测量代码块的性能。我想知道的是在不同的运行之间我是否可以做一些事情来对相同的数据进行相同的测量(我想测量不同排序算法在包含 pod 或一些自定义对象的不同大小的数组上的性能)。我知道当前进程可能会因为中断或 I/O 操作而中断执行。我没有做任何 I/O,所以只有中断可能会影响我的测量,我假设内核也有一些时间框架允许我的进程运行,所以我认为这也会安排我的 proc。
人们如何通过测量特定代码的执行时间来进行准确的测量?
【问题讨论】:
做一百万次测量,然后得到平均值。真的不建议在现代系统上关闭抢占。 关闭抢占基本上是个好主意。你找到实现这一目标的方法了吗?我会说这是不可能的,所以你必须忍受它。抢占式测量是非常现实的,因为那是您的客户所拥有的。 嗨,谢谢你的 cmets,不,我不知道禁用抢占,我实际上希望有某种计数器只在我的代码运行时递增。 如果代码很短,可以通过忽略异常值来过滤掉抢占开销。如果代码很长,则在统计上没有显着差异。因此,使用抢占运行通常很好,除了“中间长度”,抢占会增加“明显但难以过滤”的开销(在这种情况下,只需迭代更多) 您实际上想要测量什么,为什么?中断是不可避免的开销,如果您想测量代码的实际性能(而不是假设在没有中断的世界中的性能),在我看来您需要包括它们。 【参考方案1】:时间测量很棘手,因为您需要找出算法变慢的原因。这取决于输入数据(例如预排序数据,请参阅Why is it faster to process a sorted array than an unsorted array?)或数据集大小(适合 L1、L2、L3 缓存,请参阅http://igoro.com/archive/gallery-of-processor-cache-effects/)。
这会极大地影响您的测量时间。 测量顺序也可以发挥关键作用。如果您在循环中执行排序日志并且它们中的每一个都分配一些内存,那么第一个测试很可能会丢失。不是因为算法较差,而是当您第一次访问新分配的内存时,它将软故障进入您的进程工作集。释放内存后,堆分配器将返回池化内存,这将具有完全不同的访问性能。如果您对更大(许多 MB)的数组进行排序,这将变得非常明显。
以下是来自不同线程的 2 GB 数组在第一次和第二次打印时的触摸时间。内存的每一页(4KB)只被触摸一次。
Threads Size_MB Time_ms us/Page MB/s Scenario
1 2000 355 0.693 5634 Touch 1
1 2000 11 0.021 N.a. Touch 2
2 2000 276 0.539 7246 Touch 1
2 2000 12 0.023 N.a. Touch 2
3 2000 274 0.535 7299 Touch 1
3 2000 13 0.025 N.a. Touch 2
4 2000 288 0.563 6944 Touch 1
4 2000 11 0.021 N.a. Touch 2
// Touch is from the compiler point of view a nop operation with no observable side effect
// This is true from a pure data content point of view but performance wise there is a huge
// difference. Turn optimizations off to prevent the compiler to outsmart us.
#pragma optimize( "", off )
void Program::Touch(void *p, size_t N)
char *pB = (char *)p;
char tmp;
for (size_t i = 0; i < N; i += 4096)
tmp = pB[i];
#pragma optimize("", on)
要真正判断算法的性能,仅执行时间测量是不够的,但您需要一个分析器(例如,免费的 Windows 性能工具包,英特尔的 VTune(非免费))以确保您测量了正确的事物并且不是完全不同的东西。
【讨论】:
【参考方案2】:刚刚与 Andrei Alexandrescu 参加了关于 Fastware 的会议,他正在解决这个确切的问题,即如何测量速度。显然获得平均值是一个坏主意,但是,多次测量是个好主意。因此,考虑到这一点,您测量了一百万次并记住最小的测量值,因为实际上那是您获得最少噪音的地方。
平均值很糟糕,因为您实际上在测量的实际速度上增加了更多的噪声权重(这些不是您在评估代码速度时应该考虑的唯一因素,但这是一个好的开始,还有更多关于代码将在哪里执行的可怕事情,以及代码在一个内核上开始执行并在另一个内核上完成所带来的开销,但这是另一回事,我认为它不适用于我的类型)。
一个很好的笑话是:如果你把比尔盖茨放在一辆公共汽车上,平均而言,公共汽车上的每个人都是百万富翁 :))
干杯并感谢所有提供意见的人。
【讨论】:
以上是关于在测量性能时是不是需要防止抢占的主要内容,如果未能解决你的问题,请参考以下文章
NSInternalInconsistencyException Performance Metrics 在 Xcode 中测量性能时必须提供 10 次测量