diff --git a/source/tools/detect/sched/tasktop/Makefile b/source/tools/detect/sched/tasktop/Makefile index 3d3a2e79fe26f90b3c69ccf14112b85427e7a2fb..a47b255e78b15d8c2db5701813637978a044865a 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 0000000000000000000000000000000000000000..384cda8df50df6025669354dc1d04ebddc00052d --- /dev/null +++ b/source/tools/detect/sched/tasktop/bpf/tasktop.bpf.c @@ -0,0 +1,79 @@ +#include +#include +#include +#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); +} 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 update_cnt_map() { + u32 zero = 0; + u64 *value = 0; + + value = bpf_map_lookup_elem(&cnt_map, &zero); + if (value) { + (*value)++; + } +} + +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/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; +} + +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 0000000000000000000000000000000000000000..78f250a4cdc00e4fdf2e5d16afda9819a56868fe --- /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/procstate.c b/source/tools/detect/sched/tasktop/procstate.c new file mode 100644 index 0000000000000000000000000000000000000000..a9603f06aaecd8d8016029cb95c8a78a8a90e205 --- /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 0000000000000000000000000000000000000000..abaf44a78aa01572b52d49ae629e922e11dab601 --- /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 bd26b7cd1f04c171f6e9335cf6312e9466c643a8..e1c6dd6cecb6b58b2e1e3d1cabcbf433a5a39f07 100644 --- a/source/tools/detect/sched/tasktop/tasktop.c +++ b/source/tools/detect/sched/tasktop/tasktop.c @@ -7,20 +7,17 @@ #include #include #include +#include #include #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 +#include /* bpf_obj_pin */ +#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"; @@ -28,57 +25,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; @@ -225,7 +171,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) { @@ -250,18 +195,57 @@ 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); + + free(temp); -static void swap_record(struct record_t** lth, struct record_t** rth) { - struct record_t* tmp = *lth; - *lth = *rth; - *rth = tmp; + 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; + 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 %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 + + 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"); @@ -270,7 +254,7 @@ static u_int64_t read_pid_max() { return err; } - fscanf(fp, "%ul", &pidmax); + fscanf(fp, "%lu", &pidmax); if (fp) fclose(fp); return err; @@ -282,7 +266,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; @@ -307,7 +290,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) { @@ -346,11 +329,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 +345,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 +392,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 +409,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 +419,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) { @@ -453,25 +437,34 @@ static void sort_records(struct record_t** records, int proc_num, enum sort_type break; default: fprintf(stderr, "Unknown SORT_TYPE\n"); - break; + return; } 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) { - system("clear"); +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; 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:%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); + for (i = 0; i < proc_num; i++) { if (!records[i]) break; @@ -482,27 +475,21 @@ 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 %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 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]); - } -} - -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) { - 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 +499,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 +522,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]); @@ -561,12 +553,62 @@ 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 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; + } + } + sys_rec->nr_fork = total; + return err; +} + int main(int argc, char** argv) { int err = 0; - FILE* stat_log; - struct id_pair_t* pids; - struct cpu_time_t **prev, **now; + int cnt_map_fd = -1, fork_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, @@ -579,6 +621,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"); @@ -591,35 +637,51 @@ 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; } prepare_directory(log_dir); - stat_log = open_logfile(); if (!stat_log) { fprintf(stderr, "Failed open stat log file.\n"); 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 + 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; + } + + 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"); + goto cleanup; + } while (env.nr_iter--) { -#ifdef DEBUG - struct timeval start, end; - err = gettimeofday(&start, 0); - if (err) fprintf(stderr, "Failed get time.\n"); -#endif + 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); @@ -627,51 +689,46 @@ 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: + tasktop_bpf__destroy(skel); + if (pids) free(pids); u_int64_t i; - if (prev) { - for (0; i < pidmax; i++) { - if (prev[i]) free(prev[i]); + if (prev_task) { + for (i = 0; i < pidmax; 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 0000000000000000000000000000000000000000..8d423433d7dcd616d4ceaab501a307995bc1ad9a --- /dev/null +++ b/source/tools/detect/sched/tasktop/tasktop.h @@ -0,0 +1,101 @@ +// #define DEBUG 1 +#ifndef __TASKTOP_H +#define __TASKTOP_H +#include +#include "common.h" + + +#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 { + int pid; + int 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; + float load1; + int nr_R; + int nr_D; + int nr_fork; + struct proc_fork_info_t most_fork_info; +}; + +struct record_t { + struct task_record_t **tasks; + struct sys_record_t sys; +}; + +#endif \ No newline at end of file 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 Binary files /dev/null and b/source/tools/detect/sched/tasktop/tasktopSelftest/test differ diff --git a/source/tools/detect/sched/tasktop/tasktopSelftest/test.c b/source/tools/detect/sched/tasktop/tasktopSelftest/test.c new file mode 100644 index 0000000000000000000000000000000000000000..779ecc5a319276348bbd6795b1c46ca197066943 --- /dev/null +++ b/source/tools/detect/sched/tasktop/tasktopSelftest/test.c @@ -0,0 +1,55 @@ +#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) { + 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 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 0000000000000000000000000000000000000000..d6d25ee8642239a58710cab2709694cc78472ff0 --- /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