8

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

1

5 Answers 5

3

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
Sign up to request clarification or add additional context in comments.

Comments

2

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);
       ...
    }

1 Comment

My thanks for this detailed answer! (the only valuable one)
1

man 2 times

This is generally enough to get a precise overview of each thread user/sys/idle times without much hassle.

Don't rely on the children times in the uts struct, they are only accounted when a child has exited and been waited for.

1 Comment

Please share more details, like any code sample, and a proper explanation such that others can learn from your answer
0

Though I am a naive in this field I think the below approach might work

1)maintain a updated list of new PID's that are getting created in your program in a shared memory segment ( My idea was to take help of IPC's )

2) develop an application which is capable to access the previously created shared segment and fetch the PID's to check the corresponding utilization.

Comments

0

One of the problem of /proc is finding which thread is what.

you can set thread name using pthread_setname_np to set thread name and check thread name of a given time using /proc/<MainPID>/task/<threadID>/status or /proc/<MainPID>/task/<threadID>/stat and then check these answers calculating-cpu-usage-for-given-pid on stackoverflow to get some idea!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.