getrusage(RUSAGE_THREAD,& r_usage)中的用户CPU时间和系统CPU时间是多少?

时间:2017-02-17 16:18:31

标签: c linux multithreading getrusage

所以我想知道当前线程到目前为止执行的时间。我正在尝试使用getrusage(RUSAGE_THREAD, &r_usage);。以下是我的困惑:

1-此函数返回的时间是否包括线程被阻止的时间(例如在条件变量上)或预定出来的时间?

2-线程因其他原因被阻止的时间如何,例如阻止I / O?

3-我可以提高时间精度,使getrusage(RUSAGE_THREAD, &r_usage);以纳秒为单位返回吗?

非常感谢!

2 个答案:

答案 0 :(得分:2)

似乎很难相信所花费的时间(无论出于何种原因)将被视为执行时间 - 但是如果它有机会,请让我们做一个快速实验来获得一个想法:< / p>

#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <iostream>
#include <iomanip>

std::ostream &operator<<(std::ostream &os, timeval const &t) {
    return os << t.tv_sec << '.' << std::setw(6) << std::setfill('0') << t.tv_usec << std::setfill(' ');
}

int main() {
    rusage r;

    getrusage(RUSAGE_THREAD, &r);
    std::cout << r.ru_utime << " [" << r.ru_stime << "]\n";
    sleep(10);
    getrusage(RUSAGE_THREAD, &r);
    std::cout << r.ru_utime << " [" << r.ru_stime << "]\n";
}

结果:

0.000000 [0.000000]
0.000000 [0.000000]

所以,睡觉的时间并没有收费。我们可以使用互斥锁进行类似的测试:

#include <sys/time.h>
#include <sys/resource.h>
#include <iostream>
#include <iomanip>
#include <thread>
#include <mutex>

using namespace std::literals;

std::ostream &operator<<(std::ostream &os, timeval const &t) {
    return os << t.tv_sec << '.' << std::setw(6) << std::setfill('0') << t.tv_usec << std::setfill(' ');
}

int main() {
    rusage r;

    getrusage(RUSAGE_THREAD, &r);
    std::cout << r.ru_utime << " [" << r.ru_stime << "]\n" << std::flush;

    std::mutex m;
    m.try_lock();   // ensure mutex is locked

    // create thread to unlock mutex after 5 seconds:
    auto t = std::thread([&]{ std::this_thread::sleep_for(5s); m.unlock(); });

    // wait for mutex to be unlocked
    m.lock();

    // re-check resource usage
    getrusage(RUSAGE_THREAD, &r);
    std::cout << r.ru_utime << " [" << r.ru_stime << "]\n";
    t.join();
}

这给出了类似的结果。我没有为条件变量重复它​​而感到困扰,但是看到不同的结果我会感到非常惊讶(condvar总是与互斥锁相关联,它是你的互斥体真的等等)。

尝试测试每种可能类型的I / O都不太实际,但过去的经验表明它也是如此:等待I / O的时间被阻止不被视为执行时间。

就准确性而言,我认为可以理论上将精度提高到纳秒范围,但它会涉及重写内核,而不仅仅是翻转开关或调用不同的函数。实际上,即使在那时你是否能够使更准确,这是一个很大的问题。如果你需要纳秒级精度,这可能不是适合这项工作的工具。

答案 1 :(得分:2)

不,通常,阻止的时间不会被分配给用户或内核CPU时间(这是rusage测量的)。 rusage计时器基本上是一个&#34;挂钟计时器&#34;这是由OS启动和停止的:当进程被调度时,它会记录时间以及它何时被取消调度它会停止它(类似于用户/内核在进入/退出到内核例程时拆分)。所有这些段的总和是CPU时间。

在某些情况下,如IO,内核可能正在进行实际工作,而不是等待,可能会分配给您的流程。

如果您想要更高的 CPU时间,您应该查看性能计数器。在Linux上,您可以使用perf_events系统以虚拟化方式访问这些计数器,或使用包含对此子系统的访问权限的PAPI库,或者最容易上手的是使用像libpfc提供简单的计数器访问。

你也问:

  

此外,我如何在I / O上花费时间?

由于现代系统上IO的异步和缓存特性,这是一个棘手的问题。很难精确确定花费的时间以及如何分配它(例如,如果一个进程将一个页面从磁盘带入缓存,然后其他10个进程随后访问它,那么如何分配IO时间)?有人认为你可以做的是查看/proc/pid/计数器和状态条目,它们可能有一个阻塞IO指示符。实际上,top可以显示处于此状态的进程,因此您可能会从/proc/$pid获取此进程。请注意,您必须从其他一些线程中对此文件系统进行采样,以便实现这一目标。

或者,您可以尝试在应用程序级别检测IO调用。最后,您可以在Linux上使用类似ptrace或更新FTrace的内容来检测IO调用的内核级别,您可以按进程对其进行过滤。较新的内核显然具有&#34;每进程IO计费&#34; - 但我无法快速挖掘出一个好的链接。可能iotop的来源可能会有你需要的电话。

最后,这完全取决于到目前为止当前线程执行的时间的意思:如果你想要包含IO,也许你只需要挂钟时间,因为线程开始?然后你可以使用clock_gettime和朋友,它们提供纳秒分辨率(名义上,但调用本身需要至少十几纳秒,所以你不能准确地测量需要1或2纳秒的东西)。