Reputation: 2749
I have a number of worker threads which work on tasks called class Task
. I'm using C++ on x86_64 Windows/Mac/Linux. While working on each task, I can update a global Task* activeTasks[]
array so that the application knows when each worker is processing which task.
activeTasks[threadId] = &task;
task.work();
activeTasks[threadId] = NULL;
I would like to write a simple in-application profiler so that the user can see how many microseconds have been spent on each task.
An additional complication is that tasks may call sleep()
inside their work()
function. The profiler should only sample a task when the thread is active, not sleeping or suspended by the scheduler.
How could a profiler like this be implemented?
It seems this is exactly how profilers like perf
work, except they inspect the current call stack rather than an activeTasks
array.
A naive idea is to launch a separate profiler thread that periodically checks activeTasks[threadId]
every few microseconds, incrementing a counter for each task if the worker thread is in a running state. This can be checked with thread.ExecutionState == 3
on Windows and possibly some way with pthreads.
But the issue is that on single-core machines, running a profiler thread and any of the worker threads is never simultaneous, so the profiler would always see the worker as "suspended".
Another idea is to trigger some sort of interrupt, but I have no idea how this is done.
Upvotes: 0
Views: 290
Reputation: 11158
The simple implementation is to have a class that can be toggled on/off, then at the end of the (say) function log a counter. Having another thread doing that is bad because you would consume CPU time on polling time, which is bad.
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);
...
}
Upvotes: 1
Reputation: 85316
It sounds like you want to measure thread CPU time.
There are ways to do that in Win32 (using GetThreadTimes) and pthreads (using pthread_getcpuclockid).
long startTime = getThreadCPUTime();
task.work();
long endTime = getThreadCPUTime();
// lock mutex
taskTimes[taskType] += endTime - startTime;
// unlock mutex
Upvotes: 2