簡體   English   中英

在 C++ 中分別測量每個線程上花費的 CPU 時間

[英]Measure CPU time spent on each thread separately in C++

我知道這個問題聽起來像一個簡單的問題,並且與以前的問題重復,其中 boost.timer 和 C++11 的計時工具作為答案給出。

但是,我的想法有點不同,我在 StackOverflow 或其他地方都沒有找到答案:

在我關於 Ubuntu Linux 的 (C++11) 程序中,我使用 std::async 和 std::future 機制啟動了幾個線程。

在每個線程中,我使用 boost.timer() 測量 CPU-Time。 如果我只啟動一個線程,我的 CPU 時間(在我的示例中)約為 0.39 秒,WC 時間相等,約為 0.39 秒。

如果我啟動多個線程,每個線程的 WC 時間會更長,例如 16 個線程為 0.8 秒,現在每個線程的 CPU 時間約為 6.4 秒,即 8 * 0.8 秒(我有一個四核 Xeon CPU)。

所以每個線程的 CPU-Time 似乎乘以(CPU 核心數)* 2。

當然(?)我希望每個線程的 CPU 時間接近 0.39 秒,因為這可能仍然是線程將 CPU 用於其目的的時間。 顯示的較長 CPU 時間(乘以“CPU 數量因子”)對於分別衡量每個線程的真實 CPU 消耗沒有太大幫助。

為了說明我的 append 我的測試程序及其 output,首先是一個線程,然后是 16 個線程。

所以我的問題是:我能做些什么,我可以使用哪個庫、function 或編程技術來獲得每個線程的真實 CPU 使用率,它不應該隨着線程數的啟動而發生太大變化?

#include <iostream>
#include <fstream>

#include <vector>
#include <cmath>

#include <future>
#include <mutex>
#include <chrono>

#include <boost/timer/timer.hpp>

std::mutex mtx;


class XTimer
{
public:
    XTimer() {};

    void start();
    void stop();

    double cpu_time();
    double boost_cpu_time();
    double wc_time();

    std::chrono::time_point<std::chrono::system_clock> timestamp_wc;
    std::chrono::time_point<std::chrono::steady_clock> timestamp_cpu;

    boost::timer::cpu_timer timer_cpu;

    double wc_time_val;
    double cpu_time_val;

    double boost_cpu_time_val;

};

void XTimer::start()
{
    timestamp_wc = std::chrono::system_clock::now();
    timestamp_cpu = std::chrono::steady_clock::now();

    timer_cpu.start();

    cpu_time_val = 0;
    wc_time_val = 0;

    boost_cpu_time_val = 0;


}

void XTimer::stop()
{
    const auto ns_wc = std::chrono::system_clock::now() - timestamp_wc;
    const auto ns_cpu = std::chrono::steady_clock::now() - timestamp_cpu;

    auto elapsed_times(timer_cpu.elapsed());

    auto cpu_elapsed(elapsed_times.system + elapsed_times.user);

    //std::cout << "boost: cpu elapsed = " << cpu_elapsed << std::endl;

    wc_time_val = double(ns_wc.count())/1e9;
    cpu_time_val = double(ns_cpu.count())/1e9;

    boost_cpu_time_val = double(cpu_elapsed)/1e9;

}


double XTimer::cpu_time()
{
    return cpu_time_val;
}

double XTimer::boost_cpu_time()
{
    return boost_cpu_time_val;
}

double XTimer::wc_time()
{
    return wc_time_val;
}




template<class T>
int wait_for_all(std::vector<std::future<T>> & fuvec)
{
    std::vector<T> res;

    for(auto & fu: fuvec) {
        res.push_back(fu.get());
    }
    return res.size();

}


int test_thread(int a)
{
    const int N = 10000000;

    double x = 0;

    XTimer tt;

    do {
        std::lock_guard<std::mutex> lck {mtx}; 
        std::cout << "start thread: " << a << std::endl;
    } while (0);

    tt.start(); 

    for(int i = 0; i < N; ++i) {

        if (i % 10000 == 0) {
            //std::cout << (char((int('A') + a)));
        }

        x += sin(i);
    }

    tt.stop();

    do {
        std::lock_guard<std::mutex> lck {mtx};

        std::cout << "end thread: " << a << std::endl;
        std::cout << "boost cpu = " << tt.boost_cpu_time() << " wc = " << tt.wc_time() << std::endl;
    } while (0);

    return 0;
}


