如何在 C# 和 C++ 中测量经过的时间

Posted

技术标签:

【中文标题】如何在 C# 和 C++ 中测量经过的时间【英文标题】:How to measure elapsed time in C# and C++ 【发布时间】:2011-10-14 18:28:02 【问题描述】:

我有一个简单的 C# 和 C++ 代码来计算点积的总和。

C#代码是:

using System;

namespace DotPerfTestCS

    class Program
    
        struct Point3D
        
            public double X, Y, Z;

            public Point3D(double x, double y, double z)
            
                X = x;
                Y = y;
                Z = z;
            
        

        static void RunTest()
        
            unchecked
            
                const int numPoints = 100000;
                const int numIters = 100000000;

                Point3D[] pts = new Point3D[numPoints];
                for (int i = 0; i < numPoints; i++) pts[i] = new Point3D(i, i + 1, i + 2);

                var begin = DateTime.Now;
                double sum = 0.0;
                var u = new Point3D(1, 2, 3);
                for (int i = 0; i < numIters; i++)
                
                    var v = pts[i % numPoints];
                    sum += u.X * v.X + u.Y * v.Y + u.Z * v.Z;
                
                var end = DateTime.Now;
                Console.WriteLine("Sum: 0 Time elapsed: 1 ms", sum, (end - begin).TotalMilliseconds);
            
        

        static void Main(string[] args)
        
            for (int i = 0; i < 5; i++) RunTest();
        
    

而 C++ 是

#include <iostream>
#include <vector>
#include <time.h>

using namespace std;

typedef struct point3d

    double x, y, z;

    point3d(double x, double y, double z)
    
        this->x = x;
        this->y = y;
        this->z = z;
    
 point3d_t;

double diffclock(clock_t clock1,clock_t clock2)

    double diffticks=clock1-clock2;
    double diffms=(diffticks*10)/CLOCKS_PER_SEC;
    return diffms;


void runTest()

    const int numPoints = 100000;
    const int numIters = 100000000;

    vector<point3d_t> pts;
    for (int i = 0; i < numPoints; i++) pts.push_back(point3d_t(i, i + 1, i + 2));

    auto begin = clock();
    double sum = 0.0, dum = 0.0;
    point3d_t u(1, 2, 3);
    for (int i = 0; i < numIters; i++) 
    
        point3d_t v = pts[i % numPoints];
        sum += u.x * v.x + u.y * v.y + u.z * v.z;
    
    auto end = clock();
    cout << "Sum: " << sum << " Time elapsed: " << double(diffclock(end,begin)) << " ms" << endl;



int main()

    for (int i = 0; i < 5; i++) runTest();
    return 0;

C#版本(发布x86优化,x64更慢)输出是

Sum: 30000500000000 Time elapsed: 551.0299 ms 
Sum: 30000500000000 Time elapsed: 551.0315 ms 
Sum: 30000500000000 Time elapsed: 552.0294 ms
Sum: 30000500000000 Time elapsed: 551.0316 ms 
Sum: 30000500000000 Time elapsed: 550.0315 ms

而 C++(默认 VS2010 Release 构建设置)产生

Sum: 3.00005e+013 Time elapsed: 4.27 ms
Sum: 3.00005e+013 Time elapsed: 4.27 ms
Sum: 3.00005e+013 Time elapsed: 4.25 ms
Sum: 3.00005e+013 Time elapsed: 4.25 ms
Sum: 3.00005e+013 Time elapsed: 4.25 ms

现在我预计 C# 代码会慢一些。但是对我来说,慢 130 倍似乎太多了。有人可以向我解释一下这里发生了什么吗?

编辑

我不是 C++ 程序员,我只是从互联网的某个地方获取了 diffclock 代码,而没有真正检查它是否正确。

使用 std::difftime C++ 结果是

Sum: 3.00005e+013 Time elapsed: 457 ms
Sum: 3.00005e+013 Time elapsed: 452 ms
Sum: 3.00005e+013 Time elapsed: 451 ms
Sum: 3.00005e+013 Time elapsed: 451 ms
Sum: 3.00005e+013 Time elapsed: 451 ms

这似乎是对的。

【问题讨论】:

