diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-09-11 06:12:54 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-09-13 04:22:49 -0400 |
| commit | b1ffe8f3e0c96f5527a89e24410d6b0e59b3554a (patch) | |
| tree | f766ae671c3528186c4bbe313e178f77b0f52478 /tools | |
| parent | f2858d8ad9858e63c87257553c5721cba5db95ae (diff) | |
perf sched: Finish latency => atom rename and misc cleanups
- Rename 'latency' field/variable names to the better 'atom' ones
- Reduce the number of #include lines and consolidate them
- Gather file scope variables at the top of the file
- Remove unused bits
No change in functionality.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/builtin-sched.c | 399 |
1 files changed, 184 insertions, 215 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index e01cc63b98cc..cc2dbd5b50eb 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | #include "builtin.h" | 1 | #include "builtin.h" |
| 2 | #include "perf.h" | ||
| 2 | 3 | ||
| 3 | #include "util/util.h" | 4 | #include "util/util.h" |
| 4 | #include "util/cache.h" | 5 | #include "util/cache.h" |
| @@ -7,15 +8,16 @@ | |||
| 7 | #include "util/header.h" | 8 | #include "util/header.h" |
| 8 | 9 | ||
| 9 | #include "util/parse-options.h" | 10 | #include "util/parse-options.h" |
| 11 | #include "util/trace-event.h" | ||
| 10 | 12 | ||
| 11 | #include "perf.h" | ||
| 12 | #include "util/debug.h" | 13 | #include "util/debug.h" |
| 13 | 14 | ||
| 14 | #include "util/trace-event.h" | ||
| 15 | #include <sys/types.h> | 15 | #include <sys/types.h> |
| 16 | #include <sys/prctl.h> | ||
| 16 | 17 | ||
| 17 | 18 | #include <semaphore.h> | |
| 18 | #define MAX_CPUS 4096 | 19 | #include <pthread.h> |
| 20 | #include <math.h> | ||
| 19 | 21 | ||
| 20 | static char const *input_name = "perf.data"; | 22 | static char const *input_name = "perf.data"; |
| 21 | static int input; | 23 | static int input; |
| @@ -33,44 +35,126 @@ static u64 sample_type; | |||
| 33 | static char default_sort_order[] = "avg, max, switch, runtime"; | 35 | static char default_sort_order[] = "avg, max, switch, runtime"; |
| 34 | static char *sort_order = default_sort_order; | 36 | static char *sort_order = default_sort_order; |
| 35 | 37 | ||
| 38 | #define PR_SET_NAME 15 /* Set process name */ | ||
| 39 | #define MAX_CPUS 4096 | ||
| 36 | 40 | ||
| 37 | /* | 41 | #define BUG_ON(x) assert(!(x)) |
| 38 | * Scheduler benchmarks | ||
| 39 | */ | ||
| 40 | #include <sys/resource.h> | ||
| 41 | #include <sys/types.h> | ||
| 42 | #include <sys/stat.h> | ||
| 43 | #include <sys/time.h> | ||
| 44 | #include <sys/prctl.h> | ||
| 45 | 42 | ||
| 46 | #include <linux/unistd.h> | 43 | static u64 run_measurement_overhead; |
| 44 | static u64 sleep_measurement_overhead; | ||
| 47 | 45 | ||
| 48 | #include <semaphore.h> | 46 | #define COMM_LEN 20 |
| 49 | #include <pthread.h> | 47 | #define SYM_LEN 129 |
| 50 | #include <signal.h> | ||
| 51 | #include <values.h> | ||
| 52 | #include <string.h> | ||
| 53 | #include <unistd.h> | ||
| 54 | #include <stdlib.h> | ||
| 55 | #include <assert.h> | ||
| 56 | #include <fcntl.h> | ||
| 57 | #include <time.h> | ||
| 58 | #include <math.h> | ||
| 59 | 48 | ||
| 60 | #include <stdio.h> | 49 | #define MAX_PID 65536 |
| 61 | 50 | ||
| 62 | #define PR_SET_NAME 15 /* Set process name */ | 51 | static unsigned long nr_tasks; |
| 63 | 52 | ||
| 64 | #define BUG_ON(x) assert(!(x)) | 53 | struct sched_event; |
| 65 | 54 | ||
| 66 | #define DEBUG 0 | 55 | struct task_desc { |
| 56 | unsigned long nr; | ||
| 57 | unsigned long pid; | ||
| 58 | char comm[COMM_LEN]; | ||
| 67 | 59 | ||
| 68 | typedef unsigned long long nsec_t; | 60 | unsigned long nr_events; |
| 61 | unsigned long curr_event; | ||
| 62 | struct sched_event **events; | ||
| 63 | |||
| 64 | pthread_t thread; | ||
| 65 | sem_t sleep_sem; | ||
| 69 | 66 | ||
| 70 | static nsec_t run_measurement_overhead; | 67 | sem_t ready_for_work; |
| 71 | static nsec_t sleep_measurement_overhead; | 68 | sem_t work_done_sem; |
| 69 | |||
| 70 | u64 cpu_usage; | ||
| 71 | }; | ||
| 72 | |||
| 73 | enum sched_event_type { | ||
| 74 | SCHED_EVENT_RUN, | ||
| 75 | SCHED_EVENT_SLEEP, | ||
| 76 | SCHED_EVENT_WAKEUP, | ||
| 77 | }; | ||
| 78 | |||
| 79 | struct sched_event { | ||
| 80 | enum sched_event_type type; | ||
| 81 | u64 timestamp; | ||
| 82 | u64 duration; | ||
| 83 | unsigned long nr; | ||
| 84 | int specific_wait; | ||
| 85 | sem_t *wait_sem; | ||
| 86 | struct task_desc *wakee; | ||
| 87 | }; | ||
| 88 | |||
| 89 | static struct task_desc *pid_to_task[MAX_PID]; | ||
| 90 | |||
| 91 | static struct task_desc **tasks; | ||
| 92 | |||
| 93 | static pthread_mutex_t start_work_mutex = PTHREAD_MUTEX_INITIALIZER; | ||
| 94 | static u64 start_time; | ||
| 95 | |||
| 96 | static pthread_mutex_t work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER; | ||
| 72 | 97 | ||
| 73 | static nsec_t get_nsecs(void) | 98 | static unsigned long nr_run_events; |
| 99 | static unsigned long nr_sleep_events; | ||
| 100 | static unsigned long nr_wakeup_events; | ||
| 101 | |||
| 102 | static unsigned long nr_sleep_corrections; | ||
| 103 | static unsigned long nr_run_events_optimized; | ||
| 104 | |||
| 105 | static unsigned long targetless_wakeups; | ||
| 106 | static unsigned long multitarget_wakeups; | ||
| 107 | |||
| 108 | static u64 cpu_usage; | ||
| 109 | static u64 runavg_cpu_usage; | ||
| 110 | static u64 parent_cpu_usage; | ||
| 111 | static u64 runavg_parent_cpu_usage; | ||
| 112 | |||
| 113 | static unsigned long nr_runs; | ||
| 114 | static u64 sum_runtime; | ||
| 115 | static u64 sum_fluct; | ||
| 116 | static u64 run_avg; | ||
| 117 | |||
| 118 | static unsigned long replay_repeat = 10; | ||
| 119 | |||
| 120 | #define TASK_STATE_TO_CHAR_STR "RSDTtZX" | ||
| 121 | |||
| 122 | enum thread_state { | ||
| 123 | THREAD_SLEEPING = 0, | ||
| 124 | THREAD_WAIT_CPU, | ||
| 125 | THREAD_SCHED_IN, | ||
| 126 | THREAD_IGNORE | ||
| 127 | }; | ||
| 128 | |||
| 129 | struct work_atom { | ||
| 130 | struct list_head list; | ||
| 131 | enum thread_state state; | ||
| 132 | u64 wake_up_time; | ||
| 133 | u64 sched_in_time; | ||
| 134 | u64 runtime; | ||
| 135 | }; | ||
| 136 | |||
| 137 | struct task_atoms { | ||
| 138 | struct list_head atom_list; | ||
| 139 | struct thread *thread; | ||
| 140 | struct rb_node node; | ||
| 141 | u64 max_lat; | ||
| 142 | u64 total_lat; | ||
| 143 | u64 nb_atoms; | ||
| 144 | u64 total_runtime; | ||
| 145 | }; | ||
| 146 | |||
| 147 | typedef int (*sort_thread_lat)(struct task_atoms *, struct task_atoms *); | ||
| 148 | |||
| 149 | static struct rb_root atom_root, sorted_atom_root; | ||
| 150 | |||
| 151 | static u64 all_runtime; | ||
| 152 | static u64 all_count; | ||
| 153 | |||
| 154 | static int read_events(void); | ||
| 155 | |||
| 156 | |||
| 157 | static u64 get_nsecs(void) | ||
| 74 | { | 158 | { |
| 75 | struct timespec ts; | 159 | struct timespec ts; |
| 76 | 160 | ||
| @@ -79,16 +163,16 @@ static nsec_t get_nsecs(void) | |||
| 79 | return ts.tv_sec * 1000000000ULL + ts.tv_nsec; | 163 | return ts.tv_sec * 1000000000ULL + ts.tv_nsec; |
| 80 | } | 164 | } |
| 81 | 165 | ||
| 82 | static void burn_nsecs(nsec_t nsecs) | 166 | static void burn_nsecs(u64 nsecs) |
| 83 | { | 167 | { |
| 84 | nsec_t T0 = get_nsecs(), T1; | 168 | u64 T0 = get_nsecs(), T1; |
| 85 | 169 | ||
| 86 | do { | 170 | do { |
| 87 | T1 = get_nsecs(); | 171 | T1 = get_nsecs(); |
| 88 | } while (T1 + run_measurement_overhead < T0 + nsecs); | 172 | } while (T1 + run_measurement_overhead < T0 + nsecs); |
| 89 | } | 173 | } |
| 90 | 174 | ||
| 91 | static void sleep_nsecs(nsec_t nsecs) | 175 | static void sleep_nsecs(u64 nsecs) |
| 92 | { | 176 | { |
| 93 | struct timespec ts; | 177 | struct timespec ts; |
| 94 | 178 | ||
| @@ -100,7 +184,7 @@ static void sleep_nsecs(nsec_t nsecs) | |||
| 100 | 184 | ||
| 101 | static void calibrate_run_measurement_overhead(void) | 185 | static void calibrate_run_measurement_overhead(void) |
| 102 | { | 186 | { |
| 103 | nsec_t T0, T1, delta, min_delta = 1000000000ULL; | 187 | u64 T0, T1, delta, min_delta = 1000000000ULL; |
| 104 | int i; | 188 | int i; |
| 105 | 189 | ||
| 106 | for (i = 0; i < 10; i++) { | 190 | for (i = 0; i < 10; i++) { |
| @@ -117,7 +201,7 @@ static void calibrate_run_measurement_overhead(void) | |||
| 117 | 201 | ||
| 118 | static void calibrate_sleep_measurement_overhead(void) | 202 | static void calibrate_sleep_measurement_overhead(void) |
| 119 | { | 203 | { |
| 120 | nsec_t T0, T1, delta, min_delta = 1000000000ULL; | 204 | u64 T0, T1, delta, min_delta = 1000000000ULL; |
| 121 | int i; | 205 | int i; |
| 122 | 206 | ||
| 123 | for (i = 0; i < 10; i++) { | 207 | for (i = 0; i < 10; i++) { |
| @@ -133,67 +217,8 @@ static void calibrate_sleep_measurement_overhead(void) | |||
| 133 | printf("sleep measurement overhead: %Ld nsecs\n", min_delta); | 217 | printf("sleep measurement overhead: %Ld nsecs\n", min_delta); |
| 134 | } | 218 | } |
| 135 | 219 | ||
| 136 | #define COMM_LEN 20 | ||
| 137 | #define SYM_LEN 129 | ||
| 138 | |||
| 139 | #define MAX_PID 65536 | ||
| 140 | |||
| 141 | static unsigned long nr_tasks; | ||
| 142 | |||
| 143 | struct sched_event; | ||
| 144 | |||
| 145 | struct task_desc { | ||
| 146 | unsigned long nr; | ||
| 147 | unsigned long pid; | ||
| 148 | char comm[COMM_LEN]; | ||
| 149 | |||
| 150 | unsigned long nr_events; | ||
| 151 | unsigned long curr_event; | ||
| 152 | struct sched_event **events; | ||
| 153 | |||
| 154 | pthread_t thread; | ||
| 155 | sem_t sleep_sem; | ||
| 156 | |||
| 157 | sem_t ready_for_work; | ||
| 158 | sem_t work_done_sem; | ||
| 159 | |||
| 160 | nsec_t cpu_usage; | ||
| 161 | }; | ||
| 162 | |||
| 163 | enum sched_event_type { | ||
| 164 | SCHED_EVENT_RUN, | ||
| 165 | SCHED_EVENT_SLEEP, | ||
| 166 | SCHED_EVENT_WAKEUP, | ||
| 167 | }; | ||
| 168 | |||
| 169 | struct sched_event { | ||
| 170 | enum sched_event_type type; | ||
| 171 | nsec_t timestamp; | ||
| 172 | nsec_t duration; | ||
| 173 | unsigned long nr; | ||
| 174 | int specific_wait; | ||
| 175 | sem_t *wait_sem; | ||
| 176 | struct task_desc *wakee; | ||
| 177 | }; | ||
| 178 | |||
| 179 | static struct task_desc *pid_to_task[MAX_PID]; | ||
| 180 | |||
| 181 | static struct task_desc **tasks; | ||
| 182 | |||
| 183 | static pthread_mutex_t start_work_mutex = PTHREAD_MUTEX_INITIALIZER; | ||
| 184 | static nsec_t start_time; | ||
| 185 | |||
| 186 | static pthread_mutex_t work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER; | ||
| 187 | |||
| 188 | static unsigned long nr_run_events; | ||
| 189 | static unsigned long nr_sleep_events; | ||
| 190 | static unsigned long nr_wakeup_events; | ||
| 191 | |||
| 192 | static unsigned long nr_sleep_corrections; | ||
| 193 | static unsigned long nr_run_events_optimized; | ||
| 194 | |||
| 195 | static struct sched_event * | 220 | static struct sched_event * |
| 196 | get_new_event(struct task_desc *task, nsec_t timestamp) | 221 | get_new_event(struct task_desc *task, u64 timestamp) |
| 197 | { | 222 | { |
| 198 | struct sched_event *event = calloc(1, sizeof(*event)); | 223 | struct sched_event *event = calloc(1, sizeof(*event)); |
| 199 | unsigned long idx = task->nr_events; | 224 | unsigned long idx = task->nr_events; |
| @@ -221,7 +246,7 @@ static struct sched_event *last_event(struct task_desc *task) | |||
| 221 | } | 246 | } |
| 222 | 247 | ||
| 223 | static void | 248 | static void |
| 224 | add_sched_event_run(struct task_desc *task, nsec_t timestamp, u64 duration) | 249 | add_sched_event_run(struct task_desc *task, u64 timestamp, u64 duration) |
| 225 | { | 250 | { |
| 226 | struct sched_event *event, *curr_event = last_event(task); | 251 | struct sched_event *event, *curr_event = last_event(task); |
| 227 | 252 | ||
| @@ -243,11 +268,8 @@ add_sched_event_run(struct task_desc *task, nsec_t timestamp, u64 duration) | |||
| 243 | nr_run_events++; | 268 | nr_run_events++; |
| 244 | } | 269 | } |
| 245 | 270 | ||
| 246 | static unsigned long targetless_wakeups; | ||
| 247 | static unsigned long multitarget_wakeups; | ||
| 248 | |||
| 249 | static void | 271 | static void |
| 250 | add_sched_event_wakeup(struct task_desc *task, nsec_t timestamp, | 272 | add_sched_event_wakeup(struct task_desc *task, u64 timestamp, |
| 251 | struct task_desc *wakee) | 273 | struct task_desc *wakee) |
| 252 | { | 274 | { |
| 253 | struct sched_event *event, *wakee_event; | 275 | struct sched_event *event, *wakee_event; |
| @@ -275,7 +297,7 @@ add_sched_event_wakeup(struct task_desc *task, nsec_t timestamp, | |||
| 275 | } | 297 | } |
| 276 | 298 | ||
| 277 | static void | 299 | static void |
| 278 | add_sched_event_sleep(struct task_desc *task, nsec_t timestamp, | 300 | add_sched_event_sleep(struct task_desc *task, u64 timestamp, |
| 279 | u64 task_state __used) | 301 | u64 task_state __used) |
| 280 | { | 302 | { |
| 281 | struct sched_event *event = get_new_event(task, timestamp); | 303 | struct sched_event *event = get_new_event(task, timestamp); |
| @@ -350,7 +372,7 @@ static void | |||
| 350 | process_sched_event(struct task_desc *this_task __used, struct sched_event *event) | 372 | process_sched_event(struct task_desc *this_task __used, struct sched_event *event) |
| 351 | { | 373 | { |
| 352 | int ret = 0; | 374 | int ret = 0; |
| 353 | nsec_t now; | 375 | u64 now; |
| 354 | long long delta; | 376 | long long delta; |
| 355 | 377 | ||
| 356 | now = get_nsecs(); | 378 | now = get_nsecs(); |
| @@ -375,10 +397,10 @@ process_sched_event(struct task_desc *this_task __used, struct sched_event *even | |||
| 375 | } | 397 | } |
| 376 | } | 398 | } |
| 377 | 399 | ||
| 378 | static nsec_t get_cpu_usage_nsec_parent(void) | 400 | static u64 get_cpu_usage_nsec_parent(void) |
| 379 | { | 401 | { |
| 380 | struct rusage ru; | 402 | struct rusage ru; |
| 381 | nsec_t sum; | 403 | u64 sum; |
| 382 | int err; | 404 | int err; |
| 383 | 405 | ||
| 384 | err = getrusage(RUSAGE_SELF, &ru); | 406 | err = getrusage(RUSAGE_SELF, &ru); |
| @@ -390,12 +412,12 @@ static nsec_t get_cpu_usage_nsec_parent(void) | |||
| 390 | return sum; | 412 | return sum; |
| 391 | } | 413 | } |
| 392 | 414 | ||
| 393 | static nsec_t get_cpu_usage_nsec_self(void) | 415 | static u64 get_cpu_usage_nsec_self(void) |
| 394 | { | 416 | { |
| 395 | char filename [] = "/proc/1234567890/sched"; | 417 | char filename [] = "/proc/1234567890/sched"; |
| 396 | unsigned long msecs, nsecs; | 418 | unsigned long msecs, nsecs; |
| 397 | char *line = NULL; | 419 | char *line = NULL; |
| 398 | nsec_t total = 0; | 420 | u64 total = 0; |
| 399 | size_t len = 0; | 421 | size_t len = 0; |
| 400 | ssize_t chars; | 422 | ssize_t chars; |
| 401 | FILE *file; | 423 | FILE *file; |
| @@ -423,7 +445,7 @@ static nsec_t get_cpu_usage_nsec_self(void) | |||
| 423 | static void *thread_func(void *ctx) | 445 | static void *thread_func(void *ctx) |
| 424 | { | 446 | { |
| 425 | struct task_desc *this_task = ctx; | 447 | struct task_desc *this_task = ctx; |
| 426 | nsec_t cpu_usage_0, cpu_usage_1; | 448 | u64 cpu_usage_0, cpu_usage_1; |
| 427 | unsigned long i, ret; | 449 | unsigned long i, ret; |
| 428 | char comm2[22]; | 450 | char comm2[22]; |
| 429 | 451 | ||
| @@ -485,14 +507,9 @@ static void create_tasks(void) | |||
| 485 | } | 507 | } |
| 486 | } | 508 | } |
| 487 | 509 | ||
| 488 | static nsec_t cpu_usage; | ||
| 489 | static nsec_t runavg_cpu_usage; | ||
| 490 | static nsec_t parent_cpu_usage; | ||
| 491 | static nsec_t runavg_parent_cpu_usage; | ||
| 492 | |||
| 493 | static void wait_for_tasks(void) | 510 | static void wait_for_tasks(void) |
| 494 | { | 511 | { |
| 495 | nsec_t cpu_usage_0, cpu_usage_1; | 512 | u64 cpu_usage_0, cpu_usage_1; |
| 496 | struct task_desc *task; | 513 | struct task_desc *task; |
| 497 | unsigned long i, ret; | 514 | unsigned long i, ret; |
| 498 | 515 | ||
| @@ -543,16 +560,9 @@ static void wait_for_tasks(void) | |||
| 543 | } | 560 | } |
| 544 | } | 561 | } |
| 545 | 562 | ||
| 546 | static int read_events(void); | ||
| 547 | |||
| 548 | static unsigned long nr_runs; | ||
| 549 | static nsec_t sum_runtime; | ||
| 550 | static nsec_t sum_fluct; | ||
| 551 | static nsec_t run_avg; | ||
| 552 | |||
| 553 | static void run_one_test(void) | 563 | static void run_one_test(void) |
| 554 | { | 564 | { |
| 555 | nsec_t T0, T1, delta, avg_delta, fluct, std_dev; | 565 | u64 T0, T1, delta, avg_delta, fluct, std_dev; |
| 556 | 566 | ||
| 557 | T0 = get_nsecs(); | 567 | T0 = get_nsecs(); |
| 558 | wait_for_tasks(); | 568 | wait_for_tasks(); |
| @@ -576,10 +586,6 @@ static void run_one_test(void) | |||
| 576 | printf("#%-3ld: %0.3f, ", | 586 | printf("#%-3ld: %0.3f, ", |
| 577 | nr_runs, (double)delta/1000000.0); | 587 | nr_runs, (double)delta/1000000.0); |
| 578 | 588 | ||
| 579 | #if 0 | ||
| 580 | printf("%0.2f +- %0.2f, ", | ||
| 581 | (double)avg_delta/1e6, (double)std_dev/1e6); | ||
| 582 | #endif | ||
| 583 | printf("ravg: %0.2f, ", | 589 | printf("ravg: %0.2f, ", |
| 584 | (double)run_avg/1e6); | 590 | (double)run_avg/1e6); |
| 585 | 591 | ||
| @@ -605,7 +611,7 @@ static void run_one_test(void) | |||
| 605 | 611 | ||
| 606 | static void test_calibrations(void) | 612 | static void test_calibrations(void) |
| 607 | { | 613 | { |
| 608 | nsec_t T0, T1; | 614 | u64 T0, T1; |
| 609 | 615 | ||
| 610 | T0 = get_nsecs(); | 616 | T0 = get_nsecs(); |
| 611 | burn_nsecs(1e6); | 617 | burn_nsecs(1e6); |
| @@ -620,8 +626,6 @@ static void test_calibrations(void) | |||
| 620 | printf("the sleep test took %Ld nsecs\n", T1-T0); | 626 | printf("the sleep test took %Ld nsecs\n", T1-T0); |
| 621 | } | 627 | } |
| 622 | 628 | ||
| 623 | static unsigned long replay_repeat = 10; | ||
| 624 | |||
| 625 | static void __cmd_replay(void) | 629 | static void __cmd_replay(void) |
| 626 | { | 630 | { |
| 627 | unsigned long i; | 631 | unsigned long i; |
| @@ -865,47 +869,8 @@ static struct trace_sched_handler replay_ops = { | |||
| 865 | .fork_event = replay_fork_event, | 869 | .fork_event = replay_fork_event, |
| 866 | }; | 870 | }; |
| 867 | 871 | ||
| 868 | #define TASK_STATE_TO_CHAR_STR "RSDTtZX" | ||
| 869 | |||
| 870 | enum thread_state { | ||
| 871 | THREAD_SLEEPING = 0, | ||
| 872 | THREAD_WAIT_CPU, | ||
| 873 | THREAD_SCHED_IN, | ||
| 874 | THREAD_IGNORE | ||
| 875 | }; | ||
| 876 | |||
| 877 | struct work_atom { | ||
| 878 | struct list_head list; | ||
| 879 | enum thread_state state; | ||
| 880 | u64 wake_up_time; | ||
| 881 | u64 sched_in_time; | ||
| 882 | u64 runtime; | ||
| 883 | }; | ||
| 884 | |||
| 885 | struct task_atoms { | ||
| 886 | struct list_head snapshot_list; | ||
| 887 | struct thread *thread; | ||
| 888 | struct rb_node node; | ||
| 889 | u64 max_lat; | ||
| 890 | u64 total_lat; | ||
| 891 | u64 nb_atoms; | ||
| 892 | u64 total_runtime; | ||
| 893 | }; | ||
| 894 | |||
| 895 | typedef int (*sort_thread_lat)(struct task_atoms *, struct task_atoms *); | ||
| 896 | |||
| 897 | struct sort_dimension { | ||
| 898 | const char *name; | ||
| 899 | sort_thread_lat cmp; | ||
| 900 | struct list_head list; | ||
| 901 | }; | ||
| 902 | |||
| 903 | static LIST_HEAD(cmp_pid); | ||
| 904 | |||
| 905 | static struct rb_root lat_snapshot_root, sorted_lat_snapshot_root; | ||
| 906 | |||
| 907 | static struct task_atoms * | 872 | static struct task_atoms * |
| 908 | thread_atom_list_search(struct rb_root *root, struct thread *thread) | 873 | thread_atoms_search(struct rb_root *root, struct thread *thread) |
| 909 | { | 874 | { |
| 910 | struct rb_node *node = root->rb_node; | 875 | struct rb_node *node = root->rb_node; |
| 911 | 876 | ||
| @@ -924,6 +889,14 @@ thread_atom_list_search(struct rb_root *root, struct thread *thread) | |||
| 924 | return NULL; | 889 | return NULL; |
| 925 | } | 890 | } |
| 926 | 891 | ||
| 892 | struct sort_dimension { | ||
| 893 | const char *name; | ||
| 894 | sort_thread_lat cmp; | ||
| 895 | struct list_head list; | ||
| 896 | }; | ||
| 897 | |||
| 898 | static LIST_HEAD(cmp_pid); | ||
| 899 | |||
| 927 | static int | 900 | static int |
| 928 | thread_lat_cmp(struct list_head *list, struct task_atoms *l, | 901 | thread_lat_cmp(struct list_head *list, struct task_atoms *l, |
| 929 | struct task_atoms *r) | 902 | struct task_atoms *r) |
| @@ -965,16 +938,17 @@ __thread_latency_insert(struct rb_root *root, struct task_atoms *data, | |||
| 965 | rb_insert_color(&data->node, root); | 938 | rb_insert_color(&data->node, root); |
| 966 | } | 939 | } |
| 967 | 940 | ||
| 968 | static void thread_atom_list_insert(struct thread *thread) | 941 | static void thread_atoms_insert(struct thread *thread) |
| 969 | { | 942 | { |
| 970 | struct task_atoms *atoms; | 943 | struct task_atoms *atoms; |
| 944 | |||
| 971 | atoms = calloc(sizeof(*atoms), 1); | 945 | atoms = calloc(sizeof(*atoms), 1); |
| 972 | if (!atoms) | 946 | if (!atoms) |
| 973 | die("No memory"); | 947 | die("No memory"); |
| 974 | 948 | ||
| 975 | atoms->thread = thread; | 949 | atoms->thread = thread; |
| 976 | INIT_LIST_HEAD(&atoms->snapshot_list); | 950 | INIT_LIST_HEAD(&atoms->atom_list); |
| 977 | __thread_latency_insert(&lat_snapshot_root, atoms, &cmp_pid); | 951 | __thread_latency_insert(&atom_root, atoms, &cmp_pid); |
| 978 | } | 952 | } |
| 979 | 953 | ||
| 980 | static void | 954 | static void |
| @@ -1001,50 +975,49 @@ lat_sched_out(struct task_atoms *atoms, | |||
| 1001 | u64 delta, | 975 | u64 delta, |
| 1002 | u64 timestamp) | 976 | u64 timestamp) |
| 1003 | { | 977 | { |
| 1004 | struct work_atom *snapshot; | 978 | struct work_atom *atom; |
| 1005 | 979 | ||
| 1006 | snapshot = calloc(sizeof(*snapshot), 1); | 980 | atom = calloc(sizeof(*atom), 1); |
| 1007 | if (!snapshot) | 981 | if (!atom) |
| 1008 | die("Non memory"); | 982 | die("Non memory"); |
| 1009 | 983 | ||
| 1010 | if (sched_out_state(switch_event) == 'R') { | 984 | if (sched_out_state(switch_event) == 'R') { |
| 1011 | snapshot->state = THREAD_WAIT_CPU; | 985 | atom->state = THREAD_WAIT_CPU; |
| 1012 | snapshot->wake_up_time = timestamp; | 986 | atom->wake_up_time = timestamp; |
| 1013 | } | 987 | } |
| 1014 | 988 | ||
| 1015 | snapshot->runtime = delta; | 989 | atom->runtime = delta; |
| 1016 | list_add_tail(&snapshot->list, &atoms->snapshot_list); | 990 | list_add_tail(&atom->list, &atoms->atom_list); |
| 1017 | } | 991 | } |
| 1018 | 992 | ||
| 1019 | static void | 993 | static void |
| 1020 | lat_sched_in(struct task_atoms *atoms, u64 timestamp) | 994 | lat_sched_in(struct task_atoms *atoms, u64 timestamp) |
| 1021 | { | 995 | { |
| 1022 | struct work_atom *snapshot; | 996 | struct work_atom *atom; |
| 1023 | u64 delta; | 997 | u64 delta; |
| 1024 | 998 | ||
| 1025 | if (list_empty(&atoms->snapshot_list)) | 999 | if (list_empty(&atoms->atom_list)) |
| 1026 | return; | 1000 | return; |
| 1027 | 1001 | ||
| 1028 | snapshot = list_entry(atoms->snapshot_list.prev, struct work_atom, | 1002 | atom = list_entry(atoms->atom_list.prev, struct work_atom, list); |
| 1029 | list); | ||
| 1030 | 1003 | ||
| 1031 | if (snapshot->state != THREAD_WAIT_CPU) | 1004 | if (atom->state != THREAD_WAIT_CPU) |
| 1032 | return; | 1005 | return; |
| 1033 | 1006 | ||
| 1034 | if (timestamp < snapshot->wake_up_time) { | 1007 | if (timestamp < atom->wake_up_time) { |
| 1035 | snapshot->state = THREAD_IGNORE; | 1008 | atom->state = THREAD_IGNORE; |
| 1036 | return; | 1009 | return; |
| 1037 | } | 1010 | } |
| 1038 | 1011 | ||
| 1039 | snapshot->state = THREAD_SCHED_IN; | 1012 | atom->state = THREAD_SCHED_IN; |
| 1040 | snapshot->sched_in_time = timestamp; | 1013 | atom->sched_in_time = timestamp; |
| 1041 | 1014 | ||
| 1042 | delta = snapshot->sched_in_time - snapshot->wake_up_time; | 1015 | delta = atom->sched_in_time - atom->wake_up_time; |
| 1043 | atoms->total_lat += delta; | 1016 | atoms->total_lat += delta; |
| 1044 | if (delta > atoms->max_lat) | 1017 | if (delta > atoms->max_lat) |
| 1045 | atoms->max_lat = delta; | 1018 | atoms->max_lat = delta; |
| 1046 | atoms->nb_atoms++; | 1019 | atoms->nb_atoms++; |
| 1047 | atoms->total_runtime += snapshot->runtime; | 1020 | atoms->total_runtime += atom->runtime; |
| 1048 | } | 1021 | } |
| 1049 | 1022 | ||
| 1050 | static void | 1023 | static void |
| @@ -1076,20 +1049,20 @@ latency_switch_event(struct trace_switch_event *switch_event, | |||
| 1076 | sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); | 1049 | sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); |
| 1077 | sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); | 1050 | sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); |
| 1078 | 1051 | ||
| 1079 | in_atoms = thread_atom_list_search(&lat_snapshot_root, sched_in); | 1052 | in_atoms = thread_atoms_search(&atom_root, sched_in); |
| 1080 | if (!in_atoms) { | 1053 | if (!in_atoms) { |
| 1081 | thread_atom_list_insert(sched_in); | 1054 | thread_atoms_insert(sched_in); |
| 1082 | in_atoms = thread_atom_list_search(&lat_snapshot_root, sched_in); | 1055 | in_atoms = thread_atoms_search(&atom_root, sched_in); |
| 1083 | if (!in_atoms) | 1056 | if (!in_atoms) |
| 1084 | die("Internal latency tree error"); | 1057 | die("in-atom: Internal tree error"); |
| 1085 | } | 1058 | } |
| 1086 | 1059 | ||
| 1087 | out_atoms = thread_atom_list_search(&lat_snapshot_root, sched_out); | 1060 | out_atoms = thread_atoms_search(&atom_root, sched_out); |
| 1088 | if (!out_atoms) { | 1061 | if (!out_atoms) { |
| 1089 | thread_atom_list_insert(sched_out); | 1062 | thread_atoms_insert(sched_out); |
| 1090 | out_atoms = thread_atom_list_search(&lat_snapshot_root, sched_out); | 1063 | out_atoms = thread_atoms_search(&atom_root, sched_out); |
| 1091 | if (!out_atoms) | 1064 | if (!out_atoms) |
| 1092 | die("Internal latency tree error"); | 1065 | die("out-atom: Internal tree error"); |
| 1093 | } | 1066 | } |
| 1094 | 1067 | ||
| 1095 | lat_sched_in(in_atoms, timestamp); | 1068 | lat_sched_in(in_atoms, timestamp); |
| @@ -1104,7 +1077,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, | |||
| 1104 | struct thread *thread __used) | 1077 | struct thread *thread __used) |
| 1105 | { | 1078 | { |
| 1106 | struct task_atoms *atoms; | 1079 | struct task_atoms *atoms; |
| 1107 | struct work_atom *snapshot; | 1080 | struct work_atom *atom; |
| 1108 | struct thread *wakee; | 1081 | struct thread *wakee; |
| 1109 | 1082 | ||
| 1110 | /* Note for later, it may be interesting to observe the failing cases */ | 1083 | /* Note for later, it may be interesting to observe the failing cases */ |
| @@ -1112,23 +1085,22 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, | |||
| 1112 | return; | 1085 | return; |
| 1113 | 1086 | ||
| 1114 | wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); | 1087 | wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); |
| 1115 | atoms = thread_atom_list_search(&lat_snapshot_root, wakee); | 1088 | atoms = thread_atoms_search(&atom_root, wakee); |
| 1116 | if (!atoms) { | 1089 | if (!atoms) { |
| 1117 | thread_atom_list_insert(wakee); | 1090 | thread_atoms_insert(wakee); |
| 1118 | return; | 1091 | return; |
| 1119 | } | 1092 | } |
| 1120 | 1093 | ||
| 1121 | if (list_empty(&atoms->snapshot_list)) | 1094 | if (list_empty(&atoms->atom_list)) |
| 1122 | return; | 1095 | return; |
| 1123 | 1096 | ||
| 1124 | snapshot = list_entry(atoms->snapshot_list.prev, struct work_atom, | 1097 | atom = list_entry(atoms->atom_list.prev, struct work_atom, list); |
| 1125 | list); | ||
| 1126 | 1098 | ||
| 1127 | if (snapshot->state != THREAD_SLEEPING) | 1099 | if (atom->state != THREAD_SLEEPING) |
| 1128 | return; | 1100 | return; |
| 1129 | 1101 | ||
| 1130 | snapshot->state = THREAD_WAIT_CPU; | 1102 | atom->state = THREAD_WAIT_CPU; |
| 1131 | snapshot->wake_up_time = timestamp; | 1103 | atom->wake_up_time = timestamp; |
| 1132 | } | 1104 | } |
| 1133 | 1105 | ||
| 1134 | static struct trace_sched_handler lat_ops = { | 1106 | static struct trace_sched_handler lat_ops = { |
| @@ -1137,9 +1109,6 @@ static struct trace_sched_handler lat_ops = { | |||
| 1137 | .fork_event = latency_fork_event, | 1109 | .fork_event = latency_fork_event, |
| 1138 | }; | 1110 | }; |
| 1139 | 1111 | ||
| 1140 | static u64 all_runtime; | ||
| 1141 | static u64 all_count; | ||
| 1142 | |||
| 1143 | static void output_lat_thread(struct task_atoms *atom_list) | 1112 | static void output_lat_thread(struct task_atoms *atom_list) |
| 1144 | { | 1113 | { |
| 1145 | int i; | 1114 | int i; |
| @@ -1287,13 +1256,13 @@ static void sort_lat(void) | |||
| 1287 | 1256 | ||
| 1288 | for (;;) { | 1257 | for (;;) { |
| 1289 | struct task_atoms *data; | 1258 | struct task_atoms *data; |
| 1290 | node = rb_first(&lat_snapshot_root); | 1259 | node = rb_first(&atom_root); |
| 1291 | if (!node) | 1260 | if (!node) |
| 1292 | break; | 1261 | break; |
| 1293 | 1262 | ||
| 1294 | rb_erase(node, &lat_snapshot_root); | 1263 | rb_erase(node, &atom_root); |
| 1295 | data = rb_entry(node, struct task_atoms, node); | 1264 | data = rb_entry(node, struct task_atoms, node); |
| 1296 | __thread_latency_insert(&sorted_lat_snapshot_root, data, &sort_list); | 1265 | __thread_latency_insert(&sorted_atom_root, data, &sort_list); |
| 1297 | } | 1266 | } |
| 1298 | } | 1267 | } |
| 1299 | 1268 | ||
| @@ -1309,7 +1278,7 @@ static void __cmd_lat(void) | |||
| 1309 | printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); | 1278 | printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); |
| 1310 | printf("-----------------------------------------------------------------------------------\n"); | 1279 | printf("-----------------------------------------------------------------------------------\n"); |
| 1311 | 1280 | ||
| 1312 | next = rb_first(&sorted_lat_snapshot_root); | 1281 | next = rb_first(&sorted_atom_root); |
| 1313 | 1282 | ||
| 1314 | while (next) { | 1283 | while (next) { |
| 1315 | struct task_atoms *atom_list; | 1284 | struct task_atoms *atom_list; |
