C ++ std :: chrono在自己的例子中给出了错误的输出

时间:2015-10-20 17:29:05

标签: c++ chrono

所以我一直在使用时间探查器类(见下文)。 它完美地工作直到某些点(通过不工作我的意思是我怀疑它输出了奇怪的值)。然后我从头开始创建一个新的空白项目,基本上从这里复制粘贴示例:http://en.cppreference.com/w/cpp/chrono/duration/duration_cast。相反,它现在打印1014,当它显然应该是1000,就像它已经是doibg直到昨天!再一次,上面的链接中的相同示例过去一直工作,直到昨天。我不知道发生了什么。我重新启动了我的机器,但它仍无法正常工作。

这是时间分析器类:

#pragma once

#include <stdio.h>
#include <time.h>
#include <chrono> // C++11
#include <thread>
#include <string>

namespace profiler
{
// The time profiling class
class Time
{
public:
    Time(const std::string& str) 
        : m_str(str), m_start(std::chrono::system_clock::now()) { }

    virtual ~Time()
    {
        auto end = std::chrono::system_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - m_start).count();

        printf("%s took %lli milliseconds\n", m_str.empty() ? "Block" : m_str.c_str(), duration);
    }

private:
    std::string m_str;
    std::chrono::system_clock::time_point m_start;
};
}

#ifdef _DEBUG
// Profile only if debugging. This profiles the time spent to process the block that this macro was called within
#ifndef TIME
#define TIME(str) profiler::Time timer__(str)
#endif // TIME
#else
// If not debugging, do nothing
#ifndef TIME
#define TIME(str) do { } while(0) // This avoids empty statements
#endif // TIME
#endif // _DEBUG

#ifndef SLEEP
#define SLEEP(ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms));
#endif

// A working example of this profiler. Call EXAMPLE() and it should print 16 milliseconds
#ifndef EXAMPLE
#define EXAMPLE() \
    profiler::Time timer__("Example that takes 16 milliseconds (value should match)"); \
    std::this_thread::sleep_for(std::chrono::milliseconds(1)); \
    std::this_thread::sleep_for(std::chrono::milliseconds(2)); \
    std::this_thread::sleep_for(std::chrono::milliseconds(3)); \
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
#endif

以下是使用代码:

#include <stdio.h>
#include <chrono>
#include <thread>

int main()
{
    auto start = std::chrono::system_clock::now();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    auto end = std::chrono::system_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

    printf("Block took %lli milliseconds\n", duration); 

    return getchar();
}

我在Windows 7 Professional 64位上使用Visual Studio Ultimate 2012,如果有帮助的话。

2 个答案:

答案 0 :(得分:3)

gradle run --debug-jvm无法保证完全 1秒钟。

使用1.014秒,包括对std::this_thread::sleep_for(std::chrono::seconds(1));的第二次调用,必须被视为足够好。

答案 1 :(得分:2)

很可能它的另一个应用程序调用timeBeginPeriod,这会搞乱你的测量。下面是一个例子:

这是一个测量1000毫秒睡眠的应用程序,然后生成另一个调用timeBeingPeriod(1)和timeEndPeriod(1)的应用程序。请注意第二个调用timeBeginPeriod的应用程序如何影响此应用程序的时间度量:

#include <Windows.h>
#include <chrono>
#include <iostream>

int main(int nArgs, char**args)
{
    if (nArgs <= 1)
    {
        // if we're spawned normally measure sleeping for 1000ms 30 times
        for (int i = 0; i < 30; ++i)
        {
            auto timeBegin = std::chrono::system_clock::now();
            Sleep(1000);
            auto timeEnd = std::chrono::system_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeBegin);
            std::cout << "Iteration " << i << ", sleeping for 1000ms took " << duration.count() << "ms..." << std::endl;
            // On the 10th iteration spawn a bad app which calls timeBeginPeriod(1)
            if (i == 10)
            {
                std::cout << "Spawning bad process" << std::endl;
                PROCESS_INFORMATION pi = {};
                STARTUPINFOA si = { sizeof(STARTUPINFOA) };
                CreateProcessA("..\\Debug\\Timer.exe", "be a bad process", nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
            }
        }
    }
    else
    {
        // If we're spawned with some arguments pretend to be a bad app that calls timeBeginPeriod(1)
        std::cout << "Bad process calling timeBeginPeriod(1)" << std::endl;
        timeBeginPeriod(1);
        Sleep(10 * 1000);
        std::cout << "Bad process calling timeEndPeriod(1)" << std::endl;
        timeEndPeriod(1);
    }

}

给出:

Iteration 0, sleeping for 1000ms took 1015ms...
Iteration 1, sleeping for 1000ms took 1015ms...
Iteration 2, sleeping for 1000ms took 1015ms...
Iteration 3, sleeping for 1000ms took 1015ms...
Iteration 4, sleeping for 1000ms took 1015ms...
Iteration 5, sleeping for 1000ms took 1015ms...
Iteration 6, sleeping for 1000ms took 1015ms...
Iteration 7, sleeping for 1000ms took 1015ms...
Iteration 8, sleeping for 1000ms took 1015ms...
Iteration 9, sleeping for 1000ms took 1015ms...
Iteration 10, sleeping for 1000ms took 1015ms...
Spawning bad process
Bad process calling timeBeginPeriod(1)
Iteration 11, sleeping for 1000ms took 1011ms...
Iteration 12, sleeping for 1000ms took 1001ms...
Iteration 13, sleeping for 1000ms took 1001ms...
Iteration 14, sleeping for 1000ms took 1001ms...
Iteration 15, sleeping for 1000ms took 1000ms...
Iteration 16, sleeping for 1000ms took 1000ms...
Iteration 17, sleeping for 1000ms took 1001ms...
Iteration 18, sleeping for 1000ms took 1001ms...
Iteration 19, sleeping for 1000ms took 1001ms...
Bad process calling timeEndPeriod(1)
Iteration 20, sleeping for 1000ms took 1008ms...
Iteration 21, sleeping for 1000ms took 1011ms...
Iteration 22, sleeping for 1000ms took 1015ms...
Iteration 23, sleeping for 1000ms took 1015ms...
Iteration 24, sleeping for 1000ms took 1016ms...
Iteration 25, sleeping for 1000ms took 1015ms...
Iteration 26, sleeping for 1000ms took 1015ms...
Iteration 27, sleeping for 1000ms took 1015ms...
Iteration 28, sleeping for 1000ms took 1015ms...
Iteration 29, sleeping for 1000ms took 1015ms...

请注意,在一般情况下,我们测量的时间太长了15毫秒,但是“坏”应用程序正在运行时,我们会更准确。

您应该使用更准确的时钟来衡量时间。 QueryPerformanceCounter / QueryPerformanceFrequency GetSystemTimeAsFileTimePrecise std::chrono::high_resolution_clock仅限VS2015即可使用。 vs2013上的std::chrono::high_resolution_clock有点垃圾,但仍有这个问题。

然而,这只能解释你所看到的内容,在一般情况下,睡眠(xxx)将为xxx睡眠而另外一些 - 它只会在有一个备用CPU核心在上运行时再次启动下一次预定。请不要将timeBeginPeriod用作自己的错误,只需编写你的逻辑来处理你没有在实时系统上运行的事实,这样任何测量都会有一些错误。