在 C# 示例中,您的测试将 JITer 成本考虑在内。通常不会这样做。运行一次该方法以消除 JIT 的障碍,然后再次运行测试并比较数字 它只在第一次调用 RunTest() 时使用 JIT。它被调用了5次...... 你不应该使用DateTime.Now 来计时这样的事情。请查看 Stopwatch 类。 (虽然我怀疑这是对如此大差异的解释) @Ed S. 我没有计算那里的平均值... 您是否在没有附加调试器的情况下以发布模式运行它? (Visual Studio 中的 CTRL+F5 或直接从控制台运行) 【参考方案1】:

您的 diffclock 代码错误。

如果您将 C++ 代码更改为使用 std::clockstd::difftime,它似乎会显示实际运行时:

#include <iostream>
#include <vector>
#include <ctime>

using namespace std;

typedef struct point3d

    double x, y, z;

    point3d(double x, double y, double z)
    
        this->x = x;
        this->y = y;
        this->z = z;
    
 point3d_t;

void runTest()

    const int numPoints = 100000;
    const int numIters = 100000000;

    vector<point3d_t> pts;
    for (int i = 0; i < numPoints; i++) pts.push_back(point3d_t(i, i + 1, i + 2));

    auto begin = clock();
    double sum = 0.0, dum = 0.0;
    point3d_t u(1, 2, 3);
    for (int i = 0; i < numIters; i++) 
    
        point3d_t v = pts[i % numPoints];
        sum += u.x * v.x + u.y * v.y + u.z * v.z;
    
    auto end = clock();
    cout << "Sum: " << sum << " Time elapsed: " << double(std::difftime(end,begin)) << " ms" << endl;



int main()

    for (int i = 0; i < 5; i++) runTest();
    return 0;

结果:

Sum: 3.00005e+013 Time elapsed: 346 ms
Sum: 3.00005e+013 Time elapsed: 344 ms
Sum: 3.00005e+013 Time elapsed: 346 ms
Sum: 3.00005e+013 Time elapsed: 347 ms
Sum: 3.00005e+013 Time elapsed: 347 ms

这是在默认发布模式优化下运行应用程序,在 vs2010 之外。

编辑

正如其他人所指出的,在 C++ 中,使用 clock() 并不是对函数计时的最准确方法(如在 C# 中,Stopwatch 优于 DateTime)。

如果您使用的是 Windows,则始终可以使用 QueryPerformanceCounter 进行高分辨率计时。

【讨论】:

啊,是的,谢谢。我想这就是当你从互联网上复制粘贴一些代码而不考虑它时会发生的情况。【参考方案2】:

我相信您会发现您的 diffclock 实现产生十进制,而不是毫秒(假设 CLOCKS_PER_SECOND 被准确命名)。纠正这一点,C# 实现的运行速度会慢大约 30%,这似乎是合适的。

【讨论】:

是的,这个。所有关于 JIT 的讨论可能会占 30%,当然不会是 130 倍。【参考方案3】:

最明显的原因是 JIT,但一旦证实不是原因,我就有另一种解释。

“new Point3D”出现 100000 次。这是 100000 个堆分配,稍后会被释放。在 C++ 版本中,vector 也是基于堆的,这意味着当它增长时,会有一个 realloc。但是当向量增长时,它每次增长超过一个point3d_t。我预计 C++ 版本中只有 30 个左右的 realloc 调用。

【讨论】:

这也是我的第一个猜测,但分配都是在时间开始之前进行的(var u = new Point3D(1, 2, 3); 除外,但一次分配不应该把它扔掉那么多)。 Point3d 是一个结构,所以它不是真正的堆分配。数组在堆中,但这是一次分配。 但这不是时间的一部分。

以上是关于如何在 C# 和 C++ 中测量经过的时间的主要内容,如果未能解决你的问题,请参考以下文章

比较 c#、c++ 和 java 的性能(c# 的奇怪行为)

如何在 C++ 中测量基本的原始操作?

如何在 Java 中测量经过的时间? [复制]

如何在不考虑应用程序在后台的时间的情况下测量经过的游戏时间?

您将如何测量多线程 C# 请求的响应时间? [关闭]

如何在 OpenCV + Visual C++ 中测量对比度