我有一个在 Linux 上运行的基于 C 的应用程序,大约有 30 个线程。 现在我需要编写一个小实用程序来查找给定时间每个线程的 CPU 使用情况。它可以是应用程序的单独部分或一部分。
/proc 的问题之一是查找哪个线程是什么。
请给我一些如何开始的想法。
谢谢
我建议为每个线程指定一个人类可读的名称。 该名称在线程级“ps”输出中可见(因此“ps -L PID”)。
您可以使用此(不可移植)pthread api 为每个线程命名:
int pthread_setname_np(pthread_t thread, const char *name);
多线程雷鸟的输出示例:
% 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
正如OP所指出的,
/proc
文件系统为每个进程/proc/PROCESS-ID/stat
和每个任务/proc/PROCESS-ID/task/TASKID/stat
都有一个“stat”文件。后者是进程统计信息,是所有任务的聚合(包括已完成的任务!)。
根据
man proc
:stat
文件中的字段 14、15 包括使用的 CPU(用户、内核)。
剩下的就是将线程映射到 TASKID 的任务。正如手册页中所述(请参阅引号),没有直接的 API 来获取 gettid,而是需要系统调用
对于交互式实用程序,请考虑
top
(对于任务模式使用 y
)
有关可在应用程序内部使用的代码,请参阅下文
#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 ;
}
gettid
的手册页指出:
GETTID(2)
姓名 gettid - 获取线程标识
概要 #包括
pid_t gettid(void); Note: There is no glibc wrapper for this system call; see NOTES.
稍后: 笔记 Glibc 不提供此系统调用的包装器;使用 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)).
使用系统调用中的示例代码
#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)维护在共享内存段中的程序中创建的新 PID 的更新列表(我的想法是借助 IPC 的帮助)
2) 开发一个应用程序,该应用程序能够访问先前创建的共享段并获取 PID 以检查相应的利用率。
/proc 的问题之一是查找哪个线程是什么。
您可以使用 pthread_setname_np 设置线程名称,并使用
/proc/<MainPID>/task/<threadID>/status
或 /proc/<MainPID>/task/<threadID>/stat
检查给定时间的线程名称,然后在 stackoverflow 上检查这些答案 calculate-cpu-usage-for-given-pid得到一些想法!
男人2次
这通常足以准确概述每个线程用户/系统/空闲时间,而无需太多麻烦。
不要依赖 uts 结构中的子进程时间,只有当子进程退出并等待时才会计算它们。