diff --git a/source/lib/Makefile b/source/lib/Makefile index 3a5ed8261bf05fb9113ab9d251e45661bd71d7ea..b957459bdb3f77fd4ec56bd44eae5181af76c6b8 100644 --- a/source/lib/Makefile +++ b/source/lib/Makefile @@ -13,6 +13,8 @@ ifeq ($(BUILD_LIBBPF), YES) endif clean: +ifeq ($(BUILD_KERNEL_MODULE), YES) make -C internal/kernel_module clean +endif make -C internal/ebpf/libbpf/src clean diff --git a/source/lib/internal/kernel_module/modules/sched/noschedule.c b/source/lib/internal/kernel_module/modules/sched/noschedule.c index 5043eba3b3e86703651dabc69f14a37ec868b7bf..9bae264932cd5308377383b4169294018ccffc7b 100644 --- a/source/lib/internal/kernel_module/modules/sched/noschedule.c +++ b/source/lib/internal/kernel_module/modules/sched/noschedule.c @@ -347,7 +347,7 @@ static void tracepoint_lookup(struct tracepoint *tp, void *priv) static int threshold_show(struct seq_file *m, void *ptr) { - seq_printf(m, "%llu\n", duration_threshold); + seq_printf(m, "%llu ms\n", duration_threshold/(1000*1000)); return 0; } @@ -543,12 +543,11 @@ static int stack_trace_show(struct seq_file *m, void *ptr) struct stack_entry *entry; entry = cpu_stack_trace->stack_entries + i; - seq_printf(m, "%*ccpu:%d\tCOMM: %s\tPID:%d\tDURATION:%lluus\tSTAMP:%llu\n", + seq_printf(m, "%*ccpu:%d\tcommand:%s\tpid:%d\tlatency:%lluus\tSTAMP:%llu\n", 5, ' ', cpu, cpu_stack_trace->comms[i], cpu_stack_trace->pids[i], cpu_stack_trace->duration[i] / (1000UL), - cpu_stack_trace->stamp[i] - ); + cpu_stack_trace->stamp[i]); seq_print_stack_trace(m, entry); seq_putc(m, '\n'); diff --git a/source/lib/internal/kernel_module/modules/sched/trace_irqoff.c b/source/lib/internal/kernel_module/modules/sched/trace_irqoff.c index b70c470a7ca91b393cfddca8f5a6aec83dfc0762..5602be1a7993a3440a3fa8754fe059a2044ec4f8 100644 --- a/source/lib/internal/kernel_module/modules/sched/trace_irqoff.c +++ b/source/lib/internal/kernel_module/modules/sched/trace_irqoff.c @@ -387,12 +387,12 @@ static void trace_latency_show_one(struct seq_file *m, void *v, bool hardirq) for (i = 0; i < nr_irqoff_trace; i++) { struct irqoff_trace *trace = stack_trace->trace + i; - seq_printf(m, "%*ccpu:%d\tCOMMAND:%s\tPID:%d\tLATENCY:%lu%s\tSTAMP:%llu\n", + seq_printf(m, "%*ccpu:%d\tcommand:%s\tpid:%d\tlatency:%lu%s\tSTAMP:%llu\n", 5, ' ', cpu, stack_trace->comms[i], stack_trace->pids[i], stack_trace->latency[i].nsecs / (1000 * 1000UL), stack_trace->latency[i].more ? "+ms" : "ms", - stack_trace->stamp[i] / 1000UL); + stack_trace->stamp[i]); seq_print_stack_trace(m, trace); seq_putc(m, '\n'); @@ -423,9 +423,9 @@ static int trace_latency_show(struct seq_file *m, void *v) static ssize_t trace_latency_store(void *priv, const char __user *buf, size_t count) { - unsigned long latency; + u64 latency; - if (kstrtoul_from_user(buf, count, 0, &latency)) + if (kstrtou64_from_user(buf, count, 0, &latency)) return -EINVAL; if (latency == 0) { @@ -439,7 +439,7 @@ static ssize_t trace_latency_store(void *priv, const char __user *buf, size_t co } else if (latency < (sampling_period << 1) / (1000 * 1000UL)) return -EINVAL; - trace_irqoff_latency = latency * 1000 * 1000UL; + trace_irqoff_latency = latency; return count; } diff --git a/source/lib/internal/kernel_module/modules/sched/trace_runqlat.c b/source/lib/internal/kernel_module/modules/sched/trace_runqlat.c index c3d86bd4bc0b8b13414110f989473db99516dab1..828c36d044547f119488e60a77cdc477aba63976 100644 --- a/source/lib/internal/kernel_module/modules/sched/trace_runqlat.c +++ b/source/lib/internal/kernel_module/modules/sched/trace_runqlat.c @@ -29,7 +29,8 @@ #define MAX_TRACE_ENTRY_TASKS \ (MAX_TRACE_ENTRIES * PER_TRACE_ENTRY_TASKS) -#define THRESHOLD_DEFAULT (20 * 1000 * 1000UL) +/* 20ms */ +#define THRESHOLD_DEFAULT (20*1000*1000UL) #define INVALID_PID -1 #define INVALID_CPU -1 @@ -57,6 +58,9 @@ struct task_entry { }; struct trace_entry { + int cpu; + pid_t pid; + char comm[TASK_COMM_LEN]; u64 latency; u64 rq_start; unsigned int nr_tasks; @@ -66,6 +70,7 @@ struct trace_entry { struct runqlat_info { int cpu; /* The target CPU */ pid_t pid; /* Trace this pid only */ + char comm[TASK_COMM_LEN]; /* target task's comm */ u64 rq_start; u64 run_start; u64 threshold; @@ -203,6 +208,9 @@ static bool record_task_commit(struct runqlat_info *info, u64 latency) if (latency >= info->threshold) { trace->latency = latency; trace->rq_start = info->rq_start; + trace->cpu = info->cpu; + trace->pid = info->pid; + strncpy(trace->comm, info->comm, TASK_COMM_LEN); info->nr_trace++; if (unlikely(info->nr_trace >= MAX_TRACE_ENTRIES)) { pr_info("BUG: MAX_TRACE_ENTRIES too low!"); @@ -374,9 +382,31 @@ static int trace_pid_show(struct seq_file *m, void *ptr) return 0; } +static struct task_struct *loc_find_get_task_by_vpid(int nr) +{ + struct pid * pid_obj; + struct task_struct *task; + + rcu_read_lock(); + pid_obj = find_vpid(nr); + if (!pid_obj) + goto fail; + + task = pid_task(pid_obj, PIDTYPE_PID); + if (!task) + goto fail; + + get_task_struct(task); + rcu_read_unlock(); + return task; +fail: + rcu_read_unlock(); + return NULL; +} static ssize_t trace_pid_store(void *priv, const char __user *buf, size_t count) { int pid; + struct task_struct *task = NULL; struct runqlat_info *info = priv; if (kstrtoint_from_user(buf, count, 0, &pid)) @@ -387,8 +417,11 @@ static ssize_t trace_pid_store(void *priv, const char __user *buf, size_t count) local_irq_disable(); arch_spin_lock(&info->lock); - if (info->pid == pid) + if (info->pid == pid) { + if (pid == INVALID_PID) + sysak_module_put(&runqlat_ref); goto unlock; + } if (pid != INVALID_PID) { @@ -398,12 +431,19 @@ static ssize_t trace_pid_store(void *priv, const char __user *buf, size_t count) MAX_TRACE_ENTRIES * sizeof(struct trace_entry) + MAX_TRACE_ENTRY_TASKS * sizeof(struct task_entry)); sysak_module_get(&runqlat_ref); - } else + } else { sysak_module_put(&runqlat_ref); - + } runqlat_info_reset(info); smp_wmb(); info->pid = pid; + task = loc_find_get_task_by_vpid(pid); + if (task) { + strncpy(info->comm, task->comm, TASK_COMM_LEN); + put_task_struct(task); + } else { + strncpy(info->comm, "NULL", 5); + } unlock: arch_spin_unlock(&info->lock); local_irq_enable(); @@ -417,7 +457,7 @@ static int threshold_show(struct seq_file *m, void *ptr) { struct runqlat_info *info = m->private; - seq_printf(m, "%llu\n", info->threshold); + seq_printf(m, "%llu ms\n", info->threshold/(1000*1000)); return 0; } @@ -450,18 +490,12 @@ static int runqlat_show(struct seq_file *m, void *ptr) for (i = 0; i < info->nr_trace; i++) { struct trace_entry *entry = info->trace_entries + i; - seq_printf(m, "%*clatency(us):%llu\trunqlen:%d\trqstart(us):%llu\n", 2, ' ', - entry->latency / 1000, entry->nr_tasks, - entry->rq_start / 1000); - - for (j = 0; j < entry->nr_tasks; j++) { - struct task_entry *task = entry->entries + j; - - seq_printf(m, "%*cCOMM:%s\tPID:%d\tRUNTIME(us):%llu\n", - 6, ' ', task->comm, task->pid, - task->runtime / 1000); - } - seq_putc(m, '\n'); + seq_printf(m, "%*ccpu:%d\tcommand:%s\tpid:%d\tlatency:%llums\tSTAMP:%llu\trunqlen:%d\n", + 5, ' ', entry->cpu, + entry->comm, entry->pid, + entry->latency/(1000*1000), + entry->rq_start, + entry->nr_tasks); } arch_spin_unlock(&info->lock); local_irq_enable(); diff --git a/source/tools/monitor/sched/runlatency/json_dump.c b/source/tools/monitor/sched/runlatency/json_dump.c index 904666c1eaa9420639332ebf8bc471b990b472f3..abc46c09e6858f49e71b5d782b20fd42f664b684 100644 --- a/source/tools/monitor/sched/runlatency/json_dump.c +++ b/source/tools/monitor/sched/runlatency/json_dump.c @@ -46,7 +46,7 @@ int clear_file(char *path) return size; } -int pasre_dump(char *file) +int parse_dump(char *file) { char *s; int ret; @@ -56,11 +56,17 @@ int pasre_dump(char *file) if (s == NULL) { return -ENOMEM; } + if (file) { outf = fopen(file, "a+"); - if (!outf) + if (!outf) { + ret = errno; fprintf(stderr, "%s :fopen %s\n", strerror(errno), file); + goto failed; + } + } else { + goto failed; } ret = read_file(IRQOFF_FILE, s); if (ret < 0) { diff --git a/source/tools/monitor/sched/runlatency/parser.c b/source/tools/monitor/sched/runlatency/parser.c index 971dd248aaa3900972b75c8341be147923229bac..aa9636eda93d405c5a64e320dc2b454dba3e4a66 100644 --- a/source/tools/monitor/sched/runlatency/parser.c +++ b/source/tools/monitor/sched/runlatency/parser.c @@ -41,7 +41,7 @@ static char* accepts(char* s, char c1, char c2) return s + 1; } -static bool isdigits(char *s) +bool isdigits(char *s) { while (*s != '\0') { if (isdigit(*s) == 0) { @@ -250,16 +250,8 @@ static char* body_runq(char* beg, FILE *file) root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "mode", "runq"); - s = head_args(s, root); - arr = cJSON_CreateArray(); - cJSON_AddItemToObject(root, "que", arr); - while (*s != '\n') { - cJSON *cell = cJSON_CreateObject(); - s = head_args(s, cell); - cJSON_AddItemToArray(arr, cell); - } - + out = cJSON_Print(root); if (!file) printf("%s\n", out); diff --git a/source/tools/monitor/sched/runlatency/parser.h b/source/tools/monitor/sched/runlatency/parser.h index 57baa7bcdb885fa8c8fcf00b3d72a18f40cd1e27..adee4e5ae299b900c316991efe1a69d6da9b1e1e 100644 --- a/source/tools/monitor/sched/runlatency/parser.h +++ b/source/tools/monitor/sched/runlatency/parser.h @@ -1,7 +1,9 @@ #ifndef _PARSER_H #define _PARSER_H +#include int parser_irqoff(char *stream, int size, FILE *file); int parser_nosch(char *stream, int size, FILE *file); int parser_runq(char *stream, int size, FILE *file); -int pasre_dump(char *file); +int parse_dump(char *file); +bool isdigits(char *s); #endif diff --git a/source/tools/monitor/sched/runlatency/runlatency.c b/source/tools/monitor/sched/runlatency/runlatency.c index 26403ba03d30e0186b05c32ab3f9d5848135ec10..8aa7498ba738a6f7fa2e22e9c472756393e8f440 100644 --- a/source/tools/monitor/sched/runlatency/runlatency.c +++ b/source/tools/monitor/sched/runlatency/runlatency.c @@ -14,46 +14,52 @@ #define MAX_CMD 3 #define MAX_CMD_LEN 128 -char *firq = "/proc/sysak/runlatency/irqoff/enable"; -char *fsch = "/proc/sysak/runlatency/nosch/enable"; -char *flat = "/proc/sysak/runlatency/runqlat/pid"; +bool ready[MAX_CMD] = {false}; +int retno[MAX_CMD] = {0}; +char *enable_files[] = {"/proc/sysak/runlatency/irqoff/enable", + "/proc/sysak/runlatency/nosch/enable", + "/proc/sysak/runlatency/runqlat/pid"}; +char *trsh_files[] = {"/proc/sysak/runlatency/irqoff/latency", + "/proc/sysak/runlatency/nosch/threshold", + "/proc/sysak/runlatency/runqlat/threshold"}; static void usage(char *prog) { const char *str = - " Usage: %s [OPTIONS]\n" + " Usage: %s -e [-p pid], [-t t1 t2 t3]\n" " Options:\n" - " -f the output file\n" - " -r read the result to file or stdout, default stdout\n" - " -d disable the monitor, 7-all, 1-irq, 2-nosched, 4-runlat, default=7\n" - " -e enable the monitor, 7-all, 1-irq, 2-nosched, 4-runlat, default=7\n" + " -p set the pid we monitor, used with -e or separately\n" + " -t set thresh:latirq=thresh1, nosched=thresh2, runq=thresh3 \n" + " -r [outfile] read result to outfile, if not point,to stdout\n" + " -d [mask] disable the monitor, 7-all, 1-irq, 2-nosched, 4-runlat, default=7\n" + " -e [mask]enable the monitor, 7-all, 1-irq, 2-nosched, 4-runlat, default=7\n" + "for example:\n" + " sysak runlatency -e -p 78953 #enable all runaltency monitor for task 78953\n" + " sleep 20 #Sampling for 20 seconds 20\n" + " sysak runlatency -r ./my.json #record the sampling result to my.json\n" + " sysak runlatency -d #close all runaltency monitor\n" ; fprintf(stderr, str, prog); exit(EXIT_FAILURE); } -char *cmdstr[3]; - -int switch_func(int opt, int enable, int arg) +int switch_func(int opt, int enable, int pid) { FILE *fp; int param[3], ret, index = 0; int optalign; char cmd[MAX_CMD_LEN] = {0}; - optalign = opt & OPT_MASK; if (optalign & OPT_LAT) - param[2] = arg; - else - param[2] = enable; + param[2] = (enable != 0) ? pid:-1; param[0] = param[1] = enable; while (index < MAX_CMD) { if (optalign & (1 << index)) { - snprintf(cmd, MAX_CMD_LEN, "echo %d > %s",param[index], cmdstr[index]); + snprintf(cmd, MAX_CMD_LEN, "echo %d > %s",param[index], enable_files[index]); /* fprintf(stderr, "debug_cmd:%s\n", cmd); */ fp = popen(cmd, "r"); if (!fp) { @@ -61,45 +67,61 @@ int switch_func(int opt, int enable, int arg) perror(cmd); return ret; } - optalign = optalign; - index++; } + index++; } + + return 0; } -bool ready[MAX_CMD] = {false}; -int retno[MAX_CMD] = {0}; +int set_thresh(unsigned long *thresh) +{ + FILE *fp; + int i = 0, ret; + char cmd[MAX_CMD_LEN] = {0}; -static int not_ready(bool ready[], int retno[]) + for (; i < MAX_CMD; i++) { + snprintf(cmd, MAX_CMD_LEN, "echo %llu > %s", + thresh[i]*1000*1000, trsh_files[i]); + fp = popen(cmd, "r"); + if (!fp) { + ret = errno; + perror(cmd); + return ret; + } + } + return 0; +} + +static int all_ready(bool ready[], int retno[]) { - int i, ret = MAX_CMD; + int i, ready_cnt = 0; for (i = 0; i < MAX_CMD; i++) { if (ready[i]) { - ret--; + ready_cnt++; } else { fprintf(stderr, "%s: access() %s\n", - strerror(retno[i]), cmdstr[i]); + strerror(retno[i]), enable_files[i]); } } - return ret; + return (ready_cnt == MAX_CMD); } int main(int argc, char *argv[]) { char *refile = NULL; - int pid = -1, ret = 0, i, will_switch, enable; - int c, option_index, en_opt, dis_opt; + int pid = -1, ret = 0, i, will_switch = 0, enable = -1; + int c, option_index, opt_mask; + bool will_thresh = false; + unsigned long thresh[MAX_CMD] = {0}; opterr = 0; - dis_opt = en_opt = OPT_MASK; + opt_mask = 0; - cmdstr[0] = firq; - cmdstr[1] = fsch; - cmdstr[2] = flat; for (i = 0; i < MAX_CMD; i++) { - if (access(cmdstr[i], F_OK)) { + if (access(enable_files[i], F_OK)) { retno[i] = errno; ready[i] = false; } else { @@ -108,36 +130,61 @@ int main(int argc, char *argv[]) } } for (;;) { - c = getopt_long(argc, argv, "f:p:e::d::hr", + c = getopt_long(argc, argv, "p:e::d::trh", NULL /*long_options*/, &option_index); if (c == -1) break; switch (c) { - case 'f': - refile = optarg; - break; case 'r': - if (!not_ready(ready, retno)) + if (!all_ready(ready, retno)) return -1; - pasre_dump(refile);//do something + if (argc > optind) /* for -r xxx.log */ + refile = argv[optind]; + parse_dump(refile);//do something + break; + case 't': + if (!all_ready(ready, retno)) + return -1; + if (argc > optind + 2) { /* -t follows 3 arguments */ + for (i = 0; i < MAX_CMD; i++) { + if (isdigits(argv[i+optind])) + thresh[i] = strtoul(argv[i+optind], NULL, 10); + else + break; + } + if (i >= MAX_CMD) + will_thresh = true; + else + printf("-t must follows 3 digitals\n"); + } else { + printf("\"-t\" must follows 3 digitals\n"); + usage("sysak runlatency"); + } break; case 'p': pid = atoi(optarg); + will_switch = 1; + opt_mask |= OPT_LAT; break; case 'e': - if (!not_ready(ready, retno)) + if (!all_ready(ready, retno)) return -1; if (optarg) - en_opt = atoi(optarg); + opt_mask = atoi(optarg); + else + opt_mask = OPT_MASK & (~OPT_LAT); + will_switch = 1; enable = 1; break; case 'd': - if (!not_ready(ready, retno)) + if (!all_ready(ready, retno)) return -1; if (optarg) - dis_opt = atoi(optarg); + opt_mask = atoi(optarg); + else + opt_mask = OPT_MASK; will_switch = 1; enable = 0; break; @@ -149,7 +196,10 @@ int main(int argc, char *argv[]) } } if (will_switch) - ret = switch_func(dis_opt, enable, pid); - + ret = switch_func(opt_mask, enable, pid); + if (ret) + return ret; + if (will_thresh) + ret = set_thresh(thresh); return ret; }