Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Side by Side Diff: collector.c

Issue 6893111: Enhancements to ktop (Closed) Base URL: ssh://gitrw.chromium.org:9222/ktop.git@master
Patch Set: Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « collector.h ('k') | debug.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
3 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
4 */ 4 */
5 5
6 #include <pthread.h> 6 #include <pthread.h>
7 #include <stdio.h> 7 #include <stdio.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 #include <string.h> 9 #include <string.h>
10 #include <unistd.h> 10 #include <unistd.h>
11 11
12 #include <sys/types.h> 12 #include <sys/types.h>
13 #include <sys/stat.h> 13 #include <sys/stat.h>
14 #include <fcntl.h> 14 #include <fcntl.h>
15 15
16 #include <debug.h>
16 #include <eprintf.h> 17 #include <eprintf.h>
18 #include <mylib.h>
17 #include <style.h> 19 #include <style.h>
18 20
21 #include "collector.h"
22 #include "ktop.h"
19 #include "syscall.h" 23 #include "syscall.h"
20 #include "ktop.h"
21 24
22 #define _STR(x) #x 25 #define _STR(x) #x
23 #define STR(x) _STR(x) 26 #define STR(x) _STR(x)
24 #define MAX_PATH 256 27 #define MAX_PATH 256
25 28
26 enum {» BUF_SIZE = 1 << 12, 29 enum { PIDCALL_BUCKETS = 1543 };
27 » SMALL_READ = BUF_SIZE >> 2 };
28
29 typedef struct ring_header_s {
30 » u64» time_stamp;
31 » unint» commit;
32 » u8» data[];
33 } ring_header_s;
34
35 typedef struct ring_event_s {
36 » u32» type_len : 5,
37 » » time_delta : 27;
38 » u32» array[];
39 } ring_event_s;
40
41 typedef struct event_s {
42 » u16» type;
43 » u8» flags;
44 » u8» preempt_count;
45 » s32» pid;
46 » s32» lock_depth;
47 } event_s;
48
49 typedef struct sys_enter_s {
50 » event_s»ev;
51 » snint» id;
52 » unint» args[6];
53 } sys_enter_s;
54
55 typedef struct sys_exit_s {
56 » event_s»ev;
57 » snint» id;
58 » snint» ret;
59 } sys_exit_s;
60
61 30
62 pthread_mutex_t Count_lock = PTHREAD_MUTEX_INITIALIZER; 31 pthread_mutex_t Count_lock = PTHREAD_MUTEX_INITIALIZER;
63 32
64 u64 Syscall_count[NUM_SYS_CALLS]; 33 u64 Syscall_count[NUM_SYS_CALLS];
65 u64 MyPidCount; 34 u64 MyPidCount;
66 u64 Slept; 35 u64 Slept;
67 int Pid[MAX_PID]; 36 int Pid[MAX_PID];
68 37
38 Pidcall_s Pidcall[MAX_PIDCALLS];
39 Pidcall_s *Pidclock = Pidcall;
40 u64 PidcallIterations;
41 u64 PidcallRecord;
42 u64 Pidcall_tick;
43
44 u64 No_enter;
45 u64 Found;
46 u64 Out_of_order;
47 u64 No_start;
48
49 Pidcall_s *Pidcall_bucket[PIDCALL_BUCKETS];
50
69 static const char *find_debugfs(void) 51 static const char *find_debugfs(void)
70 { 52 {
71 static char debugfs[MAX_PATH+1]; 53 static char debugfs[MAX_PATH+1];
72 static int debugfs_found; 54 static int debugfs_found;
73 char type[100]; 55 char type[100];
74 FILE *fp; 56 FILE *fp;
75 57
76 if (debugfs_found) 58 if (debugfs_found)
77 return debugfs; 59 return debugfs;
78 60
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 { 144 {
163 145
164 enable_event("sys_exit"); 146 enable_event("sys_exit");
165 } 147 }
166 148
167 static void disable_sys_exit (void) 149 static void disable_sys_exit (void)
168 { 150 {
169 disable_event("sys_exit"); 151 disable_event("sys_exit");
170 } 152 }
171 153
172 static int init_raw(int cpu) 154 int open_raw(int cpu)
173 { 155 {
174 char name[MAX_NAME]; 156 char name[MAX_NAME];
175 int fd; 157 int fd;
176 158
177 snprintf(name, sizeof(name), "per_cpu/cpu%d/trace_pipe_raw", cpu); 159 snprintf(name, sizeof(name), "per_cpu/cpu%d/trace_pipe_raw", cpu);
178 fd = open(tracing_file(name), O_RDONLY); 160 fd = open(tracing_file(name), O_RDONLY);
179 if (fd == -1) { 161 if (fd == -1) {
180 fatal("open %s:", name); 162 fatal("open %s:", name);
181 } 163 }
182 return fd; 164 return fd;
183 } 165 }
184 166
185 Pidcall_s Pidcall[MAX_PIDCALLS]; 167 static Pidcall_s *hash_pidcall(u32 pidcall)
186 Pidcall_s *Pidnext = Pidcall;
187
188 static inline void swap_pidcall(Pidcall_s *p)
189 { 168 {
190 » Pidcall_s tmp; 169 » return (Pidcall_s *)&Pidcall_bucket[pidcall % PIDCALL_BUCKETS];
191
192 » if (p == Pidcall) return;
193 » tmp = *p;
194 » *p = p[-1];
195 » p[-1] = tmp;
196 } 170 }
197 171
198 void record_pid_syscall (u32 pidcall) 172 static Pidcall_s *find_pidcall(u32 pidcall)
199 { 173 {
200 » Pidcall_s *p; 174 » Pidcall_s *pc = hash_pidcall(pidcall);
201 175
202 » for (p = Pidcall; p < Pidnext; p++) { 176 ++PidcallRecord;
203 » » if (p->pidcall == pidcall) { 177 » for (;;) {
204 » » » ++p->count; 178 ++PidcallIterations;
205 » » » swap_pidcall(p); 179 » » pc = pc->next;
180 » » if (!pc) return NULL;
181 » » if (pc->pidcall == pidcall) {
182 » » » pc->clock = 1;
183 » » » return pc;
184 » » }
185 » }
186 }
187
188 #if 0
189 static void dump(char *label, Pidcall_s *pc)
190 {
191 » int i;
192
193 » fprintf(stderr, "%s", label);
194 » for (i = 0; (i < 10) && pc; i++) {
195 » » fprintf(stderr, " %p", pc);
196 » » pc = pc->next;
197 » }
198 » if (pc) fprintf(stderr, "STUCK");
199 » fprintf(stderr, "\n");
200 }
201 #endif
202
203 static void add_pidcall(Pidcall_s *pidcall)
204 {
205 » Pidcall_s *pc = hash_pidcall(pidcall->pidcall);
206
207 » pidcall->next = pc->next;
208 » pc->next = pidcall;
209 }
210
211 static void rmv_pidcall(u32 pidcall)
212 {
213 » Pidcall_s *prev = hash_pidcall(pidcall);
214 » Pidcall_s *next;
215
216 » for (;;) {
217 » » next = prev->next;
218 » » if (!next) return;
219 » » if (next->pidcall == pidcall) {
220 » » » prev->next = next->next;
206 return; 221 return;
207 } 222 }
223 prev = next;
208 } 224 }
209 if (Pidnext == &Pidcall[MAX_PIDCALLS]) {
210 /*
211 * Need a better method but this might be good enough
212 */
213 --p;
214 p->pidcall = pidcall;
215 p->count = 1;
216 swap_pidcall(p);
217 return;
218 }
219 p = Pidnext++;
220 p->pidcall = pidcall;
221 p->count = 1;
222 } 225 }
223 226
224 static void process_sys_enter(void *event) 227 static Pidcall_s *victim_pidcall(u32 pidcall)
228 {
229 » Pidcall_s *pc = Pidclock;
230
231 » while (pc->clock) {
232 ++Pidcall_tick;
233 » » pc->clock = 0;
234 » » if (++Pidclock == &Pidcall[MAX_PIDCALLS]) {
235 » » » Pidclock = Pidcall;
236 » » }
237 » » pc = Pidclock;
238 » }
239 » if (pc->pidcall) {
240 » » rmv_pidcall(pc->pidcall);
241 » }
242 » if (pc->name) {
243 » » free(pc->name);
244 » }
245 » zero(*pc);
246 » pc->pidcall = pidcall;
247 » add_pidcall(pc);
248
249 » return pc;
250 }
251
252 static void parse_sys_enter(void *event, u64 time)
225 { 253 {
226 sys_enter_s *sy = event; 254 sys_enter_s *sy = event;
227 » int pid = sy->ev.pid; 255 » int pid = sy->ev.pid;
228 » snint call_num = sy->id; 256 » snint call_num = sy->id;
257 » u32 pidcall = mkpidcall(pid, call_num);
258 » Pidcall_s *pc;
229 259
230 ++Pid[pid]; 260 ++Pid[pid];
231 261
232 if (call_num >= Num_syscalls) { 262 if (call_num >= Num_syscalls) {
233 warn("syscall number out of range %ld\n", call_num); 263 warn("syscall number out of range %ld\n", call_num);
234 return; 264 return;
235 } 265 }
236 ++Syscall_count[call_num]; 266 ++Syscall_count[call_num];
237 » record_pid_syscall(mkpidcall(pid, call_num)); 267
268 » pc = find_pidcall(pidcall);
269 » if (!pc) {
270 » » pc = victim_pidcall(pidcall);
271 » }
272 » ++pc->count;
273 » pc->time.start = time;
274 » memmove(pc->arg, sy->arg, sizeof(pc->arg));
238 } 275 }
239 276
240 static void process_sys_exit(void *event) 277 static void parse_sys_exit(void *event, u64 time)
241 { 278 {
242 //» sys_exit_s *sy = event; 279 » sys_exit_s *sy = event;
280 » int pid = sy->ev.pid;
281 » snint call_num = sy->id;
282 » u32 pidcall = mkpidcall(pid, call_num);
283 » Pidcall_s *pc;
284
285 » pc = find_pidcall(pidcall);
286 » if (!pc) {
287 » » ++No_enter;
288 » » return;
289 » }
290 » if (pc->time.start) {
291 » » if (time > pc->time.start) {
292 » » » ++Found;
293 » » » pc->time.total += time - pc->time.start;
294 » » } else {
295 » » » ++Out_of_order;
296 » » }
297 » » pc->time.start = 0;
298 » } else {
299 » » ++No_start;
300 » }
243 } 301 }
244 302
245 static void process_event(void *buf) 303 static void parse_event(void *buf, u64 time)
246 { 304 {
247 event_s *event = buf; 305 event_s *event = buf;
248 306
249 if (Trace_self) { 307 if (Trace_self) {
250 if (!do_ignore_pid(event->pid)) { 308 if (!do_ignore_pid(event->pid)) {
251 return; 309 return;
252 } 310 }
253 ++MyPidCount; 311 ++MyPidCount;
254 } else { 312 } else {
255 if (do_ignore_pid(event->pid)) { 313 if (do_ignore_pid(event->pid)) {
256 ++MyPidCount; 314 ++MyPidCount;
257 return; 315 return;
258 } 316 }
259 } 317 }
260 switch (event->type) { 318 switch (event->type) {
261 case 21: 319 case 21:
262 » » process_sys_exit(event); 320 » » parse_sys_exit(event, time);
263 break; 321 break;
264 case 22: 322 case 22:
265 » » process_sys_enter(event); 323 » » parse_sys_enter(event, time);
266 break; 324 break;
267 default: 325 default:
268 //printf(" no processing\n"); 326 //printf(" no processing\n");
269 break; 327 break;
270 } 328 }
271 } 329 }
272 330
273 static unint process_buf(u8 *buf) 331 static unint parse_buf(u8 *buf)
274 { 332 {
275 ring_header_s *rh = (ring_header_s *)buf; 333 ring_header_s *rh = (ring_header_s *)buf;
276 ring_event_s *r; 334 ring_event_s *r;
277 unint commit; 335 unint commit;
278 unint length; 336 unint length;
279 unint size; 337 unint size;
280 u64 time; 338 u64 time;
281 u8 *end; 339 u8 *end;
282 340
283 time = rh->time_stamp; 341 time = rh->time_stamp;
284 commit = rh->commit; 342 commit = rh->commit;
285 buf += sizeof(*rh); 343 buf += sizeof(*rh);
286 end = &buf[commit]; 344 end = &buf[commit];
287 pthread_mutex_lock(&Count_lock); 345 pthread_mutex_lock(&Count_lock);
288 for (; buf < end; buf += size) { 346 for (; buf < end; buf += size) {
289 r = (ring_event_s *)buf; 347 r = (ring_event_s *)buf;
290 if (r->type_len == 0) { 348 if (r->type_len == 0) {
291 /* Larger record where size is at beginning of record */ 349 /* Larger record where size is at beginning of record */
292 length = r->array[0]; 350 length = r->array[0];
293 size = 4 + length * 4; 351 size = 4 + length * 4;
294 time += r->time_delta; 352 time += r->time_delta;
295 } else if (r->type_len <= 28) { 353 } else if (r->type_len <= 28) {
296 /* Data record */ 354 /* Data record */
297 length = r->type_len; 355 length = r->type_len;
298 size = 4 + length * 4; 356 size = 4 + length * 4;
299 time += r->time_delta; 357 time += r->time_delta;
300 » » » process_event(buf+4); 358 » » » parse_event(buf+4, time);
301 } else if (r->type_len == 29) { 359 } else if (r->type_len == 29) {
302 /* Left over page padding or discarded event */ 360 /* Left over page padding or discarded event */
303 if (r->time_delta == 0) { 361 if (r->time_delta == 0) {
304 goto done; 362 goto done;
305 } else { 363 } else {
306 length = r->array[0]; 364 length = r->array[0];
307 size = 4 + length * 4; 365 size = 4 + length * 4;
308 } 366 }
309 } else if (r->type_len == 30) { 367 } else if (r->type_len == 30) {
310 /* Extended time delta */ 368 /* Extended time delta */
311 size = 8; 369 size = 8;
312 time += (((u64)r->array[0]) << 28) | r->time_delta; 370 time += (((u64)r->array[0]) << 28) | r->time_delta;
313 } else if (r->type_len == 31) { 371 } else if (r->type_len == 31) {
314 /* Sync time with external clock (NOT IMMPLEMENTED) */ 372 /* Sync time with external clock (NOT IMMPLEMENTED) */
315 » » » //tv_nsec = r->array[0]; 373 » » » time = r->array[0];
316 » » » //tv_sec = *(u64 *)&(r->array[1]); 374 » » » time += *(u64 *)&(r->array[1]) * A_BILLION;
317 } else { 375 } else {
318 warn(" Unknown event %d", r->type_len); 376 warn(" Unknown event %d", r->type_len);
319 /* Unknown - ignore */ 377 /* Unknown - ignore */
320 size = 4; 378 size = 4;
321 } 379 }
322 } 380 }
323 done: 381 done:
324 pthread_mutex_unlock(&Count_lock); 382 pthread_mutex_unlock(&Count_lock);
325 return commit; 383 return commit;
326 } 384 }
327 385
328 void pr_buf(int cpu, int sz, u8 buf[sz])
329 {
330 int i;
331 int j;
332
333 printf("%d. trace=%d bytes\n", cpu, sz);
334 for (i = 0; i < sz; i++) {
335 for (j = 0; j < 32; j++, i++) {
336 if (i == sz) goto done;
337 printf(" %2x", buf[i]);
338 }
339 printf("\n");
340 }
341 done:
342 printf("\n");
343 }
344
345 static void pr_event(event_s *event)
346 {
347 printf(" type=%2u flags=%2x cnt=%2d pid=%5d lock=%2d",
348 event->type, event->flags, event->preempt_count, event->pid,
349 event->lock_depth);
350 }
351
352 static void pr_sys_enter(void *event)
353 {
354 sys_enter_s *sy = event;
355 int i;
356
357 printf(" %-20s", Syscall[sy->id]);
358 for (i = 0; i < 6; i++) {
359 printf(" %ld", sy->args[i]);
360 }
361 printf("\n");
362 }
363
364 static void pr_sys_exit(void *event)
365 {
366 sys_exit_s *sy = event;
367
368 printf(" %-20s ret=%ld\n", Syscall[sy->id], sy->ret);
369 }
370
371 static void pr_ring_header(ring_header_s *rh)
372 {
373 printf("%lld %lld %ld\n",
374 rh->time_stamp / A_BILLION, rh->time_stamp % A_BILLION,
375 rh->commit);
376 }
377
378 static void dump_event(void *buf)
379 {
380 event_s *event = buf;
381
382 pr_event(event);
383 switch (event->type) {
384 case 21:
385 pr_sys_exit(event);
386 break;
387 case 22:
388 pr_sys_enter(event);
389 break;
390 default:
391 printf(" no processing\n");
392 break;
393 }
394 }
395
396 static void dump_buf(u8 *buf)
397 {
398 ring_header_s *rh = (ring_header_s *)buf;
399 ring_event_s *r;
400 unint length;
401 unint size;
402 u64 time;
403 u8 *end;
404
405 pr_ring_header(rh);
406 time = rh->time_stamp;
407 buf += sizeof(*rh);
408 end = &buf[rh->commit];
409 for (; buf < end; buf += size) {
410 r = (ring_event_s *)buf;
411 printf("type_len=%2u time=%9d", r->type_len, r->time_delta);
412 if (r->type_len == 0) {
413 length = r->array[0];
414 size = 4 + length * 4;
415 time += r->time_delta;
416 } else if (r->type_len <= 28) {
417 length = r->type_len;
418 size = 4 + length * 4;
419 time += r->time_delta;
420 dump_event(buf+4);
421 } else if (r->type_len == 29) {
422 printf("\n");
423 if (r->time_delta == 0) {
424 return;
425 } else {
426 length = r->array[0];
427 size = 4 + length * 4;
428 }
429 } else if (r->type_len == 30) {
430 /* Extended time delta */
431 printf("\n");
432 size = 8;
433 time += (((u64)r->array[0]) << 28) | r->time_delta;
434 } else if (r->type_len == 31) {
435 /* Sync time with external clock (NOT IMMPLEMENTED) */
436 //tv_nsec = r->array[0];
437 //tv_sec = *(u64 *)&(r->array[1]);
438 } else {
439 printf(" Unknown event %d\n", r->type_len);
440 /* Unknown - ignore */
441 size = 4;
442 }
443 }
444 }
445
446 static void dump_raw(int cpu, int sz, u8 buf[sz])
447 {
448 dump_buf(buf); // Need to do something with sz
449 }
450
451 void *collector(void *args) 386 void *collector(void *args)
452 { 387 {
453 Collector_args_s *a = args; 388 Collector_args_s *a = args;
454 /* 389 /*
455 * 1 ms -> 7% overhead 390 * 1 ms -> 7% overhead
456 * 10 ms -> 1% overhead 391 * 10 ms -> 1% overhead
457 */ 392 */
458 struct timespec sleep = { 0, 10 * A_MILLION }; 393 struct timespec sleep = { 0, 10 * A_MILLION };
459 u8 buf[BUF_SIZE]; 394 u8 buf[BUF_SIZE];
460 int cpu = a->cpu_id; 395 int cpu = a->cpu_id;
461 int trace_pipe; 396 int trace_pipe;
462 int rc; 397 int rc;
463 int i; 398 int i;
464 399
465 ignore_pid(gettid()); 400 ignore_pid(gettid());
466 » trace_pipe = init_raw(cpu); 401 » trace_pipe = open_raw(cpu);
467 for (i = 0;; i++) { 402 for (i = 0;; i++) {
468 rc = read(trace_pipe, buf, sizeof(buf)); 403 rc = read(trace_pipe, buf, sizeof(buf));
469 if (rc == -1) { 404 if (rc == -1) {
470 close(trace_pipe); 405 close(trace_pipe);
471 cleanup(0); 406 cleanup(0);
472 } 407 }
473 » » rc = process_buf(buf); 408 » » rc = parse_buf(buf);
474 if (rc < SMALL_READ) { 409 if (rc < SMALL_READ) {
475 ++Slept; 410 ++Slept;
476 nanosleep(&sleep, NULL); 411 nanosleep(&sleep, NULL);
477 // sleep(1); // Wait for input to accumulate
478 } 412 }
479 } 413 }
480 return NULL; 414 return NULL;
481 }
482
483 static void *dump_collector(void *args)
484 {
485 Collector_args_s *a = args;
486 u8 buf[BUF_SIZE];
487 int cpu = a->cpu_id;
488 int trace_pipe;
489 int rc;
490 int i;
491
492 ignore_pid(gettid());
493 trace_pipe = init_raw(cpu);
494 for (i = 0;; i++) {
495 rc = read(trace_pipe, buf, sizeof(buf));
496 printf("i=%d rc=%d\n", i, rc);
497 if (rc == -1) {
498 close(trace_pipe);
499 cleanup(0);
500 }
501 dump_raw(cpu, rc, buf);
502 if (rc < SMALL_READ) {
503 ++Slept;
504 sleep(1); // Wait for input to accumulate
505 }
506 }
507 return NULL;
508 } 415 }
509 416
510 void cleanup_collector(void) 417 void cleanup_collector(void)
511 { 418 {
512 disable_sys_enter(); 419 disable_sys_enter();
513 disable_sys_exit(); 420 disable_sys_exit();
514 } 421 }
515 422
516 void start_collector(void) 423 void start_collector(void)
517 { 424 {
(...skipping 10 matching lines...) Expand all
528 num_cpus = sysconf(_SC_NPROCESSORS_CONF); 435 num_cpus = sysconf(_SC_NPROCESSORS_CONF);
529 if (Dump) num_cpus = 1; // for now while playing with it 436 if (Dump) num_cpus = 1; // for now while playing with it
530 args = ezalloc(num_cpus * sizeof(Collector_args_s)); 437 args = ezalloc(num_cpus * sizeof(Collector_args_s));
531 for (i = 0; i < num_cpus; i++, args++) { 438 for (i = 0; i < num_cpus; i++, args++) {
532 args->cpu_id = i; 439 args->cpu_id = i;
533 rc = pthread_create(&collector_thread, NULL, 440 rc = pthread_create(&collector_thread, NULL,
534 Dump ? dump_collector : collector, args); 441 Dump ? dump_collector : collector, args);
535 if (rc) fatal("Couldn't create collector %d:", rc); 442 if (rc) fatal("Couldn't create collector %d:", rc);
536 } 443 }
537 } 444 }
OLDNEW
« no previous file with comments | « collector.h ('k') | debug.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698