当前位置: 首页 > 知识库问答 >
问题:

如何将QueryThreadCycleTime()转换为秒?

严安志
2023-03-14

Windows函数QueryThreadCycleTime()给出给定线程使用的“CPU时钟周期”数。Windows手册中大胆地指出

不要尝试将QueryThreadCycleTime返回的CPU时钟周期转换为经过的时间。

对于大多数英特尔和AMDx86_64CPU,我想这样做。它不需要非常精确,因为无论如何你都不能期望像RDTSC这样的循环计数器完美。我只需要一些笨拙的方法来获取CPU的时间因子秒/QueryThreadCycleTime

首先,我设想QueryThreadCycleTime在内部使用RDTSC。我设想在某些CPU上,使用恒定速率TSC,因此更改实际时钟速率(例如,使用变频CPU电源管理)不会影响时间/TSC系数。在其他CPU上,这个速率可能会改变,所以我必须定期查询这个因子。

在任何人引用XY问题之前,我应该注意到我对替代解决方案并不真正感兴趣。这是因为我对分析有两个其他方法无法满足的硬性要求。

  • 它应该只测量线程时间,因此sleep(1)不应该返回1秒,但是持续1秒的繁忙循环应该返回1秒。换句话说,探查器不应该说一个任务在其线程仅活动1ms的情况下运行了10ms。这就是我无法使用QueryPerformanceCounter()的原因

按照@Ted Lyngmo的要求,目标是实现computeFactor()。

#include <stdio.h>
#include <windows.h>

double computeFactor();

int main() {
    uint64_t start, end;
    QueryThreadCycleTime(GetCurrentThread(), &start);
    // insert task here, such as an actual workload or sleep(1)
    QueryThreadCycleTime(GetCurrentThread(), &end);
    printf("%lf\n", (end - start) * computeFactor());
    return 0;
}

共有1个答案

夏朗
2023-03-14

不要尝试将QueryThreadCycleTime返回的CPU时钟周期转换为经过的时间。

我想这样做。

你的愿望显然被拒绝了!

一种解决方法是创建一个带有稳定时钟的线程,以指定的频率对QueryThreadCycleTime和/或GetThreadTimes进行采样。下面是一个示例,演示如何使用采样线程每秒对这两个线程进行一次采样。

#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <thread>
#include <vector>

#include <Windows.h>

using namespace std::literals::chrono_literals;

struct FTs_t {
    FILETIME CreationTime, ExitTime, KernelTime, UserTime;
    ULONG64 CycleTime;
};

using Sample = std::vector<FTs_t>;

std::ostream& operator<<(std::ostream& os, const FILETIME& ft) {
    std::uint64_t bft = (std::uint64_t(ft.dwHighDateTime) << 16) + ft.dwLowDateTime;
    return os << bft;
}

std::ostream& operator<<(std::ostream& os, const Sample& smp) {
    size_t tno = 0;
    for (const auto& fts : smp) {
        os << " tno:" << std::setw(3) << tno << std::setw(10) << fts.KernelTime
           << std::setw(10) << fts.UserTime << std::setw(16) << fts.CycleTime << "\n";
        ++tno;
    }
    return os;
}

// the sampling thread
void ft_sampler(std::atomic<bool>& quit, std::vector<std::thread>& threads, std::vector<Sample>& samples) {
    auto tp = std::chrono::steady_clock::now(); // for steady sampling

    FTs_t fts;
    while (quit == false) {
        Sample s;
        s.reserve(threads.size());
        for (auto& th : threads) {
            if (QueryThreadCycleTime(th.native_handle(), &fts.CycleTime) &&
                GetThreadTimes(th.native_handle(), &fts.CreationTime,
                               &fts.ExitTime, &fts.KernelTime, &fts.UserTime)) {
                s.push_back(fts);
            }
        }
        samples.emplace_back(std::move(s));

        tp += 1s; // add a second since we last sampled and sleep until that time_point
        std::this_thread::sleep_until(tp);
    }
}

// a worker thread
void worker(std::atomic <bool>& quit, size_t payload) {
    volatile std::uintmax_t x = 0;
    while (quit == false) {
        for (size_t i = 0; i < payload; ++i) ++x;
        std::this_thread::sleep_for(1us);
    }
}

int main() {
    std::atomic<bool> quit_sampling = false, quit_working = false;
    std::vector<std::thread> threads;
    std::vector<Sample> samples;
    size_t max_threads = std::thread::hardware_concurrency() > 1 ? std::thread::hardware_concurrency() - 1 : 1;

    // start some worker threads
    for (size_t tno = 0; tno < max_threads; ++tno) {
        threads.emplace_back(std::thread(&worker, std::ref(quit_working), (tno + 100) * 100000));
    }

    // start the sampling thread
    auto smplr = std::thread(&ft_sampler, std::ref(quit_sampling), std::ref(threads), std::ref(samples));

    // let the threads work for some time
    std::this_thread::sleep_for(10s);

    quit_sampling = true;
    smplr.join();

    quit_working = true;
    for (auto& th : threads) th.join();

    std::cout << "Took " << samples.size() << " samples\n";

    size_t s = 0;
    for (const auto& smp : samples) {
        std::cout << "Sample " << s << ":\n" << smp << "\n";
        ++s;
    }
}

 类似资料:
  • 问题内容: 我在mySQL 5.1中有一个数据类型的日期列。如何将其转换为DATE? 这是我到目前为止所拥有的- 得到这个 错误-#1064-您的SQL语法有错误;查看与您的MySQL服务器版本相对应的手册以获取正确的语法,以在’FROM 7 FOR 4附近使用) 请帮忙。 问题答案: 您可以使用MySQL的功能 尽管我怀疑您使用Unix时间戳会更轻松

  • 问题内容: 有没有一种简单的方法可以避免处理文本编码问题? 问题答案: 您确实无法避免处理文本编码问题,但是Apache Commons中已有一些解决方案: 至: 至: 您只需要选择所需的编码即可。

  • 问题内容: 如何使用Java将Dicom文件(.dcm)转换为jpeg图像?这是我的代码: 我在运行项目时遇到以下错误 请帮助并提前感谢 问题答案: 这是使用dcm4che 2将DICOM转换为JPEG的链接 以下是我的代码,效果很好,我将其与导入一起放置,因此可能用完了。 用于运行它的罐子 dcm4che-imageio-2.0.28.jar dcm4che-image-2.0.28.jar j

  • 问题内容: 我正在使用A 将Json从Web转换为字符串。 这可能很简单,但是我似乎无法将此字符串转换为。 我怎样才能做到这一点? 问题答案: 请参阅文档和示例。

  • 问题内容: 如何在Java中将org.jdom.Document转换为字符串? 问题答案:

  • 问题内容: 我有一个下面的代码- 通过HttpClient连接到Web服务到PHP文件 从SQL查询返回结果 返回格式是一个jArray(一个JSONArray) 当我查看LogCat时,我看到了查询的所有“名称”,每条记录都被打印出来。我只需要将这些结果插入ListView中即可。我怎样才能做到这一点? PS-我没有ArrayAdapter的单独类。这可能是原因吗? 问题答案: 如果您只想显示t