int test_threads_start(int num_threads)
{

    std::vector<std::future<int>> fivec;

    XTimer tt;

    tt.start();

    for(int i = 0; i < num_threads; ++i) {
        fivec.push_back(std::async(test_thread, i));
    }

    int sz = wait_for_all(fivec);

    tt.stop();

    std::cout << std::endl << std::endl;

    std::cout << "all threads finished: total wc time = " << tt.wc_time() << std::endl;
    std::cout << "all threads finished: total boost cpu time = " << tt.boost_cpu_time() << std::endl;

}


int main(int argc, char** argv)
{
    const int num_threads_default = 1;
    int num_threads = num_threads_default;

    //boost::timer::auto_cpu_timer ac;

    if (argc > 1) {
        num_threads = atoi(argv[1]);
    }

    std::cout << "starting " << num_threads << " threads." << std::endl;

    test_threads_start(num_threads);

    std::cout << "end." << std::endl;

    return 0;
}

我可以編譯

g++ -o testit testit.cpp -L/usr/lib/x86_64-linux-gnu -pthread -lboost_timer -lboost_system -lboost_thread 

樣品 output 帶 1 個線程

starting 1 threads.
start thread: 0
end thread: 0
boost cpu = 0.37 wc = 0.374107


all threads finished: total wc time = 0.374374
all threads finished: total boost cpu time = 0.37

樣品 output 16 線程

starting 16 threads.
start thread: 0
start thread: 1
start thread: 2
start thread: 3
start thread: 4
start thread: 10
start thread: 5
start thread: 7
start thread: 6
start thread: 11
start thread: 8
start thread: 9
start thread: 13
start thread: 12
start thread: 14
start thread: 15
end thread: 1
boost cpu = 4.67 wc = 0.588818
end thread: 2
boost cpu = 5.29 wc = 0.66638
end thread: 0
boost cpu = 5.72 wc = 0.7206
end thread: 13
boost cpu = 5.82 wc = 0.728717
end thread: 11
boost cpu = 6.18 wc = 0.774979
end thread: 12
boost cpu = 6.17 wc = 0.773298
end thread: 6
boost cpu = 6.32 wc = 0.793143
end thread: 15
boost cpu = 6.12 wc = 0.767049
end thread: 4
boost cpu = 6.7 wc = 0.843377
end thread: 14
boost cpu = 6.74 wc = 0.84842
end thread: 3
boost cpu = 6.91 wc = 0.874065
end thread: 9
boost cpu = 6.83 wc = 0.86342
end thread: 5
boost cpu = 7 wc = 0.896873
end thread: 7
boost cpu = 7.05 wc = 0.917324
end thread: 10
boost cpu = 7.11 wc = 0.930335
end thread: 8
boost cpu = 7.03 wc = 0.940374


all threads finished: total wc time = 0.957748
all threads finished: total boost cpu time = 7.14
end.

boost::timer 的文檔沒有提到任何關於每個線程測量的內容。 幸運的是 boost::chrono 包含thread_clock ,它在支持它的平台上提供每個線程的 CPU 使用率。 它使用與 std::chrono 時鍾相同的接口並測量線程掛鍾。

在示例代碼中添加以下行后:

// Includes section
#include <boost/chrono.hpp>

// XTimer
boost::chrono::thread_clock::time_point timestamp_thread_wc;
double thread_wc_time_val;

// XTimer::start()
timestamp_thread_wc = boost::chrono::thread_clock::now();

// XTimer::stop()
const auto ns_thread_wc = boost::chrono::thread_clock::now() - timestamp_thread_wc;
thread_wc_time_val = double(ns_thread_wc.count())/1e9;

// test_thread() just after for loop
sleep(1);

// test_thread() in bottom do -> while(0) loop
std::cout << "thread cpu = " << tt.thread_wc_time_val << std::endl;

並使用附加-lboost_chrono選項進行編譯,我得到:

starting 1 threads.
start thread: 0
end thread: 0
boost cpu = 0.16 wc = 1.16715
thread cpu = 0.166943


all threads finished: total wc time = 1.16754
all threads finished: total boost cpu time = 0.16
end.

和:

starting 2 threads.
start thread: 0
start thread: 1
end thread: 1
boost cpu = 0.28 wc = 1.14168
thread cpu = 0.141524
end thread: 0
boost cpu = 0.28 wc = 1.14417
thread cpu = 0.14401


all threads finished: total wc time = 1.14442
all threads finished: total boost cpu time = 0.28
end.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM