因此,我试图知道当前线程执行到目前为止的时间。我正在尝试使用getrusage(RUSAGE_THREAD, &r_usage);来实现它。以下是我的困惑:
1-此函数返回的时间是否包括线程被阻塞(例如在条件变量上)或计划退出的时间?
2-线程由于其他原因而被阻塞的时间如何,例如由于I/O而被阻塞?
3-我能提高时间精度使getrusage(RUSAGE_THREAD, &r_usage);在纳秒内返回吗?
非常感谢!
发布于 2017-02-17 17:40:21
不,通常不会将阻塞的时间分配给用户或内核CPU时间(这是资源占用量)。rusage定时器基本上是一个由操作系统启动和停止的“挂钟定时器”:当进程被调度时,它会记录时间,当它被解压时,它会停止它(用户/内核在进入/退出内核例程时的分裂类似)。所有这些段的和是CPU时间。
在某些情况下,比如IO,内核可能正在执行真正的工作,而不是等待,这可能被分配给您的进程。
如果您想要更高的宝贵CPU时间,您应该查看性能计数器。在Linux上,您可以使用perf_events系统以虚拟化的方式访问这些计数器,也可以使用包装对该子系统访问的帕皮之类的库,或者最容易开始使用一些轻量级的工具,比如libpfc,它提供了直接的计数器访问。
你还会问:
此外,我如何包括在I/O上花费的时间?
这是一个棘手的问题,因为IO在现代系统上具有异步和缓存的特性。很难准确地确定所花费的时间以及如何分配它(例如,如果一个进程将一个页从磁盘带到缓存中,但随后又有10个其他进程访问它,那么如何分配IO时间)?有人认为您可以查看/proc/pid/计数器和状态条目,它们可能有一个阻塞的IO指示符。实际上,top可以显示处于这种状态的进程,因此您很可能从/proc/$pid中获取它。请注意,我认为,要使该文件系统工作,您必须从其他线程中获取该文件系统。
或者,您可以尝试在应用程序级别测试IO调用。最后,您可以使用类似于ptrace或Linux上较新的FTrace来在内核级别检测IO调用,并且您可能可以通过进程对其进行过滤。较新的内核显然有“每个进程的IO会计”,但我不能很快找到一个好的链接。不过,iotop的源代码可能会有您需要的电话。
最后,这取决于到目前为止执行当前线程所指的时间:如果您想包含IO,那么您可能只想要线程启动后的挂钟时间?然后您可以使用clock_gettime和朋友,它们提供纳秒分辨率(名义上,但调用本身至少需要十几纳秒,所以您不会精确地测量需要1或2纳诺的东西)。
发布于 2017-02-17 17:17:51
似乎很难相信用掉的时间(不管出于什么原因)会被记为执行的时间--但在偶然的情况下,让我们做一个简单的实验来得到一个想法:
#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的时间被阻塞,不被视为执行时间。
就精度而言,我认为理论上可以提高到纳秒级的精度,但这将涉及重写内核,而不仅仅是翻转开关或调用不同的函数。现实地说,这是一个很大的疑问,你是否能够得到更多的准确性,即使那时。如果你需要纳秒级的精度,这可能不是合适的工具。
https://stackoverflow.com/questions/42302622
复制相似问题