aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/kprobes-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/kprobes-test.c')
-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) {