为工作线程任务实现分析器
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
我有许多工作线程处理名为 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