I have a C based application running on linux, with around 30 threads. Now I need to write a small utility which finds the CPU usage of each thread at given time. It can be a separate or part of the application.
One of the problem of /proc is finding which thread is what.
Please give me some ideas on how to start.
Thanks
As notes by the OP, the /proc
file system has a 'stat' file for each process, /proc/PROCESS-ID/stat
and for each task /proc/PROCESS-ID/task/TASKID/stat
. The later is the process stat is aggregate of all tasks (including completed tasks!).
As per man proc
: fields 14, 15 in stat
file include CPU (user, kernel) used.
That leave with the task of mapping threads to TASKID. As noted in the man page (see quotes), there is no direct API to gettid, instead the syscall is needed
For interactive utility, consider top
(use y
for task mode)
For code that can be used inside an app, see below
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
pid_t get_task_id(void) ;
int get_task_cpu(pid_t tid) ;
int main(int argc, char *argv[])
{
pthread_create(...) ;
}
void thread_proc(void *arg) {
pid_t tid = get_task_id() ;
// do something
int cpu = get_task_cpu(tid) ;
printf("TID=%d CPU=%d\n", tid, cpu) ;
}
pid_t get_task_id(void) {
pid_t tid = syscall(SYS_gettid);
return tid ;
}
int get_task_cpu(pid_t tid) {
char fname[200] ;
snprintf(fname, sizeof(fname), "/proc/self/task/%d/stat", (int) get_task_id()) ;
FILE *fp = fopen(fname, "r") ;
if ( !fp ) return -1 ;
int ucpu = 0, scpu=0, tot_cpu = 0 ;
if ( fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %d %d",
&ucpu, &scpu) == 2 )
tot_cpu = ucpu + scpu ;
fclose(fp) ;
return tot_cpu ;
}
The man page for gettid
states:
GETTID(2)
NAME gettid - get thread identification
SYNOPSIS #include
pid_t gettid(void); Note: There is no glibc wrapper for this system call; see NOTES.
And later on: NOTES Glibc does not provide a wrapper for this system call; call it using syscall(2).
The thread ID returned by this call is not the same thing as a POSIX thread ID (i.e., the opaque value returned by pthread_self(3)).
With the example code in syscall
#define _GNU_SOURCE #include <unistd.h> #include <sys/syscall.h> #include <sys/types.h> #include <signal.h> int main(int argc, char *argv[]) { pid_t tid; tid = syscall(SYS_gettid); ... }
I recommend to give every thread a human-readable name. This name is visible in thread-level "ps" output (so "ps -L PID").
You give each thread a name with this (non-portable) pthread api:
int pthread_setname_np(pthread_t thread, const char *name);
Example output for the multi-threaded thunderbird:
% ps -o pid,pcpu,comm,cmd -L 7111
PID %CPU COMMAND CMD
7111 8.3 thunderbird /usr/lib/thunderbird/thunderbird
7111 0.0 Gecko_IOThread /usr/lib/thunderbird/thunderbird
7111 0.0 Link Monitor /usr/lib/thunderbird/thunderbird
7111 0.0 Socket Thread /usr/lib/thunderbird/thunderbird
7111 0.0 JS Watchdog /usr/lib/thunderbird/thunderbird
7111 0.0 JS Helper /usr/lib/thunderbird/thunderbird
7111 0.1 JS Helper /usr/lib/thunderbird/thunderbird
7111 0.1 JS Helper /usr/lib/thunderbird/thunderbird
7111 0.1 JS Helper /usr/lib/thunderbird/thunderbird
7111 0.0 AudioIPC Callba /usr/lib/thunderbird/thunderbird
7111 0.0 AudioIPC Server /usr/lib/thunderbird/thunderbird
7111 0.0 BGReadURLs /usr/lib/thunderbird/thunderbird
7111 0.0 Hang Monitor /usr/lib/thunderbird/thunderbird
7111 0.0 gmain /usr/lib/thunderbird/thunderbird
7111 0.0 gdbus /usr/lib/thunderbird/thunderbird
7111 0.0 Cache2 I/O /usr/lib/thunderbird/thunderbird
7111 0.0 Cookie /usr/lib/thunderbird/thunderbird
7111 0.0 Timer /usr/lib/thunderbird/thunderbird
7111 0.0 GMPThread /usr/lib/thunderbird/thunderbird
7111 0.5 Softwar~cThread /usr/lib/thunderbird/thunderbird
7111 0.0 Compositor /usr/lib/thunderbird/thunderbird
7111 0.0 VRListener /usr/lib/thunderbird/thunderbird
7111 0.0 ImgDecoder #1 /usr/lib/thunderbird/thunderbird
7111 0.0 ImageIO /usr/lib/thunderbird/thunderbird
7111 0.0 IPDL Background /usr/lib/thunderbird/thunderbird
7111 0.0 HTML5 Parser /usr/lib/thunderbird/thunderbird
7111 0.0 LoadRoots /usr/lib/thunderbird/thunderbird
7111 0.0 DataStorage /usr/lib/thunderbird/thunderbird
7111 0.0 DataStorage /usr/lib/thunderbird/thunderbird
7111 0.0 mozStorage #1 /usr/lib/thunderbird/thunderbird
7111 0.0 StyleThread#0 /usr/lib/thunderbird/thunderbird
7111 0.0 StyleThread#1 /usr/lib/thunderbird/thunderbird
7111 0.0 StyleThread#2 /usr/lib/thunderbird/thunderbird
7111 0.0 ImgDecoder #2 /usr/lib/thunderbird/thunderbird
7111 0.0 dconf worker /usr/lib/thunderbird/thunderbird
7111 0.0 mozStorage #2 /usr/lib/thunderbird/thunderbird
7111 0.0 SysProxySetting /usr/lib/thunderbird/thunderbird
7111 0.0 ProxyResolution /usr/lib/thunderbird/thunderbird
7111 0.0 DataStorage /usr/lib/thunderbird/thunderbird
7111 0.0 URL Classifier /usr/lib/thunderbird/thunderbird
7111 0.0 Classif~ Update /usr/lib/thunderbird/thunderbird
7111 0.0 DNS Resolver #1 /usr/lib/thunderbird/thunderbird
7111 0.0 DOM Worker /usr/lib/thunderbird/thunderbird
7111 0.0 ImageBr~geChild /usr/lib/thunderbird/thunderbird
7111 0.0 mozStorage #3 /usr/lib/thunderbird/thunderbird
7111 0.0 thunderbird /usr/lib/thunderbird/thunderbird
7111 0.0 thunderbird /usr/lib/thunderbird/thunderbird
7111 0.0 thunderbird /usr/lib/thunderbird/thunderbird
7111 0.0 mozStorage #4 /usr/lib/thunderbird/thunderbird
7111 0.0 DNS Resolver #2 /usr/lib/thunderbird/thunderbird
7111 0.0 mozStorage #5 /usr/lib/thunderbird/thunderbird
7111 0.0 ImgDecoder #3 /usr/lib/thunderbird/thunderbird
7111 0.0 DNS Resolver #3 /usr/lib/thunderbird/thunderbird
7111 0.0 localStorage DB /usr/lib/thunderbird/thunderbird
7111 0.0 thunderbird /usr/lib/thunderbird/thunderbird
7111 0.0 thunderbird /usr/lib/thunderbird/thunderbird
7111 0.0 thunderbird /usr/lib/thunderbird/thunderbird
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With