count_instructions.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Copyright 2013, Michael Ellerman, IBM Corp.
  3. * Licensed under GPLv2.
  4. */
  5. #define _GNU_SOURCE
  6. #include <stdio.h>
  7. #include <stdbool.h>
  8. #include <string.h>
  9. #include <sys/prctl.h>
  10. #include "event.h"
  11. #include "utils.h"
  12. #include "lib.h"
  13. extern void thirty_two_instruction_loop(u64 loops);
  14. static void setup_event(struct event *e, u64 config, char *name)
  15. {
  16. event_init_opts(e, config, PERF_TYPE_HARDWARE, name);
  17. e->attr.disabled = 1;
  18. e->attr.exclude_kernel = 1;
  19. e->attr.exclude_hv = 1;
  20. e->attr.exclude_idle = 1;
  21. }
  22. static int do_count_loop(struct event *events, u64 instructions,
  23. u64 overhead, bool report)
  24. {
  25. s64 difference, expected;
  26. double percentage;
  27. prctl(PR_TASK_PERF_EVENTS_ENABLE);
  28. /* Run for 1M instructions */
  29. thirty_two_instruction_loop(instructions >> 5);
  30. prctl(PR_TASK_PERF_EVENTS_DISABLE);
  31. event_read(&events[0]);
  32. event_read(&events[1]);
  33. expected = instructions + overhead;
  34. difference = events[0].result.value - expected;
  35. percentage = (double)difference / events[0].result.value * 100;
  36. if (report) {
  37. event_report(&events[0]);
  38. event_report(&events[1]);
  39. printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);
  40. printf("Expected %llu\n", expected);
  41. printf("Actual %llu\n", events[0].result.value);
  42. printf("Delta %lld, %f%%\n", difference, percentage);
  43. }
  44. event_reset(&events[0]);
  45. event_reset(&events[1]);
  46. if (difference < 0)
  47. difference = -difference;
  48. /* Tolerate a difference below 0.0001 % */
  49. difference *= 10000 * 100;
  50. if (difference / events[0].result.value)
  51. return -1;
  52. return 0;
  53. }
  54. /* Count how many instructions it takes to do a null loop */
  55. static u64 determine_overhead(struct event *events)
  56. {
  57. u64 current, overhead;
  58. int i;
  59. do_count_loop(events, 0, 0, false);
  60. overhead = events[0].result.value;
  61. for (i = 0; i < 100; i++) {
  62. do_count_loop(events, 0, 0, false);
  63. current = events[0].result.value;
  64. if (current < overhead) {
  65. printf("Replacing overhead %llu with %llu\n", overhead, current);
  66. overhead = current;
  67. }
  68. }
  69. return overhead;
  70. }
  71. static int test_body(void)
  72. {
  73. struct event events[2];
  74. u64 overhead;
  75. setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions");
  76. setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles");
  77. if (event_open(&events[0])) {
  78. perror("perf_event_open");
  79. return -1;
  80. }
  81. if (event_open_with_group(&events[1], events[0].fd)) {
  82. perror("perf_event_open");
  83. return -1;
  84. }
  85. overhead = determine_overhead(events);
  86. printf("Overhead of null loop: %llu instructions\n", overhead);
  87. /* Run for 1Mi instructions */
  88. FAIL_IF(do_count_loop(events, 1000000, overhead, true));
  89. /* Run for 10Mi instructions */
  90. FAIL_IF(do_count_loop(events, 10000000, overhead, true));
  91. /* Run for 100Mi instructions */
  92. FAIL_IF(do_count_loop(events, 100000000, overhead, true));
  93. /* Run for 1Bi instructions */
  94. FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
  95. /* Run for 16Bi instructions */
  96. FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
  97. /* Run for 64Bi instructions */
  98. FAIL_IF(do_count_loop(events, 64000000000, overhead, true));
  99. event_close(&events[0]);
  100. event_close(&events[1]);
  101. return 0;
  102. }
  103. static int count_instructions(void)
  104. {
  105. return eat_cpu(test_body);
  106. }
  107. int main(void)
  108. {
  109. return test_harness(count_instructions, "count_instructions");
  110. }