aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-08-28 11:44:30 -0400
committerJon Medhurst <tixy@yxit.co.uk>2011-09-20 14:17:44 -0400
commitce5af3bad0e03e94d01c002698ca6b2697b51836 (patch)
tree34f47fdaba1cc0311deb804605dff8a6044698fc /arch/arm/kernel
parent963780dfe390e80e148eb84f0c84a01533a64d28 (diff)
ARM: kprobes: Add some benchmarking to test module
These benchmarks show the basic speed of kprobes and verify the success of optimisations done to the emulation of typical function entry instructions (i.e. push/stmdb). Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/kprobes-test.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c
index fe169e934d42..e5740c7c64e5 100644
--- a/arch/arm/kernel/kprobes-test.c
+++ b/arch/arm/kernel/kprobes-test.c
@@ -185,6 +185,9 @@
185#include "kprobes-test.h" 185#include "kprobes-test.h"
186 186
187 187
188#define BENCHMARKING 1
189
190
188/* 191/*
189 * Test basic API 192 * Test basic API
190 */ 193 */
@@ -444,6 +447,157 @@ static int run_api_tests(long (*func)(long, long))
444 447
445 448
446/* 449/*
450 * Benchmarking
451 */
452
453#if BENCHMARKING
454
455static void __naked benchmark_nop(void)
456{
457 __asm__ __volatile__ (
458 "nop \n\t"
459 "bx lr"
460 );
461}
462
463#ifdef CONFIG_THUMB2_KERNEL
464#define wide ".w"
465#else
466#define wide
467#endif
468
469static void __naked benchmark_pushpop1(void)
470{
471 __asm__ __volatile__ (
472 "stmdb"wide" sp!, {r3-r11,lr} \n\t"
473 "ldmia"wide" sp!, {r3-r11,pc}"
474 );
475}
476
477static void __naked benchmark_pushpop2(void)
478{
479 __asm__ __volatile__ (
480 "stmdb"wide" sp!, {r0-r8,lr} \n\t"
481 "ldmia"wide" sp!, {r0-r8,pc}"
482 );
483}
484
485static void __naked benchmark_pushpop3(void)
486{
487 __asm__ __volatile__ (
488 "stmdb"wide" sp!, {r4,lr} \n\t"
489 "ldmia"wide" sp!, {r4,pc}"
490 );
491}
492
493static void __naked benchmark_pushpop4(void)
494{
495 __asm__ __volatile__ (
496 "stmdb"wide" sp!, {r0,lr} \n\t"
497 "ldmia"wide" sp!, {r0,pc}"
498 );
499}
500
501
502#ifdef CONFIG_THUMB2_KERNEL
503
504static void __naked benchmark_pushpop_thumb(void)
505{
506 __asm__ __volatile__ (
507 "push.n {r0-r7,lr} \n\t"
508 "pop.n {r0-r7,pc}"
509 );
510}
511
512#endif
513
514static int __kprobes
515benchmark_pre_handler(struct kprobe *p, struct pt_regs *regs)
516{
517 return 0;
518}
519
520static int benchmark(void(*fn)(void))
521{
522 unsigned n, i, t, t0;
523
524 for (n = 1000; ; n *= 2) {
525 t0 = sched_clock();
526 for (i = n; i > 0; --i)
527 fn();
528 t = sched_clock() - t0;
529 if (t >= 250000000)
530 break; /* Stop once we took more than 0.25 seconds */
531 }
532 return t / n; /* Time for one iteration in nanoseconds */
533};
534
535static int kprobe_benchmark(void(*fn)(void), unsigned offset)
536{
537 struct kprobe k = {
538 .addr = (kprobe_opcode_t *)((uintptr_t)fn + offset),
539 .pre_handler = benchmark_pre_handler,
540 };
541
542 int ret = register_kprobe(&k);
543 if (ret < 0) {
544 pr_err("FAIL: register_kprobe failed with %d\n", ret);
545 return ret;
546 }
547
548 ret = benchmark(fn);
549
550 unregister_kprobe(&k);
551 return ret;
552};
553
554struct benchmarks {
555 void (*fn)(void);
556 unsigned offset;
557 const char *title;
558};
559
560static int run_benchmarks(void)
561{
562 int ret;
563 struct benchmarks list[] = {
564 {&benchmark_nop, 0, "nop"},
565 /*
566 * benchmark_pushpop{1,3} will have the optimised
567 * instruction emulation, whilst benchmark_pushpop{2,4} will
568 * be the equivalent unoptimised instructions.
569 */
570 {&benchmark_pushpop1, 0, "stmdb sp!, {r3-r11,lr}"},
571 {&benchmark_pushpop1, 4, "ldmia sp!, {r3-r11,pc}"},
572 {&benchmark_pushpop2, 0, "stmdb sp!, {r0-r8,lr}"},
573 {&benchmark_pushpop2, 4, "ldmia sp!, {r0-r8,pc}"},
574 {&benchmark_pushpop3, 0, "stmdb sp!, {r4,lr}"},
575 {&benchmark_pushpop3, 4, "ldmia sp!, {r4,pc}"},
576 {&benchmark_pushpop4, 0, "stmdb sp!, {r0,lr}"},
577 {&benchmark_pushpop4, 4, "ldmia sp!, {r0,pc}"},
578#ifdef CONFIG_THUMB2_KERNEL
579 {&benchmark_pushpop_thumb, 0, "push.n {r0-r7,lr}"},
580 {&benchmark_pushpop_thumb, 2, "pop.n {r0-r7,pc}"},
581#endif
582 {0}
583 };
584
585 struct benchmarks *b;
586 for (b = list; b->fn; ++b) {
587 ret = kprobe_benchmark(b->fn, b->offset);
588 if (ret < 0)
589 return ret;
590 pr_info(" %dns for kprobe %s\n", ret, b->title);
591 }
592
593 pr_info("\n");
594 return 0;
595}
596
597#endif /* BENCHMARKING */
598
599
600/*
447 * Decoding table self-consistency tests 601 * Decoding table self-consistency tests
448 */ 602 */
449 603
@@ -1526,6 +1680,13 @@ static int __init run_all_tests(void)
1526 goto out; 1680 goto out;
1527 } 1681 }
1528 1682
1683#if BENCHMARKING
1684 pr_info("Benchmarks\n");
1685 ret = run_benchmarks();
1686 if (ret)
1687 goto out;
1688#endif
1689
1529#if __LINUX_ARM_ARCH__ >= 7 1690#if __LINUX_ARM_ARCH__ >= 7
1530 /* We are able to run all test cases so coverage should be complete */ 1691 /* We are able to run all test cases so coverage should be complete */
1531 if (coverage_fail) { 1692 if (coverage_fail) {