diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-09 15:43:06 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-09 15:43:06 -0500 |
commit | 4ce5f24193cef2e26f182ce708e94ba1f5fafc0c (patch) | |
tree | 300373440be70af7c8ce662d4b30d8103e7c6026 /drivers/oprofile/buffer_sync.c | |
parent | 7c51d57e9d7fbce89f79c41dc8da383101dbe9c6 (diff) | |
parent | a076aa4f96f40fc75451ae835a1a665ce1faf951 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rric/oprofile
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rric/oprofile: (31 commits)
powerpc/oprofile: fix whitespaces in op_model_cell.c
powerpc/oprofile: IBM CELL: add SPU event profiling support
powerpc/oprofile: fix cell/pr_util.h
powerpc/oprofile: IBM CELL: cleanup and restructuring
oprofile: make new cpu buffer functions part of the api
oprofile: remove #ifdef CONFIG_OPROFILE_IBS in non-ibs code
ring_buffer: fix ring_buffer_event_length()
oprofile: use new data sample format for ibs
oprofile: add op_cpu_buffer_get_data()
oprofile: add op_cpu_buffer_add_data()
oprofile: rework implementation of cpu buffer events
oprofile: modify op_cpu_buffer_read_entry()
oprofile: add op_cpu_buffer_write_reserve()
oprofile: rename variables in add_ibs_begin()
oprofile: rename add_sample() in cpu_buffer.c
oprofile: rename variable ibs_allowed to has_ibs in op_model_amd.c
oprofile: making add_sample_entry() inline
oprofile: remove backtrace code for ibs
oprofile: remove unused ibs macro
oprofile: remove unused components in struct oprofile_cpu_buffer
...
Diffstat (limited to 'drivers/oprofile/buffer_sync.c')
-rw-r--r-- | drivers/oprofile/buffer_sync.c | 188 |
1 files changed, 79 insertions, 109 deletions
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 65e8294a9e29..9da5a4b81133 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c | |||
@@ -1,11 +1,12 @@ | |||
1 | /** | 1 | /** |
2 | * @file buffer_sync.c | 2 | * @file buffer_sync.c |
3 | * | 3 | * |
4 | * @remark Copyright 2002 OProfile authors | 4 | * @remark Copyright 2002-2009 OProfile authors |
5 | * @remark Read the file COPYING | 5 | * @remark Read the file COPYING |
6 | * | 6 | * |
7 | * @author John Levon <levon@movementarian.org> | 7 | * @author John Levon <levon@movementarian.org> |
8 | * @author Barry Kasindorf | 8 | * @author Barry Kasindorf |
9 | * @author Robert Richter <robert.richter@amd.com> | ||
9 | * | 10 | * |
10 | * This is the core of the buffer management. Each | 11 | * This is the core of the buffer management. Each |
11 | * CPU buffer is processed and entered into the | 12 | * CPU buffer is processed and entered into the |
@@ -315,88 +316,73 @@ static void add_trace_begin(void) | |||
315 | add_event_entry(TRACE_BEGIN_CODE); | 316 | add_event_entry(TRACE_BEGIN_CODE); |
316 | } | 317 | } |
317 | 318 | ||
318 | #ifdef CONFIG_OPROFILE_IBS | 319 | static void add_data(struct op_entry *entry, struct mm_struct *mm) |
319 | |||
320 | #define IBS_FETCH_CODE_SIZE 2 | ||
321 | #define IBS_OP_CODE_SIZE 5 | ||
322 | |||
323 | /* | ||
324 | * Add IBS fetch and op entries to event buffer | ||
325 | */ | ||
326 | static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) | ||
327 | { | 320 | { |
328 | unsigned long rip; | 321 | unsigned long code, pc, val; |
329 | int i, count; | 322 | unsigned long cookie; |
330 | unsigned long ibs_cookie = 0; | ||
331 | off_t offset; | 323 | off_t offset; |
332 | struct op_sample *sample; | ||
333 | |||
334 | sample = cpu_buffer_read_entry(cpu); | ||
335 | if (!sample) | ||
336 | goto Error; | ||
337 | rip = sample->eip; | ||
338 | 324 | ||
339 | #ifdef __LP64__ | 325 | if (!op_cpu_buffer_get_data(entry, &code)) |
340 | rip += sample->event << 32; | 326 | return; |
341 | #endif | 327 | if (!op_cpu_buffer_get_data(entry, &pc)) |
328 | return; | ||
329 | if (!op_cpu_buffer_get_size(entry)) | ||
330 | return; | ||
342 | 331 | ||
343 | if (mm) { | 332 | if (mm) { |
344 | ibs_cookie = lookup_dcookie(mm, rip, &offset); | 333 | cookie = lookup_dcookie(mm, pc, &offset); |
345 | 334 | ||
346 | if (ibs_cookie == NO_COOKIE) | 335 | if (cookie == NO_COOKIE) |
347 | offset = rip; | 336 | offset = pc; |
348 | if (ibs_cookie == INVALID_COOKIE) { | 337 | if (cookie == INVALID_COOKIE) { |
349 | atomic_inc(&oprofile_stats.sample_lost_no_mapping); | 338 | atomic_inc(&oprofile_stats.sample_lost_no_mapping); |
350 | offset = rip; | 339 | offset = pc; |
351 | } | 340 | } |
352 | if (ibs_cookie != last_cookie) { | 341 | if (cookie != last_cookie) { |
353 | add_cookie_switch(ibs_cookie); | 342 | add_cookie_switch(cookie); |
354 | last_cookie = ibs_cookie; | 343 | last_cookie = cookie; |
355 | } | 344 | } |
356 | } else | 345 | } else |
357 | offset = rip; | 346 | offset = pc; |
358 | 347 | ||
359 | add_event_entry(ESCAPE_CODE); | 348 | add_event_entry(ESCAPE_CODE); |
360 | add_event_entry(code); | 349 | add_event_entry(code); |
361 | add_event_entry(offset); /* Offset from Dcookie */ | 350 | add_event_entry(offset); /* Offset from Dcookie */ |
362 | 351 | ||
363 | /* we send the Dcookie offset, but send the raw Linear Add also*/ | 352 | while (op_cpu_buffer_get_data(entry, &val)) |
364 | add_event_entry(sample->eip); | 353 | add_event_entry(val); |
365 | add_event_entry(sample->event); | ||
366 | |||
367 | if (code == IBS_FETCH_CODE) | ||
368 | count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/ | ||
369 | else | ||
370 | count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ | ||
371 | |||
372 | for (i = 0; i < count; i++) { | ||
373 | sample = cpu_buffer_read_entry(cpu); | ||
374 | if (!sample) | ||
375 | goto Error; | ||
376 | add_event_entry(sample->eip); | ||
377 | add_event_entry(sample->event); | ||
378 | } | ||
379 | |||
380 | return; | ||
381 | |||
382 | Error: | ||
383 | return; | ||
384 | } | 354 | } |
385 | 355 | ||
386 | #endif | 356 | static inline void add_sample_entry(unsigned long offset, unsigned long event) |
387 | |||
388 | static void add_sample_entry(unsigned long offset, unsigned long event) | ||
389 | { | 357 | { |
390 | add_event_entry(offset); | 358 | add_event_entry(offset); |
391 | add_event_entry(event); | 359 | add_event_entry(event); |
392 | } | 360 | } |
393 | 361 | ||
394 | 362 | ||
395 | static int add_us_sample(struct mm_struct *mm, struct op_sample *s) | 363 | /* |
364 | * Add a sample to the global event buffer. If possible the | ||
365 | * sample is converted into a persistent dentry/offset pair | ||
366 | * for later lookup from userspace. Return 0 on failure. | ||
367 | */ | ||
368 | static int | ||
369 | add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) | ||
396 | { | 370 | { |
397 | unsigned long cookie; | 371 | unsigned long cookie; |
398 | off_t offset; | 372 | off_t offset; |
399 | 373 | ||
374 | if (in_kernel) { | ||
375 | add_sample_entry(s->eip, s->event); | ||
376 | return 1; | ||
377 | } | ||
378 | |||
379 | /* add userspace sample */ | ||
380 | |||
381 | if (!mm) { | ||
382 | atomic_inc(&oprofile_stats.sample_lost_no_mm); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
400 | cookie = lookup_dcookie(mm, s->eip, &offset); | 386 | cookie = lookup_dcookie(mm, s->eip, &offset); |
401 | 387 | ||
402 | if (cookie == INVALID_COOKIE) { | 388 | if (cookie == INVALID_COOKIE) { |
@@ -415,25 +401,6 @@ static int add_us_sample(struct mm_struct *mm, struct op_sample *s) | |||
415 | } | 401 | } |
416 | 402 | ||
417 | 403 | ||
418 | /* Add a sample to the global event buffer. If possible the | ||
419 | * sample is converted into a persistent dentry/offset pair | ||
420 | * for later lookup from userspace. | ||
421 | */ | ||
422 | static int | ||
423 | add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) | ||
424 | { | ||
425 | if (in_kernel) { | ||
426 | add_sample_entry(s->eip, s->event); | ||
427 | return 1; | ||
428 | } else if (mm) { | ||
429 | return add_us_sample(mm, s); | ||
430 | } else { | ||
431 | atomic_inc(&oprofile_stats.sample_lost_no_mm); | ||
432 | } | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | |||
437 | static void release_mm(struct mm_struct *mm) | 404 | static void release_mm(struct mm_struct *mm) |
438 | { | 405 | { |
439 | if (!mm) | 406 | if (!mm) |
@@ -526,66 +493,69 @@ void sync_buffer(int cpu) | |||
526 | { | 493 | { |
527 | struct mm_struct *mm = NULL; | 494 | struct mm_struct *mm = NULL; |
528 | struct mm_struct *oldmm; | 495 | struct mm_struct *oldmm; |
496 | unsigned long val; | ||
529 | struct task_struct *new; | 497 | struct task_struct *new; |
530 | unsigned long cookie = 0; | 498 | unsigned long cookie = 0; |
531 | int in_kernel = 1; | 499 | int in_kernel = 1; |
532 | sync_buffer_state state = sb_buffer_start; | 500 | sync_buffer_state state = sb_buffer_start; |
533 | unsigned int i; | 501 | unsigned int i; |
534 | unsigned long available; | 502 | unsigned long available; |
503 | unsigned long flags; | ||
504 | struct op_entry entry; | ||
505 | struct op_sample *sample; | ||
535 | 506 | ||
536 | mutex_lock(&buffer_mutex); | 507 | mutex_lock(&buffer_mutex); |
537 | 508 | ||
538 | add_cpu_switch(cpu); | 509 | add_cpu_switch(cpu); |
539 | 510 | ||
540 | cpu_buffer_reset(cpu); | 511 | op_cpu_buffer_reset(cpu); |
541 | available = cpu_buffer_entries(cpu); | 512 | available = op_cpu_buffer_entries(cpu); |
542 | 513 | ||
543 | for (i = 0; i < available; ++i) { | 514 | for (i = 0; i < available; ++i) { |
544 | struct op_sample *s = cpu_buffer_read_entry(cpu); | 515 | sample = op_cpu_buffer_read_entry(&entry, cpu); |
545 | if (!s) | 516 | if (!sample) |
546 | break; | 517 | break; |
547 | 518 | ||
548 | if (is_code(s->eip)) { | 519 | if (is_code(sample->eip)) { |
549 | switch (s->event) { | 520 | flags = sample->event; |
550 | case 0: | 521 | if (flags & TRACE_BEGIN) { |
551 | case CPU_IS_KERNEL: | 522 | state = sb_bt_start; |
523 | add_trace_begin(); | ||
524 | } | ||
525 | if (flags & KERNEL_CTX_SWITCH) { | ||
552 | /* kernel/userspace switch */ | 526 | /* kernel/userspace switch */ |
553 | in_kernel = s->event; | 527 | in_kernel = flags & IS_KERNEL; |
554 | if (state == sb_buffer_start) | 528 | if (state == sb_buffer_start) |
555 | state = sb_sample_start; | 529 | state = sb_sample_start; |
556 | add_kernel_ctx_switch(s->event); | 530 | add_kernel_ctx_switch(flags & IS_KERNEL); |
557 | break; | 531 | } |
558 | case CPU_TRACE_BEGIN: | 532 | if (flags & USER_CTX_SWITCH |
559 | state = sb_bt_start; | 533 | && op_cpu_buffer_get_data(&entry, &val)) { |
560 | add_trace_begin(); | ||
561 | break; | ||
562 | #ifdef CONFIG_OPROFILE_IBS | ||
563 | case IBS_FETCH_BEGIN: | ||
564 | state = sb_bt_start; | ||
565 | add_ibs_begin(cpu, IBS_FETCH_CODE, mm); | ||
566 | break; | ||
567 | case IBS_OP_BEGIN: | ||
568 | state = sb_bt_start; | ||
569 | add_ibs_begin(cpu, IBS_OP_CODE, mm); | ||
570 | break; | ||
571 | #endif | ||
572 | default: | ||
573 | /* userspace context switch */ | 534 | /* userspace context switch */ |
535 | new = (struct task_struct *)val; | ||
574 | oldmm = mm; | 536 | oldmm = mm; |
575 | new = (struct task_struct *)s->event; | ||
576 | release_mm(oldmm); | 537 | release_mm(oldmm); |
577 | mm = take_tasks_mm(new); | 538 | mm = take_tasks_mm(new); |
578 | if (mm != oldmm) | 539 | if (mm != oldmm) |
579 | cookie = get_exec_dcookie(mm); | 540 | cookie = get_exec_dcookie(mm); |
580 | add_user_ctx_switch(new, cookie); | 541 | add_user_ctx_switch(new, cookie); |
581 | break; | ||
582 | } | ||
583 | } else if (state >= sb_bt_start && | ||
584 | !add_sample(mm, s, in_kernel)) { | ||
585 | if (state == sb_bt_start) { | ||
586 | state = sb_bt_ignore; | ||
587 | atomic_inc(&oprofile_stats.bt_lost_no_mapping); | ||
588 | } | 542 | } |
543 | if (op_cpu_buffer_get_size(&entry)) | ||
544 | add_data(&entry, mm); | ||
545 | continue; | ||
546 | } | ||
547 | |||
548 | if (state < sb_bt_start) | ||
549 | /* ignore sample */ | ||
550 | continue; | ||
551 | |||
552 | if (add_sample(mm, sample, in_kernel)) | ||
553 | continue; | ||
554 | |||
555 | /* ignore backtraces if failed to add a sample */ | ||
556 | if (state == sb_bt_start) { | ||
557 | state = sb_bt_ignore; | ||
558 | atomic_inc(&oprofile_stats.bt_lost_no_mapping); | ||
589 | } | 559 | } |
590 | } | 560 | } |
591 | release_mm(mm); | 561 | release_mm(mm); |