兽族的荣耀

勤以修身 俭以养德

博客园 首页 新随笔 联系 订阅 管理
  218 Posts :: 0 Stories :: 698 Comments :: 35 Trackbacks

近一段时间测试过几个程序,有一些心得。具体步骤如下:

(1)写出测试程序
(2)测试原程序,记录运行时间,作为优化的基础。要在Release下测试。
(3)检查算法,是不是最有效的算法。尤其是现在内存便宜,看有没有能够用空间换取时间的方法
(4)用Reflector查看类库,看你使用的方法是不是最有效率的方法
(5)对于运行次数多,性能关键的地方,不要直接调用类库。类库是为通用目的设计的,用Reflector可以发现,针对特殊的问题,内库里面有很多冗余代码

测试程序是很关键的,dotnet下用DateTime.Now.Ticks能够得到精确的时间,单位是10^-7s。

我爱用下面这种结构的测试代码:

 1    static void Main(string[] args)
 2    {
 3long _start,_end,_loops; //DateTime.Now.Ticks是long int
 4        _loops=100000;    //重复次数
 5        _start=DateTime.Now.Ticks;
 6
 7        for (int i=0;i<_loops;i++)
 8        {
 9            原方法;
10        }

11        _end=DateTime.Now.Ticks;
12
13        Console.WriteLine("{0}次调用原方法共花费时间{1}ms",_loops,(_end-_start)/10000);
14
15        _start=DateTime.Now.Ticks;
16
17        for (int i=0;i<_loops;i++)
18        {
19            优化后方法;
20        }

21        _end=DateTime.Now.Ticks;
22
23        Console.WriteLine("{0}次调用优化后方法共花费时间{1}ms",_loops,(_end-_start)/10000);
24    }

一定要在一次运行中同时测试原方法和优化后方法,这样得到的测试结果才有比较意义。(如果你的方法非常耗用CPU,用带超线程的计算机,或者把测试进程设置成实时进程,这样得到的结果更精确。)

windows下时间精度应该是0.001-0.01ms,运行时间在0.01ms以下的结果不可靠。.net下时间精度应该更低一点。我怀疑只有0.1ms,但没有认真测试过。

不想让别的进程干扰,就把测试进程设置成实时进程。半年前测试一个程序,性能只到了40-60,查看进程发现cpu时间主要是GUI占用了,测试进程只占用了20%。动动鼠标,程序性能会上串下跳的。把进程优先级调到最高,测试进程cpu占用稳定在93-97%。设置为实时进程,cpu占用稳定在96-97%,这样测试的结果才有效。

下面以实际例子具体解释相关技巧。

posted on 2005-08-15 11:23 xiaotie 阅读(2754) 评论(15)  编辑 收藏 网摘 所属分类: [语言]CLI(.NET)

评论

#1楼  2005-08-15 12:50 Ninputer      
DateTime.Now是测不准ms级别时间的,充其量测准到20ms左右。如果要高精度计时,用PerformanceCounter
  回复  引用  查看    

#2楼  2005-08-15 13:11 xiaotie      

谢谢。测试了一下,DateTime.Now.Ticks的时间精度是10ms。

static void Main(string[] args)
{
long start,end;

start = DateTime.Now.Ticks;
end = DateTime.Now.Ticks;

while(start==end)
{
end = DateTime.Now.Ticks;
}

Console.WriteLine("DateTime.Now.Ticks时间精度:{0}ms",(end-start)/10000);
}

结果:DateTime.Now.Ticks时间精度:10ms

这里够用了。更精确的测试不够用。
  回复  引用  查看    

#3楼  2005-08-15 18:05 蛙蛙池塘      
呵呵,这样可以测试精度呀,真巧妙
  回复  引用  查看    

#4楼  2005-08-15 20:48 idior      
以后用stopwatch
  回复  引用  查看    

#5楼  2005-08-16 00:25 龙蛰(NeoLee)      
stopwatch ?
  回复  引用  查看    

#6楼  2005-08-16 08:48 yinh      
Stopwatch sw = new Stopwatch();
long t;
GC.Collect();
sw.Start();

///....

sw.Stop();

t = sw.ElapsedMilliseconds;

是这样子吗?

不过我找不到这个stopwatch是在Framework哪里定义的,我只看到有别人写的(虽然很简单)

