|
本帖最后由 hanguokai 于 2013-4-2 22:58 编辑
原文:http://han.guokai.blog.163.com/b ... 182712013215637623/
我们通常需要对代码或核心算法做性能测试。性能测试的概念非常简单:执行要测试的代码,测量其执行时间(一般是多次测试的平均值)。性能测试真正的难点是避开各种干扰因素,而这些干扰因素可能非常复杂。除了自身代码,还可能涉及硬件、底层系统、语言、库的实现等各个方面。Dart 中的性能测试和其它语言并没有什么不同,只不过需要注意几点。
1. 热身
Dart 语言的一个目标是快速启动,为此 Dart VM 并不会立刻优化要执行的代码。执行时间太短、次数太少的代码无法触发 VM 的优化器,这样的结果并不能反映真实的性能数据。所以,在正式开始记录执行时间之前要预先执行足够多的次数和时间,然后再开始测试性能。
除了热身,测试本身也要执行足够的时间和次数才能获得准确的数据,尤其是单次执行时间很短的测试。
2. 关闭检查模式和调试模式
Dart 有两种执行模式:检查模式(checked)和生产模式(production)。检查模式会在运行时插入大量类型检查,自然会影响性能。命令行模式下 dart 默认就是生产模式。但在 Dart Editor 中默认是在检查模式下运行,首先保证程序在检查模式下执行没问题,然后在性能测试时在程序的启动配置中取消 VM 的 “Run in checked mode”选项。
此外,debug 模式也会对性能有影响。在 Dart Editor 的选项配置中,Run and Debug 中的 break on exceptions 设为 none 。
基本性能测试代码
假设要执行的测试函数为 func() ,那么代码大概是像下面这样:
- int m = 10, n = 100;
- //预先执行 m 次调用作为热身,但不计时间
- for(int i = 0; i < m; i++){
- func();
- }
-
- //开始计时,并执行 n 次调用
- var st = new Stopwatch()..start();
-
- for(int i = 0; i < n; i++){
- func();
- }
-
- //打印测试结果
- print("Runtime is ${sw.elapsedMicroseconds/n} us");
复制代码 在 Dart 中 Stopwatch 用于计时,Stopwatch 对象有两个属性表示启动之后逝去的时间:elapsedMilliseconds(逝去的毫秒) 和 elapsedMicroseconds(逝去的微妙,即千分之一毫秒)。以上代码用的是微妙,也可以用毫秒。
对应的 JavaScript 代码是:
- var m = 10, n = 100;
- for(var i = 0; i < m; i++){
- func();
- }
-
- var start = (new Date).getTime();
-
- for(var i = 0; i < n; i++){
- func();
- }
-
- var time = ((new Date).getTime() - start)/n;
复制代码 这里 (new Date).getTime() 获得的时间单位是毫秒。
为了保证代码被执行足够的时间(比如1s以上),需要适当调整 m 和 n 的值。还有一个更通用的方法可以保证代码至少执行给定的时间:
- double measureFor(Function f, int timeMinimum) {
- int time = 0;
- int iter = 0;
- Stopwatch watch = new Stopwatch();
- watch.start();
- int elapsed = 0;
- while (elapsed < timeMinimum) {
- f();
- elapsed = watch.elapsedMilliseconds;
- iter++;
- }
- return 1000.0 * elapsed / iter;
- }
复制代码 上面这个函数摘自 benchmark_harness 库,f 是要执行的测试,timeMinimum 是执行的最少时间(毫秒),返回每次执行的微秒。
利用 benchmark_harness 进行测试
Dart 提供了 benchmark_harness 库用于性能测试,这个库的实现非常简单,就是在干我们前面说的那些事。
在 pubspec.yaml 中添加:
- dependencies:
- benchmark_harness: any
复制代码 执行 pub install,然后导入:
- import 'package:benchmark_harness/benchmark_harness.dart';
复制代码 使用时可以 copy 提供的代码模版,其中 run 是要执行的测试:
- // Import BenchmarkBase class.
- import 'package:benchmark_harness/benchmark_harness.dart';
- // Create a new benchmark by extending BenchmarkBase
- class TemplateBenchmark extends BenchmarkBase {
- const TemplateBenchmark() : super("Template");
- static void main() {
- new TemplateBenchmark().report();
- }
- // The benchmark code.
- void run() {
- }
- // Not measured setup code executed prior to the benchmark runs.
- void setup() { }
- // Not measures teardown code executed after the benchark runs.
- void teardown() { }
- }
- main() {
- // Run TemplateBenchmark
- TemplateBenchmark.main();
- }
复制代码 这里继承了 BenchmarkBase ,然后覆盖 run 方法,最后调用 report 方法执行。
注意输出的结果是以10次测试为单位的平均值(而非一次测试的结果)。
参考资料:
|
|