7

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

hari
  • 1,419
  • 4
  • 19
  • 30
  • 1
    I think you can get enough hints from this question: http://stackoverflow.com/questions/3475750/posix-api-call-to-list-all-the-pthreads-running-in-a-process – jupp0r Feb 24 '12 at 12:12

4 Answers4

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
scottbiker
  • 192
  • 1
  • 4
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);
       ...
    }
dash-o
  • 13,723
  • 1
  • 10
  • 37
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.

alpha0
  • 65
  • 10
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!

that other guy
  • 116,971
  • 11
  • 170
  • 194
mghh
  • 47
  • 1
  • 6