喔,原来是framework2.0中的,试试能不能reflector出来代码。
  回复  引用  查看    

#7楼  2005-08-16 09:41 火蛇儿 [未注册用户]
楼上的,为什么要调用: GC.Collect();

  回复  引用    

#8楼  2005-08-16 10:05 小春 [未注册用户]
非常的好。希望继续:)
  回复  引用    

#9楼  2005-08-16 10:09 xiaotie      
oh,找到Ninputer的一篇讲StopWatch的文章:试用“停表”高精度计时
http://blog.joycode.com/ninputer/archive/2004/07/31/29167.aspx
  回复  引用  查看    

#10楼  2005-08-16 10:54 yinh      
不过找到了另一个,精确到。。。nanosecond?这是纳秒?

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public class QueryPerfCounter
{
[DllImport("KERNEL32")]
private static extern bool QueryPerformanceCounter(
out long lpPerformanceCount);

[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);

private long start;
private long stop;
private long frequency;
Decimal multiplier = new Decimal(1.0e9);

public QueryPerfCounter()
{
if (QueryPerformanceFrequency(out frequency) == false)
{
// Frequency not supported
throw new Win32Exception();
}
}

public void Start()
{
QueryPerformanceCounter(out start);
}

public void Stop()
{
QueryPerformanceCounter(out stop);
}

public double Duration(int iterations)
{
return ((((double)(stop - start)* (double) multiplier) / (double) frequency)/iterations);
}
}
  回复  引用  查看    

#11楼  2005-08-16 12:13 xiaotie      
纳秒是到不了的。测试了一下:

static void Main(string[] args)
{
QueryPerfCounter q = new QueryPerfCounter();

q.Start();
q.Stop();

Console.WriteLine("QueryPerfCounter时间精度:{0}ns",q.Duration(1));
}

结果:

QueryPerfCounter时间精度:3911.1116077602ns
  回复  引用  查看    

#12楼  2005-08-16 12:29 xiaotie      
上面结果不对呀。QueryPerformanceFrequency的单位是多少?我的本本返回的Frequency是3579545
  回复  引用  查看    

#13楼  2005-08-16 12:45 xiaotie      
查了一下原文献:http://channel9.msdn.com/wiki/default.aspx/PerformanceWiki.HowToTimeManagedCode

Duration单位是纳秒

但是源程序测量误差还是有的,大概是3.9微秒,主要是函数调用的时间。如果测试之前这么来一下:

// Call the object and methods to JIT before the test run
QueryPerfCounter myTimer = new QueryPerfCounter();
myTimer.Start();
myTimer.Stop();

误差大概是1微妙。

我把这个类改了一下,加了时间校准:

public class QueryPerfCounter
{
[DllImport("KERNEL32")]
private static extern bool QueryPerformanceCounter(
out long lpPerformanceCount);

[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);

private long check;
private long start;
private long stop;
private long frequency;
Decimal multiplier = new Decimal(1.0e9);

public QueryPerfCounter()
{
if (QueryPerformanceFrequency(out frequency) == false)
{
// Frequency not supported
throw new Win32Exception();
}

check = 0;
int loops = 10000;

QueryPerformanceCounter(out start);
QueryPerformanceCounter(out stop);

for(int i=0;i<loops;i++)
{
QueryPerformanceCounter(out start);
QueryPerformanceCounter(out stop);
check+=stop-start;
}
check = check/loops;
}

public void Start()
{
QueryPerformanceCounter(out start);
}

public void Stop()
{
QueryPerformanceCounter(out stop);
}

public double Duration(int iterations)
{
return ((((double)(stop - start-check)* (double) multiplier) / (double) frequency)/iterations);
}
}

再运行测试:

static void Main(string[] args)
{
QueryPerfCounter q = new QueryPerfCounter();

q.Start();
q.Stop();

Console.WriteLine("QueryPerfCounter时间精度:{0}ns",q.Duration(1));
}


结果:QueryPerfCounter时间精度:0ns
  回复  引用  查看    

#14楼  2005-08-16 13:09 xiaotie      

上面这个校准后的类时间测试精度应该是279.365114840015ns。吃饭后我将撰文说明。
  回复  引用  查看    

#15楼  2007-10-26 16:27 l      
希望继续,添加关注
  回复  引用  查看    





标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
Google站内搜索

相关文章:

相关链接: