From 1e33f2f1b4874bf7b20f92f66b66170dbd8afae1 Mon Sep 17 00:00:00 2001 From: zoutao Date: Thu, 4 May 2023 09:39:03 +0800 Subject: [PATCH 1/6] tasktop: add new option --limit --- source/tools/detect/sched/tasktop/README.md | 3 ++- source/tools/detect/sched/tasktop/tasktop.c | 24 +++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/source/tools/detect/sched/tasktop/README.md b/source/tools/detect/sched/tasktop/README.md index fe986fb5..00afbf39 100644 --- a/source/tools/detect/sched/tasktop/README.md +++ b/source/tools/detect/sched/tasktop/README.md @@ -2,7 +2,7 @@ tasktop实现对task的cpu利用率进行监控 # 使用说明 ``` -USAGE: tasktop [--help] [-t] [-p TID] [-d DELAY] [-i ITERATION] [-s SORT] [-f LOGFILE] +USAGE: tasktop [--help] [-t] [-p TID] [-d DELAY] [-i ITERATION] [-s SORT] [-f LOGFILE] [-l LIMIT] -d, --delay=DELAY 采样的周期 默认采样区间为3秒 -f, --logfile=LOGFILE 日志文件 默认为/var/log/sysak/tasktop/tasktop.log 指定为/dev/stdout每次输出前会刷屏 用于实时监控 @@ -10,6 +10,7 @@ USAGE: tasktop [--help] [-t] [-p TID] [-d DELAY] [-i ITERATION] [-s SORT] [-f LO -p, --pid=TID 指定监控的TID 如果是子线程ID 需要-t开启线程模式 -s, --sort=SORT 采样结果的排序方式 可选项为user(用户态)、sys(内核态)、cpu(用户态+内核态)默认为cpu -t, --thread 线程模式 监控线程级的CPU利用率 默认为进程级 + -l, --limit=LIMIT 每次输出只显示的top-LIMIT个task 默认为所有CPU利用率大于0的task ``` # 使用举例 diff --git a/source/tools/detect/sched/tasktop/tasktop.c b/source/tools/detect/sched/tasktop/tasktop.c index a426b8e7..7af6434b 100644 --- a/source/tools/detect/sched/tasktop/tasktop.c +++ b/source/tools/detect/sched/tasktop/tasktop.c @@ -85,15 +85,21 @@ struct env { pid_t tid; long nr_iter; enum sort_type rec_sort; -} env = { - .thread_mode = false, .delay = 3, .tid = -1, .rec_sort = SORT_CPU, .nr_iter = LONG_MAX - 1}; + int limit; +} env = {.thread_mode = false, + .delay = 3, + .tid = -1, + .rec_sort = SORT_CPU, + .nr_iter = LONG_MAX - 1, + .limit = INT_MAX}; const char* argp_program_version = "tasktop 0.1"; const char argp_program_doc[] = "A light top, display the process/thread cpu utilization in peroid.\n" "\n" - "USAGE: tasktop [--help] [-t] [-p TID] [-d DELAY] [-i ITERATION] [-s SORT] [-f LOGFILE]\n" + "USAGE: tasktop [--help] [-t] [-p TID] [-d DELAY] [-i ITERATION] [-s SORT] [-f LOGFILE] [-l " + "LIMIT]\n" "\n" "EXAMPLES:\n" @@ -102,6 +108,7 @@ const char argp_program_doc[] = " tasktop -p 1100 # only display task with pid 1100.\n" " tasktop -d 5 # modify the sample interval.\n" " tasktop -i 3 # output 3 times then exit.\n" + " tasktop -l 20 # limit the records number no more than 20.\n" " tasktop -f a.log # log to a.log (default to /var/log/sysak/tasktop/tasktop.log)\n"; static const struct argp_option opts[] = { @@ -113,7 +120,7 @@ static const struct argp_option opts[] = { "Logfile for result, default /var/log/sysak/tasktop/tasktop.log"}, {"sort", 's', "SORT", 0, "Sort the result, available options are user, sys and cpu, default is cpu"}, - + {"limit", 'l', "LIMIT", 0, "Specify the top-LIMIT tasks to display"}, {NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help"}, {}, }; @@ -198,6 +205,14 @@ static error_t parse_arg(int key, char* arg, struct argp_state* state) { argp_usage(state); } break; + case 'l': + err = parse_long(arg, &val); + if (err || val <= 0) { + fprintf(stderr, "Failed parse iteration-num.\n"); + argp_usage(state); + } + env.limit = val; + break; case ARGP_KEY_ARG: break; default: @@ -466,6 +481,7 @@ static void output(struct record_t** records, int proc_num, FILE* dest) { "%UTIME", "%STIME", "%CPU"); } + if (i >= env.limit) break; fprintf(dest, "%18s %6d %6d %10d %6.2f %6.2f %6.2f\n", records[i]->comm, records[i]->pid, records[i]->ppid, records[i]->runtime, records[i]->user_cpu_rate, records[i]->system_cpu_rate, records[i]->all_cpu_rate); -- Gitee From 11abf92d24d1bad27c53b7700d20035c89e8c3d0 Mon Sep 17 00:00:00 2001 From: zoutao Date: Thu, 4 May 2023 09:51:22 +0800 Subject: [PATCH 2/6] tasktop: fix error message. --- source/tools/detect/sched/tasktop/tasktop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tools/detect/sched/tasktop/tasktop.c b/source/tools/detect/sched/tasktop/tasktop.c index 7af6434b..bd26b7cd 100644 --- a/source/tools/detect/sched/tasktop/tasktop.c +++ b/source/tools/detect/sched/tasktop/tasktop.c @@ -208,7 +208,7 @@ static error_t parse_arg(int key, char* arg, struct argp_state* state) { case 'l': err = parse_long(arg, &val); if (err || val <= 0) { - fprintf(stderr, "Failed parse iteration-num.\n"); + fprintf(stderr, "Failed parse limit-num.\n"); argp_usage(state); } env.limit = val; -- Gitee From bbd1601de9c04ca45f9f4ac2edee15ff88cfc23c Mon Sep 17 00:00:00 2001 From: zoutao Date: Fri, 5 May 2023 18:59:55 +0800 Subject: [PATCH 3/6] tasktop:add system cpu rates distribution. --- source/tools/detect/sched/tasktop/tasktop.c | 240 +++++++++----------- source/tools/detect/sched/tasktop/tasktop.h | 89 ++++++++ 2 files changed, 200 insertions(+), 129 deletions(-) create mode 100644 source/tools/detect/sched/tasktop/tasktop.h diff --git a/source/tools/detect/sched/tasktop/tasktop.c b/source/tools/detect/sched/tasktop/tasktop.c index bd26b7cd..189010a8 100644 --- a/source/tools/detect/sched/tasktop/tasktop.c +++ b/source/tools/detect/sched/tasktop/tasktop.c @@ -11,16 +11,7 @@ #include #include #include - -// #define DEBUG 1 -#define FILE_PATH_LEN 256 -#define MAX_COMM_LEN 16 -#define PEROID 3 -#define LIMIT 20 -#define BUF_SIZE 512 -#define DEBUG_LOG "./log/debug.log" -#define PIDMAX_PATH "/proc/sys/kernel/pid_max" -#define PROC_STAT_PATH "/proc/stat" +#include "tasktop.h" char log_dir[FILE_PATH_LEN] = "/var/log/sysak/tasktop"; char default_log_path[FILE_PATH_LEN] = "/var/log/sysak/tasktop/tasktop.log"; @@ -28,57 +19,6 @@ time_t btime = 0; u_int64_t pidmax = 0; char* log_path = 0; -enum sort_type { SORT_SYSTEM, SORT_USER, SORT_CPU }; - -struct id_pair_t { - pid_t pid; - pid_t tid; -}; - -struct proc_stat_t { - int pid; - char comm[16]; - char state; - int ppid; - int pgrp; - int session; - int tty_nr; - int tpgid; - unsigned int flags; - u_int64_t minflt; - u_int64_t cminflt; - u_int64_t majflt; - u_int64_t cmajflt; - u_int64_t utime; - u_int64_t stime; - int64_t cutime; - int64_t cstime; - int64_t priority; - int64_t nice; - int64_t num_threads; - int64_t itrealvalue; - unsigned long long starttime; -}; - -struct cpu_time_t { - int pid; - int ppid; - char comm[MAX_COMM_LEN]; - u_int64_t stime; - u_int64_t utime; - u_int64_t starttime; -}; - -struct record_t { - u_int64_t pid; - u_int64_t ppid; - char comm[MAX_COMM_LEN]; - time_t runtime; - double system_cpu_rate; - double user_cpu_rate; - double all_cpu_rate; -}; - struct env { bool thread_mode; time_t delay; @@ -250,18 +190,60 @@ cleanup: return err; } -static void swap_cpu_time(struct cpu_time_t** lth, struct cpu_time_t** rth) { - struct cpu_time_t* tmp = *lth; - *lth = *rth; - *rth = tmp; -} +int swap(void* lhs, void* rhs, size_t sz) { + void* temp = malloc(sz); + if (!temp) return -1; + + memcpy(temp, lhs, sz); + memcpy(lhs, rhs, sz); + memcpy(rhs, temp, sz); -static void swap_record(struct record_t** lth, struct record_t** rth) { - struct record_t* tmp = *lth; - *lth = *rth; - *rth = tmp; + free(temp); + + return 0; } +static int read_stat(struct sys_cputime_t* prev_sys, struct sys_cputime_t* now_sys, + struct sys_record_t* sys_rec) { + int err = 0; + char buf[BUF_SIZE]; + char* endptr; + long val; + FILE* fp = fopen(PROC_STAT_PATH, "r"); + if (!fp) { + fprintf(stderr, "Failed open stat file.\n"); + err = errno; + goto cleanup; + } + + /*now only read first line, maybe future will read more info*/ + fscanf(fp, "%s %d %d %d %d %d %d %d %d %d %d\n", now_sys->cpu, &now_sys->usr, &now_sys->nice, + &now_sys->sys, &now_sys->idle, &now_sys->iowait, &now_sys->irq, &now_sys->softirq, + &now_sys->steal, &now_sys->guest, &now_sys->guest_nice); + + if (prev_sys->usr == 0) goto cleanup; + int now_time = now_sys->usr + now_sys->sys + now_sys->nice + now_sys->idle + now_sys->iowait + + now_sys->irq + now_sys->softirq + now_sys->steal + now_sys->guest + + now_sys->guest_nice; + int prev_time = prev_sys->usr + prev_sys->sys + prev_sys->nice + prev_sys->idle + + prev_sys->iowait + prev_sys->irq + prev_sys->softirq + prev_sys->steal + + prev_sys->guest + prev_sys->guest_nice; + int all_time = now_time - prev_time; + // int all_time = (sysconf(_SC_NPROCESSORS_ONLN) * env.delay * sysconf(_SC_CLK_TCK)); + + /* all_time can't not calculate by delay * ticks * online-cpu-num, because there is error + * between process waked up and running, when sched delay occur , the sum of cpu rates more than + * 100%. */ + + sys_rec->usr = (double)(now_sys->usr - prev_sys->usr) * 100 / all_time; + sys_rec->sys = (double)(now_sys->sys - prev_sys->sys) * 100 / all_time; + sys_rec->iowait = (double)(now_sys->iowait - prev_sys->iowait) * 100 / all_time; + +cleanup: + if (fp) fclose(fp); + return err; +}; + static u_int64_t read_pid_max() { int err = 0; FILE* fp = fopen(PIDMAX_PATH, "r"); @@ -346,11 +328,11 @@ cleanup: return err; } -static int read_proc(pid_t pid, pid_t tid, struct cpu_time_t** prev, struct cpu_time_t** now, - struct record_t** rec) { +static int read_proc(pid_t pid, pid_t tid, struct task_cputime_t** prev, + struct task_cputime_t** now, struct task_record_t** rec) { struct proc_stat_t proc_info; char proc_path[FILE_PATH_LEN]; - struct cpu_time_t* data; + struct task_cputime_t* data; FILE* fp = 0; int err = 0; @@ -362,7 +344,7 @@ static int read_proc(pid_t pid, pid_t tid, struct cpu_time_t** prev, struct cpu_ } if (!now[pid]) { - now[pid] = calloc(1, sizeof(struct cpu_time_t)); + now[pid] = calloc(1, sizeof(struct task_cputime_t)); if (!now[pid]) { fprintf(stderr, "Failed calloc memory.\n"); err = errno; @@ -409,7 +391,7 @@ static int read_proc(pid_t pid, pid_t tid, struct cpu_time_t** prev, struct cpu_ if (base != 0) { /* only process cpu utilization > 0 */ if (udelta + sdelta > 0) { - *rec = calloc(1, sizeof(struct record_t)); + *rec = calloc(1, sizeof(struct task_record_t)); (*rec)->pid = now[pid]->pid; (*rec)->ppid = now[pid]->ppid; (*rec)->runtime = run_time; @@ -426,7 +408,8 @@ cleanup: return err; } -static void sort_records(struct record_t** records, int proc_num, enum sort_type sort) { +static void sort_records(struct record_t* rec, int proc_num, enum sort_type sort) { + struct task_record_t** records = rec->tasks; int i, j; for (i = 0; i < proc_num; i++) { for (j = i + 1; j < proc_num; j++) { @@ -435,7 +418,7 @@ static void sort_records(struct record_t** records, int proc_num, enum sort_type } else if (records[i] && !records[j]) { continue; } else if (!records[i] && records[j]) { - swap_record(&records[i], &records[j]); + swap(&records[i], &records[j], sizeof(struct task_record_t*)); } else { double lth, rth; switch (sort) { @@ -457,14 +440,15 @@ static void sort_records(struct record_t** records, int proc_num, enum sort_type } if (lth < rth) { - swap_record(&records[i], &records[j]); + swap(&records[i], &records[j], sizeof(struct task_record_t*)); } } } } } -static void output(struct record_t** records, int proc_num, FILE* dest) { +static void output(struct record_t* rec, int proc_num, FILE* dest) { + struct task_record_t** records = rec->tasks; system("clear"); time_t now = time(0); struct tm* t; @@ -472,6 +456,12 @@ static void output(struct record_t** records, int proc_num, FILE* dest) { char time_str[BUF_SIZE]; int i; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", t); + + fprintf(dest, "%8s %6s %6s %6s %6s %6s %6s \n", "System", "usr", "sys", "iowait", "R", "D", + "fork"); + fprintf(dest, "%8s %6.1f %6.1f %6d %6d %6d\n", "", rec->sys.usr, rec->sys.sys, + rec->sys.iowait, rec->sys.nr_R, rec->sys.nr_D, rec->sys.nr_fork); + for (i = 0; i < proc_num; i++) { if (!records[i]) break; @@ -482,27 +472,29 @@ static void output(struct record_t** records, int proc_num, FILE* dest) { } if (i >= env.limit) break; - fprintf(dest, "%18s %6d %6d %10d %6.2f %6.2f %6.2f\n", records[i]->comm, records[i]->pid, + fprintf(dest, "%18s %6d %6d %10d %6.1f %6.1f %6.1f\n", records[i]->comm, records[i]->pid, records[i]->ppid, records[i]->runtime, records[i]->user_cpu_rate, records[i]->system_cpu_rate, records[i]->all_cpu_rate); } fflush(dest); } -static void clean_prev_table(int pidmax, struct cpu_time_t** prev, struct cpu_time_t** now) { +static void clean_prev_table(int pidmax, struct task_cputime_t** prev, + struct task_cputime_t** now) { int i; for (i = 0; i < pidmax; i++) { if (prev[i]) free(prev[i]); } } -static void now_to_prev(struct id_pair_t* pids, int proc_num, int pidmax, struct cpu_time_t** prev, - struct cpu_time_t** now) { +static void now_to_prev(struct id_pair_t* pids, int proc_num, int pidmax, + struct task_cputime_t** prev_task, struct task_cputime_t** now_task, + struct sys_cputime_t* prev_sys, struct sys_cputime_t* now_sys) { int i; for (i = 0; i < pidmax; i++) { - if (prev[i]) { - free(prev[i]); - prev[i] = NULL; + if (prev_task[i]) { + free(prev_task[i]); + prev_task[i] = NULL; } } @@ -512,13 +504,16 @@ static void now_to_prev(struct id_pair_t* pids, int proc_num, int pidmax, struct pid = pids[i].tid; else pid = pids[i].pid; - swap_cpu_time(&prev[pid], &now[pid]); + swap(&prev_task[pid], &now_task[pid], sizeof(struct task_cputime_t*)); } + + swap(prev_sys, now_sys, sizeof(struct sys_cputime_t)); } -static int make_records(struct id_pair_t* pids, int proc_num, struct record_t*** res, - struct cpu_time_t** prev, struct cpu_time_t** now) { - struct record_t** records = *res; +static int make_records(struct id_pair_t* pids, int proc_num, struct record_t* rec, + struct task_cputime_t** prev_task, struct task_cputime_t** now_task, + struct sys_cputime_t* prev_sys, struct sys_cputime_t* now_sys) { + struct task_record_t** records = rec->tasks; int err = 0; u_int64_t i; for (i = 0; i < proc_num; i++) { @@ -532,17 +527,19 @@ static int make_records(struct id_pair_t* pids, int proc_num, struct record_t*** } } - err = read_proc(id->pid, id->tid, prev, now, &records[i]); + err = read_proc(id->pid, id->tid, prev_task, now_task, &records[i]); if (err) { fprintf(stderr, "Failed read proc\n"); return err; } } + read_stat(prev_sys, now_sys, &rec->sys); return err; } -static void free_records(struct record_t** records, int proc_num) { +static void free_records(struct record_t* rec, int proc_num) { + struct task_record_t** records = rec->tasks; int i; for (i = 0; i < proc_num; i++) { if (records[i]) free(records[i]); @@ -565,8 +562,9 @@ int main(int argc, char** argv) { int err = 0; FILE* stat_log; struct id_pair_t* pids; - struct cpu_time_t **prev, **now; - + struct task_cputime_t **prev_task, **now_task; + struct sys_cputime_t *prev_sys, *now_sys; + struct record_t* rec; static const struct argp argp = { .options = opts, .parser = parse_arg, @@ -591,10 +589,13 @@ int main(int argc, char** argv) { goto cleanup; } + rec = calloc(1, sizeof(struct record_t)); pids = calloc(pidmax, sizeof(struct id_pair_t)); - prev = calloc(pidmax, sizeof(struct cpu_time_t*)); - now = calloc(pidmax, sizeof(struct cpu_time_t*)); - if (!prev || !now) { + prev_task = calloc(pidmax, sizeof(struct task_cputime_t*)); + now_task = calloc(pidmax, sizeof(struct task_cputime_t*)); + prev_sys = calloc(1, sizeof(struct sys_cputime_t)); + now_sys = calloc(1, sizeof(struct sys_cputime_t)); + if (!prev_task || !now_task) { err = errno; fprintf(stderr, "Failed calloc prev and now\n"); goto cleanup; @@ -608,18 +609,7 @@ int main(int argc, char** argv) { goto cleanup; } -/* debug for test the program performance */ -#ifdef DEBUG - FILE* debug_fp = fopen(DEBUG_LOG, "w"); - if (!debug_fp) fprintf(stderr, "Failed open debug log file.\n"); -#endif - while (env.nr_iter--) { -#ifdef DEBUG - struct timeval start, end; - err = gettimeofday(&start, 0); - if (err) fprintf(stderr, "Failed get time.\n"); -#endif /* get all process now */ u_int64_t proc_num; err = read_all_pids(pids, &proc_num); @@ -627,51 +617,43 @@ int main(int argc, char** argv) { fprintf(stderr, "Failed read all pids.\n"); goto cleanup; } - struct record_t** records = calloc(proc_num, sizeof(struct recotd_t*)); + rec->tasks = calloc(proc_num, sizeof(struct task_record_t*)); /* if prev process info exist produce record*/ - err = make_records(pids, proc_num, &records, prev, now); + err = make_records(pids, proc_num, rec, prev_task, now_task, prev_sys, now_sys); if (err) { fprintf(stderr, "Failed make records.\n"); goto cleanup; } /* sort record by sort type */ - sort_records(records, proc_num, env.rec_sort); + sort_records(rec, proc_num, env.rec_sort); /* output record */ - output(records, proc_num, stat_log); + output(rec, proc_num, stat_log); - free_records(records, proc_num); + free_records(rec, proc_num); /* update old info and free nonexist process info */ - now_to_prev(pids, proc_num, pidmax, prev, now); - -#ifdef DEBUG - err = gettimeofday(&end, 0); - if (err) fprintf(stderr, "Failed get time.\n"); - suseconds_t interval = end.tv_usec - start.tv_usec; - fprintf(debug_fp, "scan %d process, time=%d us(%.3f ms)\n", proc_num, interval, - (double)interval / 1000); - fflush(debug_fp); -#endif + now_to_prev(pids, proc_num, pidmax, prev_task, now_task, prev_sys, now_sys); + if (env.nr_iter) sleep(env.delay); } cleanup: if (pids) free(pids); u_int64_t i; - if (prev) { + if (prev_task) { for (0; i < pidmax; i++) { - if (prev[i]) free(prev[i]); + if (prev_task[i]) free(prev_task[i]); } - free(prev); + free(prev_task); } - if (now) { + if (now_task) { for (i = 0; i < pidmax; i++) { - if (now[i]) free(now[i]); + if (now_task[i]) free(now_task[i]); } - free(now); + free(now_task); } if (stat_log) fclose(stat_log); diff --git a/source/tools/detect/sched/tasktop/tasktop.h b/source/tools/detect/sched/tasktop/tasktop.h new file mode 100644 index 00000000..ccc172be --- /dev/null +++ b/source/tools/detect/sched/tasktop/tasktop.h @@ -0,0 +1,89 @@ +// #define DEBUG 1 +#define FILE_PATH_LEN 256 +#define MAX_COMM_LEN 16 +#define PEROID 3 +#define LIMIT 20 +#define CPU_NAME_LEN 8 +#define BUF_SIZE 512 +#define DEBUG_LOG "./log/debug.log" +#define PIDMAX_PATH "/proc/sys/kernel/pid_max" +#define PROC_STAT_PATH "/proc/stat" + +enum sort_type { SORT_SYSTEM, SORT_USER, SORT_CPU }; + +struct id_pair_t { + pid_t pid; + pid_t tid; +}; + +struct proc_stat_t { + int pid; + char comm[16]; + char state; + int ppid; + int pgrp; + int session; + int tty_nr; + int tpgid; + unsigned int flags; + u_int64_t minflt; + u_int64_t cminflt; + u_int64_t majflt; + u_int64_t cmajflt; + u_int64_t utime; + u_int64_t stime; + int64_t cutime; + int64_t cstime; + int64_t priority; + int64_t nice; + int64_t num_threads; + int64_t itrealvalue; + unsigned long long starttime; +}; + +struct task_cputime_t { + int pid; + int ppid; + char comm[MAX_COMM_LEN]; + u_int64_t stime; + u_int64_t utime; + u_int64_t starttime; +}; + +struct sys_cputime_t { + char cpu[CPU_NAME_LEN]; + long usr; + long nice; + long sys; + long idle; + long iowait; + long irq; + long softirq; + long steal; + long guest; + long guest_nice; +}; + +struct task_record_t { + u_int64_t pid; + u_int64_t ppid; + char comm[MAX_COMM_LEN]; + time_t runtime; + double system_cpu_rate; + double user_cpu_rate; + double all_cpu_rate; +}; + +struct sys_record_t { + double usr; + double sys; + double iowait; + int nr_R; + int nr_D; + int nr_fork; +}; + +struct record_t { + struct task_record_t **tasks; + struct sys_record_t sys; +}; \ No newline at end of file -- Gitee From 3f9905f9f06e6a192c3d4a2345d59435256c1c60 Mon Sep 17 00:00:00 2001 From: zoutao Date: Sat, 6 May 2023 18:09:41 +0800 Subject: [PATCH 4/6] tasktop:add system laod metric --- source/tools/detect/sched/tasktop/Makefile | 10 +- .../detect/sched/tasktop/bpf/tasktop.bpf.c | 74 +++++++++++ source/tools/detect/sched/tasktop/procstate.c | 57 +++++++++ source/tools/detect/sched/tasktop/procstate.h | 26 ++++ source/tools/detect/sched/tasktop/tasktop.c | 117 +++++++++++++----- source/tools/detect/sched/tasktop/tasktop.h | 14 ++- .../sched/tasktop/test_smalltask/test.c | 52 ++++++++ 7 files changed, 311 insertions(+), 39 deletions(-) create mode 100644 source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c create mode 100644 source/tools/detect/sched/tasktop/procstate.c create mode 100644 source/tools/detect/sched/tasktop/procstate.h create mode 100644 source/tools/detect/sched/tasktop/test_smalltask/test.c diff --git a/source/tools/detect/sched/tasktop/Makefile b/source/tools/detect/sched/tasktop/Makefile index 3d3a2e79..a47b255e 100644 --- a/source/tools/detect/sched/tasktop/Makefile +++ b/source/tools/detect/sched/tasktop/Makefile @@ -1,6 +1,8 @@ -target := tasktop -mods := tasktop.o -# LDFLAGS += -lpthread +newdirs := $(shell find ./ -type d) + +bpfsrcs := $(wildcard bpf/*.bpf.c) +csrcs := $(wildcard *.c) +target := tasktop -include $(SRC)/mk/csrc.mk \ No newline at end of file +include $(SRC)/mk/bpf.mk \ No newline at end of file diff --git a/source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c b/source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c new file mode 100644 index 00000000..17ce2788 --- /dev/null +++ b/source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, u32); + __type(value, u64); +} fork SEC(".maps"); + +// struct bpf_map_def SEC("maps") fork_counter = { +// .type = BPF_MAP_TYPE_HASH, +// .key_size = sizeof(int), +// .value_size = sizeof(int), +// .max_entries = 1, +// }; + +struct trace_event_sys_enter_vfork_args { + struct trace_entry ent; +}; + +struct trace_event_sys_enter_fork_args { + struct trace_entry ent; +}; + +struct trace_event_sys_enter_clone_args { + struct trace_entry ent; +}; + +struct trace_event_sched_process_fork_args { + struct trace_entry ent; +}; + +static void record() { + u32 key = 0; + u64 val = 1; + u64 *value; + + value = bpf_map_lookup_elem(&fork, &key); + if (value) { + __sync_fetch_and_add(value, 1); + } else { + bpf_map_update_elem(&fork, &key, &val, BPF_ANY); + } +} + +SEC("tp/syscalls/sys_enter_vfork") +int handle__sys_enter_vfork(struct trace_event_sys_enter_vfork_args *ctx) { + record(); + return 0; +} + +SEC("tp/syscalls/sys_enter_fork") +int handle__sys_enter_fork(struct trace_event_sys_enter_fork_args *ctx) { + record(); + return 0; +} + +// SEC("tp/syscalls/sys_enter_clone") +// int handle__sys_enter_clone(struct trace_event_sys_enter_fork_args *ctx) { +// record(); +// return 0; +// } + +// SEC("tp/sched/sched_process_fork") +// int handle__sched_process_fork(struct trace_event_sched_process_fork_args *ctx) { +// record(); +// return 0; +// } + +char LICENSE[] SEC("license") = "GPL"; diff --git a/source/tools/detect/sched/tasktop/procstate.c b/source/tools/detect/sched/tasktop/procstate.c new file mode 100644 index 00000000..a9603f06 --- /dev/null +++ b/source/tools/detect/sched/tasktop/procstate.c @@ -0,0 +1,57 @@ +#include +#include +#include + +#include "procstate.h" +#include "tasktop.h" + +double d_placeholder; +int i_placeholder; + +int runnable_proc(struct sys_record_t *sys) { + struct loadavg_t avg; + int err = 0; + FILE *fp = fopen(LOADAVG_PATH, "r"); + if (!fp) { + fprintf(stderr, "Failed open %s.", LOADAVG_PATH); + err = errno; + return err; + } + + fscanf(fp, "%f %f %f %d/%d %ld", &avg.load1, &avg.load5, &avg.load15, &avg.nr_running, + &avg.nr_threads, &avg.new_pid); + + if (avg.nr_running > 0) avg.nr_running--; + + sys->load1 = avg.load1; + sys->nr_R = avg.nr_running; + // printf("load1 = %.2f load5 = %.2f load15 = %.2f\n", avg.load1, avg.load5, avg.load15); + return err; +} + +int unint_proc(struct sys_record_t *sys) { + int err = 0; + FILE *fp; + long long total_unint = 0, nr_unint; + + char line[1024]; + + if ((fp = fopen(SCHED_DEBUG_PATH, "r")) == NULL) { + err = -errno; + fprintf(stderr, "Failed open %s\n", SCHED_DEBUG_PATH); + return err; + } + + while (fgets(line, 1024, fp) != NULL) { + if (!strncmp(line, " .nr_uninterruptible", 21)) { + sscanf(line + 35, "%lld", &nr_unint); + // printf("read nr_unint=%lld\n", nr_unint); + total_unint += nr_unint; + } + } + if (total_unint < 0) total_unint = 0; + + sys->nr_D = total_unint; + if (fclose(fp)) fprintf(stderr, "Failed fclose %s.\n", SCHED_DEBUG_PATH); + return err; +} \ No newline at end of file diff --git a/source/tools/detect/sched/tasktop/procstate.h b/source/tools/detect/sched/tasktop/procstate.h new file mode 100644 index 00000000..abaf44a7 --- /dev/null +++ b/source/tools/detect/sched/tasktop/procstate.h @@ -0,0 +1,26 @@ +#ifndef __PROCSTATE_H +#define __PROCSTATE_H + +#include "tasktop.h" + +#define LOADAVG_PATH "/proc/loadavg" +#define SCHED_DEBUG_PATH "/proc/sched_debug" + +struct proc_state_t { + int nr_runnable; + int nr_unint; +}; + +struct loadavg_t { + float load1; + float load5; + float load15; + int nr_running; + int nr_threads; + long new_pid; +}; + +int runnable_proc(struct sys_record_t *sys); +int unint_proc(struct sys_record_t *sys); + +#endif \ No newline at end of file diff --git a/source/tools/detect/sched/tasktop/tasktop.c b/source/tools/detect/sched/tasktop/tasktop.c index 189010a8..9e05821f 100644 --- a/source/tools/detect/sched/tasktop/tasktop.c +++ b/source/tools/detect/sched/tasktop/tasktop.c @@ -7,11 +7,16 @@ #include #include #include +#include #include #include #include #include #include "tasktop.h" +#include +#include /* bpf_obj_pin */ +#include "procstate.h" +#include "bpf/tasktop.skel.h" char log_dir[FILE_PATH_LEN] = "/var/log/sysak/tasktop"; char default_log_path[FILE_PATH_LEN] = "/var/log/sysak/tasktop/tasktop.log"; @@ -165,7 +170,6 @@ static error_t parse_arg(int key, char* arg, struct argp_state* state) { static int read_btime() { int err = 0; char buf[BUF_SIZE]; - char* endptr; long val; FILE* fp = fopen(PROC_STAT_PATH, "r"); if (!fp) { @@ -206,9 +210,6 @@ int swap(void* lhs, void* rhs, size_t sz) { static int read_stat(struct sys_cputime_t* prev_sys, struct sys_cputime_t* now_sys, struct sys_record_t* sys_rec) { int err = 0; - char buf[BUF_SIZE]; - char* endptr; - long val; FILE* fp = fopen(PROC_STAT_PATH, "r"); if (!fp) { fprintf(stderr, "Failed open stat file.\n"); @@ -217,9 +218,9 @@ static int read_stat(struct sys_cputime_t* prev_sys, struct sys_cputime_t* now_s } /*now only read first line, maybe future will read more info*/ - fscanf(fp, "%s %d %d %d %d %d %d %d %d %d %d\n", now_sys->cpu, &now_sys->usr, &now_sys->nice, - &now_sys->sys, &now_sys->idle, &now_sys->iowait, &now_sys->irq, &now_sys->softirq, - &now_sys->steal, &now_sys->guest, &now_sys->guest_nice); + fscanf(fp, "%s %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", now_sys->cpu, &now_sys->usr, + &now_sys->nice, &now_sys->sys, &now_sys->idle, &now_sys->iowait, &now_sys->irq, + &now_sys->softirq, &now_sys->steal, &now_sys->guest, &now_sys->guest_nice); if (prev_sys->usr == 0) goto cleanup; int now_time = now_sys->usr + now_sys->sys + now_sys->nice + now_sys->idle + now_sys->iowait + @@ -252,7 +253,7 @@ static u_int64_t read_pid_max() { return err; } - fscanf(fp, "%ul", &pidmax); + fscanf(fp, "%lu", &pidmax); if (fp) fclose(fp); return err; @@ -264,7 +265,6 @@ static int read_all_pids(struct id_pair_t* pids, u_int64_t* num) { DIR* dir = NULL; DIR* task_dir = NULL; u_int64_t proc_num = 0; - char* endptr; struct dirent* proc_de = NULL; struct dirent* task_de = NULL; long val; @@ -289,7 +289,7 @@ static int read_all_pids(struct id_pair_t* pids, u_int64_t* num) { pids[proc_num++].tid = -1; } else { char taskpath[FILE_PATH_LEN]; - snprintf(taskpath, FILE_PATH_LEN, "/proc/%ld/task", pid); + snprintf(taskpath, FILE_PATH_LEN, "/proc/%d/task", pid); task_dir = opendir(taskpath); if (!task_dir) { if (errno == ENOENT) { @@ -436,7 +436,7 @@ static void sort_records(struct record_t* rec, int proc_num, enum sort_type sort break; default: fprintf(stderr, "Unknown SORT_TYPE\n"); - break; + return; } if (lth < rth) { @@ -449,7 +449,7 @@ static void sort_records(struct record_t* rec, int proc_num, enum sort_type sort static void output(struct record_t* rec, int proc_num, FILE* dest) { struct task_record_t** records = rec->tasks; - system("clear"); + // system("clear"); time_t now = time(0); struct tm* t; t = gmtime(&now); @@ -457,10 +457,10 @@ static void output(struct record_t* rec, int proc_num, FILE* dest) { int i; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", t); - fprintf(dest, "%8s %6s %6s %6s %6s %6s %6s \n", "System", "usr", "sys", "iowait", "R", "D", - "fork"); - fprintf(dest, "%8s %6.1f %6.1f %6d %6d %6d\n", "", rec->sys.usr, rec->sys.sys, - rec->sys.iowait, rec->sys.nr_R, rec->sys.nr_D, rec->sys.nr_fork); + fprintf(dest, "%8s %6s %6s %6s %6s %6s %6s %6s \n", "System", "usr", "sys", "iowait", "load1", + "R", "D", "fork"); + fprintf(dest, "%8s %6.1f %6.1f %6.1f %6.1f %6d %6d %6d\n", "", rec->sys.usr, rec->sys.sys, + rec->sys.iowait, rec->sys.load1, rec->sys.nr_R, rec->sys.nr_D, rec->sys.nr_fork); for (i = 0; i < proc_num; i++) { if (!records[i]) break; @@ -472,21 +472,13 @@ static void output(struct record_t* rec, int proc_num, FILE* dest) { } if (i >= env.limit) break; - fprintf(dest, "%18s %6d %6d %10d %6.1f %6.1f %6.1f\n", records[i]->comm, records[i]->pid, + fprintf(dest, "%18s %6d %6d %10ld %6.1f %6.1f %6.1f\n", records[i]->comm, records[i]->pid, records[i]->ppid, records[i]->runtime, records[i]->user_cpu_rate, records[i]->system_cpu_rate, records[i]->all_cpu_rate); } fflush(dest); } -static void clean_prev_table(int pidmax, struct task_cputime_t** prev, - struct task_cputime_t** now) { - int i; - for (i = 0; i < pidmax; i++) { - if (prev[i]) free(prev[i]); - } -} - static void now_to_prev(struct id_pair_t* pids, int proc_num, int pidmax, struct task_cputime_t** prev_task, struct task_cputime_t** now_task, struct sys_cputime_t* prev_sys, struct sys_cputime_t* now_sys) { @@ -558,13 +550,47 @@ static FILE* open_logfile() { return stat_log; } +static int libbpf_print_fn(enum libbpf_print_level level, const char* format, va_list args) { + return vfprintf(stderr, format, args); +} + +static int bump_memlock_rlimit(void) { + struct rlimit rlim_new = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + return setrlimit(RLIMIT_MEMLOCK, &rlim_new); +} + +static int look_fork(int mfd, struct sys_record_t* sys_rec) { + static long local_prev_val = 0; + int err = 0; + int key = 0; + long val = 0; + err = bpf_map_lookup_elem(mfd, &key, &val); + if (err) { + // fprintf(stderr, "Failed read fork from map.\n"); + return err; + } + // printf("fork times = %d\n", val); + sys_rec->nr_fork = val - local_prev_val; + // sys_rec->nr_fork = val; + local_prev_val = val; + return err; +} + int main(int argc, char** argv) { int err = 0; - FILE* stat_log; - struct id_pair_t* pids; - struct task_cputime_t **prev_task, **now_task; - struct sys_cputime_t *prev_sys, *now_sys; - struct record_t* rec; + int map_fd = -1; + FILE* stat_log = 0; + struct tasktop_bpf* skel = 0; + struct id_pair_t* pids = 0; + struct task_cputime_t **prev_task = 0, **now_task = 0; + struct sys_cputime_t *prev_sys = 0, *now_sys = 0; + struct record_t* rec = 0; + + /* parse args */ static const struct argp argp = { .options = opts, .parser = parse_arg, @@ -577,6 +603,10 @@ int main(int argc, char** argv) { goto cleanup; } + libbpf_set_print(libbpf_print_fn); + bump_memlock_rlimit(); + + /* init pid_max and btime */ err = read_pid_max(); if (err) { fprintf(stderr, "Failed read pid max.\n"); @@ -602,14 +632,36 @@ int main(int argc, char** argv) { } prepare_directory(log_dir); - stat_log = open_logfile(); if (!stat_log) { fprintf(stderr, "Failed open stat log file.\n"); goto cleanup; } + skel = tasktop_bpf__open(); + if (!skel) { + err = 1; + fprintf(stderr, "Failed to open BPF skeleton\n"); + goto cleanup; + } + + err = tasktop_bpf__load(skel); + if (err) { + fprintf(stderr, "Failed to load BPF skeleton\n"); + goto cleanup; + } + + map_fd = bpf_map__fd(skel->maps.fork); + err = tasktop_bpf__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } + while (env.nr_iter--) { + look_fork(map_fd, &rec->sys); + runnable_proc(&rec->sys); + unint_proc(&rec->sys); /* get all process now */ u_int64_t proc_num; err = read_all_pids(pids, &proc_num); @@ -640,10 +692,11 @@ int main(int argc, char** argv) { } cleanup: + tasktop_bpf__destroy(skel); if (pids) free(pids); u_int64_t i; if (prev_task) { - for (0; i < pidmax; i++) { + for (i = 0; i < pidmax; i++) { if (prev_task[i]) free(prev_task[i]); } free(prev_task); diff --git a/source/tools/detect/sched/tasktop/tasktop.h b/source/tools/detect/sched/tasktop/tasktop.h index ccc172be..2fcdb4bc 100644 --- a/source/tools/detect/sched/tasktop/tasktop.h +++ b/source/tools/detect/sched/tasktop/tasktop.h @@ -1,4 +1,8 @@ // #define DEBUG 1 +#ifndef __TASKTOP_H +#define __TASKTOP_H +#include + #define FILE_PATH_LEN 256 #define MAX_COMM_LEN 16 #define PEROID 3 @@ -65,8 +69,8 @@ struct sys_cputime_t { }; struct task_record_t { - u_int64_t pid; - u_int64_t ppid; + int pid; + int ppid; char comm[MAX_COMM_LEN]; time_t runtime; double system_cpu_rate; @@ -74,10 +78,12 @@ struct task_record_t { double all_cpu_rate; }; + struct sys_record_t { double usr; double sys; double iowait; + float load1; int nr_R; int nr_D; int nr_fork; @@ -86,4 +92,6 @@ struct sys_record_t { struct record_t { struct task_record_t **tasks; struct sys_record_t sys; -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/source/tools/detect/sched/tasktop/test_smalltask/test.c b/source/tools/detect/sched/tasktop/test_smalltask/test.c new file mode 100644 index 00000000..d6d25ee8 --- /dev/null +++ b/source/tools/detect/sched/tasktop/test_smalltask/test.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include +#include + +void loop_fork() { + while (1) { + int pid[128]; + for (int i = 0; i < 128; i++) { + if ((pid[i] = fork()) == 0) { + exit(0); + } + // printf("fork.\n"); + } + + for (int i = 0; i < 128; i++) { + waitpid(pid[i], 0, 0); + } + } +} + +void *do_nothing(void *arg) { return 0; } + +void loop_clone() { + while (1) { + pthread_t pid[128]; + for (int i = 0; i < 128; i++) { + pthread_create(&pid[i], 0, do_nothing, 0); + // printf("fork.\n"); + } + + for (int i = 0; i < 128; i++) { + pthread_join(pid[i], 0); + } + } +} + +int main(int argc, char **argv) { + if (argc != 2) { + printf("usage: test clone or test fork\n"); + return -1; + } + + if (!strcmp(argv[1], "clone")) { + loop_clone(); + } else if (!strcmp(argv[1], "fork")) { + loop_fork(); + } +} \ No newline at end of file -- Gitee From 34927bbd347ad0b459fc739f58840ffbb127e78b Mon Sep 17 00:00:00 2001 From: zoutao Date: Mon, 8 May 2023 19:27:56 +0800 Subject: [PATCH 5/6] tasktop:add new function,ffind process with most fork in peroid --- .../detect/sched/tasktop/bpf/tasktop.bpf.c | 99 +++++++++--------- source/tools/detect/sched/tasktop/common.h | 10 ++ source/tools/detect/sched/tasktop/tasktop.c | 60 +++++++---- source/tools/detect/sched/tasktop/tasktop.h | 3 + .../detect/sched/tasktop/tasktopSelftest/test | Bin 0 -> 8528 bytes .../sched/tasktop/tasktopSelftest/test.c | 55 ++++++++++ 6 files changed, 161 insertions(+), 66 deletions(-) create mode 100644 source/tools/detect/sched/tasktop/common.h create mode 100755 source/tools/detect/sched/tasktop/tasktopSelftest/test create mode 100644 source/tools/detect/sched/tasktop/tasktopSelftest/test.c diff --git a/source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c b/source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c index 17ce2788..384cda8d 100644 --- a/source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c +++ b/source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c @@ -4,71 +4,76 @@ #include #include +#include "../common.h" + +#define MAX_PID + +#define _(P) \ + ({ \ + typeof(P) val = 0; \ + bpf_probe_read(&val, sizeof(val), &P); \ + val; \ + }) struct { __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 4096); + __type(key, u32); + __type(value, struct proc_fork_info_t); +} fork_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(max_entries, 1); __type(key, u32); __type(value, u64); -} fork SEC(".maps"); - -// struct bpf_map_def SEC("maps") fork_counter = { -// .type = BPF_MAP_TYPE_HASH, -// .key_size = sizeof(int), -// .value_size = sizeof(int), -// .max_entries = 1, -// }; - -struct trace_event_sys_enter_vfork_args { - struct trace_entry ent; -}; - -struct trace_event_sys_enter_fork_args { - struct trace_entry ent; -}; - -struct trace_event_sys_enter_clone_args { - struct trace_entry ent; -}; +} cnt_map SEC(".maps"); struct trace_event_sched_process_fork_args { struct trace_entry ent; + char parent_comm[16]; + pid_t parent_pid; + char child_comm[16]; + pid_t child_pid; }; -static void record() { - u32 key = 0; - u64 val = 1; - u64 *value; +static void update_cnt_map() { + u32 zero = 0; + u64 *value = 0; - value = bpf_map_lookup_elem(&fork, &key); + value = bpf_map_lookup_elem(&cnt_map, &zero); if (value) { - __sync_fetch_and_add(value, 1); - } else { - bpf_map_update_elem(&fork, &key, &val, BPF_ANY); + (*value)++; } } -SEC("tp/syscalls/sys_enter_vfork") -int handle__sys_enter_vfork(struct trace_event_sys_enter_vfork_args *ctx) { - record(); - return 0; +static void update_fork_map() { + u32 ppid, pid, zero = 0; + struct task_struct *task; + struct proc_fork_info_t *prev_info; + struct proc_fork_info_t new_info; + + task = (void *)bpf_get_current_task(); + pid = _(task->pid); + ppid = BPF_CORE_READ(task, parent, pid); + + prev_info = bpf_map_lookup_elem(&fork_map, &pid); + if (prev_info) { + prev_info->fork++; + } else { + __builtin_memset(&new_info, 0, sizeof(struct proc_fork_info_t)); + new_info.fork = 1; + new_info.pid = pid; + new_info.ppid = ppid; + bpf_get_current_comm(&new_info.comm, sizeof(new_info.comm)); + bpf_map_update_elem(&fork_map, &pid, &new_info, BPF_ANY); + } } -SEC("tp/syscalls/sys_enter_fork") -int handle__sys_enter_fork(struct trace_event_sys_enter_fork_args *ctx) { - record(); +SEC("tp/sched/sched_process_fork") +int handle__sched_process_fork(struct trace_event_sched_process_fork_args *ctx) { + update_cnt_map(); + update_fork_map(); return 0; } -// SEC("tp/syscalls/sys_enter_clone") -// int handle__sys_enter_clone(struct trace_event_sys_enter_fork_args *ctx) { -// record(); -// return 0; -// } - -// SEC("tp/sched/sched_process_fork") -// int handle__sched_process_fork(struct trace_event_sched_process_fork_args *ctx) { -// record(); -// return 0; -// } - char LICENSE[] SEC("license") = "GPL"; diff --git a/source/tools/detect/sched/tasktop/common.h b/source/tools/detect/sched/tasktop/common.h new file mode 100644 index 00000000..78f250a4 --- /dev/null +++ b/source/tools/detect/sched/tasktop/common.h @@ -0,0 +1,10 @@ +#ifndef TASKTOP_COMMON_H +#define TASKTOP_COMMON_H + +struct proc_fork_info_t { + pid_t pid; + pid_t ppid; + u_int64_t fork; + char comm[16]; +}; +#endif \ No newline at end of file diff --git a/source/tools/detect/sched/tasktop/tasktop.c b/source/tools/detect/sched/tasktop/tasktop.c index 9e05821f..e5683940 100644 --- a/source/tools/detect/sched/tasktop/tasktop.c +++ b/source/tools/detect/sched/tasktop/tasktop.c @@ -12,11 +12,12 @@ #include #include #include -#include "tasktop.h" #include #include /* bpf_obj_pin */ -#include "procstate.h" #include "bpf/tasktop.skel.h" +#include "procstate.h" +#include "tasktop.h" +#include "common.h" char log_dir[FILE_PATH_LEN] = "/var/log/sysak/tasktop"; char default_log_path[FILE_PATH_LEN] = "/var/log/sysak/tasktop/tasktop.log"; @@ -455,12 +456,14 @@ static void output(struct record_t* rec, int proc_num, FILE* dest) { t = gmtime(&now); char time_str[BUF_SIZE]; int i; + struct proc_fork_info_t* info = &(rec->sys.most_fork_info); strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", t); fprintf(dest, "%8s %6s %6s %6s %6s %6s %6s %6s \n", "System", "usr", "sys", "iowait", "load1", "R", "D", "fork"); - fprintf(dest, "%8s %6.1f %6.1f %6.1f %6.1f %6d %6d %6d\n", "", rec->sys.usr, rec->sys.sys, + fprintf(dest, "%8s %6.1f %6.1f %6.1f %6.1f %6d %6d %6d ", "", rec->sys.usr, rec->sys.sys, rec->sys.iowait, rec->sys.load1, rec->sys.nr_R, rec->sys.nr_D, rec->sys.nr_fork); + fprintf(dest, ":%s(%d) ppid=%d cnt=%lu \n", info->comm, info->pid, info->ppid, info->fork); for (i = 0; i < proc_num; i++) { if (!records[i]) break; @@ -563,26 +566,41 @@ static int bump_memlock_rlimit(void) { return setrlimit(RLIMIT_MEMLOCK, &rlim_new); } -static int look_fork(int mfd, struct sys_record_t* sys_rec) { - static long local_prev_val = 0; - int err = 0; - int key = 0; - long val = 0; - err = bpf_map_lookup_elem(mfd, &key, &val); - if (err) { - // fprintf(stderr, "Failed read fork from map.\n"); - return err; +static int look_fork(int cnt_map_fd, int fork_map_fd, struct sys_record_t* sys_rec) { + int fd; + int err; + u_int64_t total = 0; + u_int64_t lookup_key = -1, next_key; + struct proc_fork_info_t info; + + fd = fork_map_fd; + int max_fork = 0; + while (!bpf_map_get_next_key(fd, &lookup_key, &next_key)) { + err = bpf_map_lookup_elem(fd, &next_key, &info); + + err = bpf_map_delete_elem(fd, &next_key); + if (err < 0) { + fprintf(stderr, "failed to delete elem: %d\n", err); + return -1; + } + lookup_key = next_key; + + if (!next_key) continue; + + total = total + info.fork; // for debug + + if (max_fork < info.fork) { + max_fork = info.fork; + sys_rec->most_fork_info = info; + } } - // printf("fork times = %d\n", val); - sys_rec->nr_fork = val - local_prev_val; - // sys_rec->nr_fork = val; - local_prev_val = val; + sys_rec->nr_fork = total; return err; } int main(int argc, char** argv) { int err = 0; - int map_fd = -1; + int cnt_map_fd = -1, fork_map_fd = -1; FILE* stat_log = 0; struct tasktop_bpf* skel = 0; struct id_pair_t* pids = 0; @@ -651,7 +669,8 @@ int main(int argc, char** argv) { goto cleanup; } - map_fd = bpf_map__fd(skel->maps.fork); + cnt_map_fd = bpf_map__fd(skel->maps.cnt_map); + fork_map_fd = bpf_map__fd(skel->maps.fork_map); err = tasktop_bpf__attach(skel); if (err) { fprintf(stderr, "Failed to attach BPF skeleton\n"); @@ -659,9 +678,10 @@ int main(int argc, char** argv) { } while (env.nr_iter--) { - look_fork(map_fd, &rec->sys); + look_fork(cnt_map_fd, fork_map_fd, &rec->sys); runnable_proc(&rec->sys); unint_proc(&rec->sys); + /* get all process now */ u_int64_t proc_num; err = read_all_pids(pids, &proc_num); @@ -669,6 +689,7 @@ int main(int argc, char** argv) { fprintf(stderr, "Failed read all pids.\n"); goto cleanup; } + rec->tasks = calloc(proc_num, sizeof(struct task_record_t*)); /* if prev process info exist produce record*/ err = make_records(pids, proc_num, rec, prev_task, now_task, prev_sys, now_sys); @@ -693,6 +714,7 @@ int main(int argc, char** argv) { cleanup: tasktop_bpf__destroy(skel); + if (pids) free(pids); u_int64_t i; if (prev_task) { diff --git a/source/tools/detect/sched/tasktop/tasktop.h b/source/tools/detect/sched/tasktop/tasktop.h index 2fcdb4bc..e96657d9 100644 --- a/source/tools/detect/sched/tasktop/tasktop.h +++ b/source/tools/detect/sched/tasktop/tasktop.h @@ -2,6 +2,8 @@ #ifndef __TASKTOP_H #define __TASKTOP_H #include +#include "common.h" + #define FILE_PATH_LEN 256 #define MAX_COMM_LEN 16 @@ -87,6 +89,7 @@ struct sys_record_t { int nr_R; int nr_D; int nr_fork; + struct proc_fork_info_t most_fork_info; }; struct record_t { diff --git a/source/tools/detect/sched/tasktop/tasktopSelftest/test b/source/tools/detect/sched/tasktop/tasktopSelftest/test new file mode 100755 index 0000000000000000000000000000000000000000..01333afa8e8b448cf3ccc881ab436b8c3a54eb0e GIT binary patch literal 8528 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 +#include +#include +#include +#include +#include +#include + +void loop_fork() { + while (1) { + int pid[128]; + for (int i = 0; i < 128; i++) { + if ((pid[i] = fork()) == 0) { + int a = 0; + int b = 1; + int c = a + b; + exit(0); + } + // printf("fork.\n"); + } + + for (int i = 0; i < 128; i++) { + waitpid(pid[i], 0, 0); + } + } +} + +void *do_nothing(void *arg) { return 0; } + +void loop_clone() { + while (1) { + pthread_t pid[128]; + for (int i = 0; i < 128; i++) { + pthread_create(&pid[i], 0, do_nothing, 0); + // printf("fork.\n"); + } + + for (int i = 0; i < 128; i++) { + pthread_join(pid[i], 0); + } + } +} + +int main(int argc, char **argv) { + if (argc != 2) { + printf("usage: test clone or test fork\n"); + return -1; + } + + if (!strcmp(argv[1], "clone")) { + loop_clone(); + } else if (!strcmp(argv[1], "fork")) { + loop_fork(); + } +} \ No newline at end of file -- Gitee From 6cc2205f2282000ed603874b009b30449289f2aa Mon Sep 17 00:00:00 2001 From: zoutao Date: Tue, 9 May 2023 10:20:15 +0800 Subject: [PATCH 6/6] tasktop: fix output format --- source/tools/detect/sched/tasktop/tasktop.c | 8 ++++---- source/tools/detect/sched/tasktop/tasktop.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/source/tools/detect/sched/tasktop/tasktop.c b/source/tools/detect/sched/tasktop/tasktop.c index e5683940..e1c6dd6c 100644 --- a/source/tools/detect/sched/tasktop/tasktop.c +++ b/source/tools/detect/sched/tasktop/tasktop.c @@ -459,11 +459,11 @@ static void output(struct record_t* rec, int proc_num, FILE* dest) { struct proc_fork_info_t* info = &(rec->sys.most_fork_info); strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", t); - fprintf(dest, "%8s %6s %6s %6s %6s %6s %6s %6s \n", "System", "usr", "sys", "iowait", "load1", - "R", "D", "fork"); - fprintf(dest, "%8s %6.1f %6.1f %6.1f %6.1f %6d %6d %6d ", "", rec->sys.usr, rec->sys.sys, + fprintf(dest, "%8s %6s %6s %6s %6s %6s %6s %6s:%6s \n", "System", "usr", "sys", "iowait", + "load1", "R", "D", "fork", "proc"); + fprintf(dest, "%8s %6.1f %6.1f %6.1f %6.1f %6d %6d %6d", "", rec->sys.usr, rec->sys.sys, rec->sys.iowait, rec->sys.load1, rec->sys.nr_R, rec->sys.nr_D, rec->sys.nr_fork); - fprintf(dest, ":%s(%d) ppid=%d cnt=%lu \n", info->comm, info->pid, info->ppid, info->fork); + fprintf(dest, ": %s(%d) ppid=%d cnt=%lu \n", info->comm, info->pid, info->ppid, info->fork); for (i = 0; i < proc_num; i++) { if (!records[i]) break; diff --git a/source/tools/detect/sched/tasktop/tasktop.h b/source/tools/detect/sched/tasktop/tasktop.h index e96657d9..8d423433 100644 --- a/source/tools/detect/sched/tasktop/tasktop.h +++ b/source/tools/detect/sched/tasktop/tasktop.h @@ -15,7 +15,8 @@ #define PIDMAX_PATH "/proc/sys/kernel/pid_max" #define PROC_STAT_PATH "/proc/stat" -enum sort_type { SORT_SYSTEM, SORT_USER, SORT_CPU }; +enum sort_type { SORT_SYSTEM, +SORT_USER, SORT_CPU }; struct id_pair_t { pid_t pid; -- Gitee