【问题标题】:High Resolution Clock in VS2013VS2013中的高分辨率时钟
【发布时间】:2015-07-26 03:37:50
【问题描述】:

我正在寻找具有高分辨率、高精度和相对较低的性能影响(按重要性排序)的跨平台时钟。

我试过了:

//using namespace std::chrono;
//typedef std::chrono::high_resolution_clock Clock;

using namespace boost::chrono;
typedef boost::chrono::high_resolution_clock Clock;
auto now = Clock::now().time_since_epoch();
std::size_t secs = duration_cast<seconds>(now).count();
std::size_t nanos = duration_cast<nanoseconds>(now).count() % 1000000000;
std::time_t tp = (std::time_t) secs;
std::string mode;
char timestamp[] = "yyyymmdd HH:MM:SS";
char format[] = "%Y%m%d %H:%M:%S";

strftime(timestamp, 80, format, std::localtime(&tp)); // Takes 12 microseconds
std::string output = timestamp + "." + std::to_string(nanos);

经过一些试验和测试: 原始的 std::chrono::high_resolution_clock 是 system_clock 的 typedef,精度约为 1 毫秒。 boost::chrono::high_resolution_clock 使用 Windows 上的 Query_Performance_Counter 并具有高分辨率和精度。不幸的是, Clock::now() 返回自启动以来的时间,而 now().time_since_epoch() 不返回纪元时间(也返回自启动以来的时间)。

不介意在不同平台(需要 VS2013 和 Linux)上为不同的解决方案使用防护。可能会存储现在并在单独的/低优先级线程中进行处理。

是否存在跨平台、高分辨率、高精度、性能友好的计时器?

boost::chrono::high_resolution_clock::now().time_since_epoch() 是否按预期工作?它没有给出自上一个纪元以来的时间。它只给出了自上次启动以来的时间。有没有办法将这个 now() 转换为自纪元以来的秒数。

【问题讨论】:

  • 添加了问题。查看boost doc,似乎可以任意定义epoch。但是没有时钟独立的方法可以将 time_since_epoch 转换为 unix 纪元时间(通常称为 1970 纪元)。
  • 这个问题和答案有帮助吗? C++ Cross-Platform High-Resolution Timer?
  • 该帖子解决了获取两点(计时器)之间时间的问题。我很乐意减去任何时钟来查找经过的时间。我想要的是能够创建 yyyymmdd HH:MM:SS.NNNNNNNNN 的时间戳,其中纳秒部分在内部是一致的(一个 stable_clock/QPC 就足够了)并且时间是正确的系统时间。
  • 这很有帮助:stackoverflow.com/questions/26128035/…。但是boost没有实现to_time_t,而chrono::high_resolution_clock在VS2013中并没有真正实现。如果有一种方法可以在 unix 时代创建任意时钟的 time_point,那么我就有了我需要的东西。
  • 只有system_clock 保证与民用日历有任何关系。它的所有已知实现都只是跟踪 Unix 时间:en.wikipedia.org/wiki/Unix_time。您可以构建自己的自定义时钟类型,但这仍然会给您带来以同时满足您的时代和精度要求的方式实现 now 的问题。

标签: c++ c++11 boost chrono


【解决方案1】:

我认为最好的方法是实现一个模拟 c++11/14 标准中Clock 要求的新时钟类型。

windows函数GetSystemTimePreciseAsFileTime可以作为windows时钟的基础。我相信这个函数会返回自 windows 纪元开始以来以 100 纳秒为单位的时间。如果我错了,请更改 period 的定义以适应。

struct windows_highres_clock
{
    // implement Clock concept
    using rep = ULONGLONG;
    using period = std::ratio<1, 10000000>;
    using duration = std::chrono::duration<rep, period>;
    using time_point = std::chrono::time_point<windows_highres_clock, duration>;

    static constexpr const bool is_steady = true;

    static time_point now() noexcept {
        FILETIME ft = { 0, 0 };
        GetSystemTimePreciseAsFileTime(&ft);
        ULARGE_INTEGER stamp { { ft.dwLowDateTime, ft.dwHighDateTime } };
        return time_point { duration { stamp.QuadPart } };
    }
};

如果您想继续并在其之上实现 TrivalClock 概念,那应该可行。只需按照http://cppreference.com的说明进行操作即可

提供 from_time_t 和 to_time_t 成员函数将完成图片,并允许您将此时钟用于计时和日期时间表示。

使用示例:

windows_highres_clock clock;
auto t0 = clock.now();
sleep(1);
auto t1 = clock.now();
auto diff = t1 - t0;
auto ms = std::chrono::duration_cast<chrono::milliseconds>(diff);
cout << "waited for " << ms.count() << " milliseconds\n";

示例输出:

waited for 1005 milliseconds

对于非 Windows 系统,system_clock 通常就足够了,但您可以使用适当的本机计时机制编写类似的每个系统时钟。

仅供参考:

这是可用于检查时钟分辨率的可移植代码。 any_clock 类是一个多态容器,可以容纳任何类时钟对象。它总是以自纪元以​​来的微秒返回其时间戳。

// create some syntax to help specialise the any_clock
template<class Clock> struct of_type {};

// polymorphic clock container
struct any_clock
{

    template<class Clock>
    any_clock(of_type<Clock>)
    : _ptr { new model<Clock> {} }
    {}

    std::chrono::microseconds now() const {
        return _ptr->now();
    }

    using duration = std::chrono::microseconds;

private:
    struct concept {
        virtual ~concept() = default;
        virtual duration now() const noexcept = 0;
    };
    template<class Clock>
    struct model final : concept {
        duration now() const noexcept final {
            return std::chrono::duration_cast<std::chrono::microseconds>(Clock::now().time_since_epoch());
        }
    };
    unique_ptr<concept> _ptr;
};

int main(int argc, const char * argv[])
{
    any_clock clocks[] = {
         { of_type<windows_highres_clock>() },
         { of_type<std::chrono::high_resolution_clock>() },
         { of_type<std::chrono::system_clock>() }
    };

    static constexpr size_t nof_clocks = std::extent<decltype(clocks)>::value;
    any_clock::duration t0[nof_clocks];
    any_clock::duration t1[nof_clocks];

    for (size_t i = 0 ; i < nof_clocks ; ++i) {
        t0[i] = clocks[i].now();
    }
    sleep(1);
    for (size_t i = 0 ; i < nof_clocks ; ++i) {
        t1[i] = clocks[i].now();
    }
    for (size_t i = 0 ; i < nof_clocks ; ++i) {
        auto diff = t1[i] - t0[i];
        auto ms = std::chrono::duration_cast<chrono::microseconds>(diff);
        cout << "waited for " << ms.count() << " microseconds\n";
    }
    return 0;
}

【讨论】:

  • 注意:GetSystemTimePreciseAsFileTime 仅适用于 Windows 8 及更高版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多