为工作线程任务实现分析器

Implementing a profiler for worker thread tasks

我有许多工作线程处理名为 class Task 的任务。我在 x86_64 Windows/Mac/Linux 上使用 C++。在处理每个任务时,我可以更新全局 Task* activeTasks[] 数组,以便应用程序知道每个工作人员何时处理哪个任务。

activeTasks[threadId] = &task;
task.work();
activeTasks[threadId] = NULL;

我想编写一个简单的应用程序内分析器,以便用户可以看到每个任务花费了多少微秒。

另一个复杂的问题是任务可能会在其 work() 函数中调用 sleep()。探查器应该只在线程处于活动状态时对任务进行采样,而不是睡眠或被调度程序挂起。

如何实现这样的分析器? 看起来这正是像 perf 这样的分析器的工作方式,除了它们检查当前调用堆栈而不是 activeTasks 数组。

尝试次数

一个天真的想法是启动一个单独的分析器线程,每隔几微秒定期检查 activeTasks[threadId],如果工作线程处于 运行 状态,则为每个任务增加一个计数器。这可以通过 Windows 上的 thread.ExecutionState == 3 进行检查,也可以通过 pthreads 以某种方式进行检查。 但问题是,在单核机器上,运行 分析器线程和任何工作线程永远不会同时发生,因此分析器总是将工作线程视为 "suspended"。

另一个想法是触发某种中断,但我不知道这是怎么做到的。

简单的实现是有一个可以切换的 class on/off,然后在(比方说)函数的末尾记录一个计数器。让另一个线程这样做是不好的,因为您会在轮询时间上消耗 CPU 时间,这很糟糕。

class PROFILE
{
 private: unsigned long long start = 0,consumedtime = 0;
 public:
    PROFILE()
    {
     on();
    }
    ~PROFILE()
    {
     off();
     log(consumedtime); // e.g. save to a global array with a mutex
    }

    void on()
    {
     start = some_tick(); // E.g. GetTickCount64() on Windows
    }
    void off()
    {
     auto end = some_tick();
     consumedtime += end - start;
    }

   void sleep(int ms)
   {
    off();
    Sleep(ms); // Win
    on();
   }
}

void foo()
{
    PROFILE pr;
    ...
    pr.sleep(500);
    ...
}

听起来您想测量线程 CPU 时间。

在 Win32 中有一些方法可以做到这一点(使用 GetThreadTimes) and pthreads (using )。

long startTime = getThreadCPUTime();
task.work();
long endTime = getThreadCPUTime();
// lock mutex
taskTimes[taskType] += endTime - startTime;
// unlock mutex