count_instructions.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. extern void thirty_two_instruction_loop(u64 loops);
  13. static void setup_event(struct event *e, u64 config, char *name)
  14. {
  15. event_init_opts(e, config, PERF_TYPE_HARDWARE, name);
  16. e->attr.disabled = 1;
  17. e->attr.exclude_kernel = 1;
  18. e->attr.exclude_hv = 1;
  19. e->attr.exclude_idle = 1;
  20. }
  21. static int do_count_loop(struct event *events, u64 instructions,
  22. u64 overhead, bool report)
  23. {
  24. s64 difference, expected;
  25. double percentage;
  26. prctl(PR_TASK_PERF_EVENTS_ENABLE);
  27. /* Run for 1M instructions */
  28. thirty_two_instruction_loop(instructions >> 5);
  29. prctl(PR_TASK_PERF_EVENTS_DISABLE);
  30. event_read(&events[0]);
  31. event_read(&events[1]);
  32. expected = instructions + overhead;
  33. difference = events[0].result.value - expected;
  34. percentage = (double)difference / events[0].result.value * 100;
  35. if (report) {
  36. event_report(&events[0]);
  37. event_report(&events[1]);
  38. printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);
  39. printf("Expected %llu\n", expected);
  40. printf("Actual %llu\n", events[0].result.value);
  41. printf("Delta %lld, %f%%\n", difference, percentage);
  42. }
  43. event_reset(&events[0]);
  44. event_reset(&events[1]);
  45. if (difference < 0)
  46. difference = -difference;
  47. /* Tolerate a difference below 0.0001 % */
  48. difference *= 10000 * 100;
  49. if (difference / events[0].result.value)
  50. return -1;
  51. return 0;
  52. }
  53. /* Count how many instructions it takes to do a null loop */
  54. static u64 determine_overhead(struct event *events)
  55. {
  56. u64 current, overhead;
  57. int i;
  58. do_count_loop(events, 0, 0, false);
  59. overhead = events[0].result.value;
  60. for (i = 0; i < 100; i++) {
  61. do_count_loop(events, 0, 0, false);
  62. current = events[0].result.value;
  63. if (current < overhead) {
  64. printf("Replacing overhead %llu with %llu\n", overhead, current);
  65. overhead = current;
  66. }
  67. }
  68. return overhead;
  69. }
  70. static int count_instructions(void)
  71. {
  72. struct event events[2];
  73. u64 overhead;
  74. setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions");
  75. setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles");
  76. if (event_open(&events[0])) {
  77. perror("perf_event_open");
  78. return -1;
  79. }
  80. if (event_open_with_group(&events[1], events[0].fd)) {
  81. perror("perf_event_open");
  82. return -1;
  83. }
  84. overhead = determine_overhead(events);
  85. printf("Overhead of null loop: %llu instructions\n", overhead);
  86. /* Run for 1M instructions */
  87. FAIL_IF(do_count_loop(events, 0x100000, overhead, true));
  88. /* Run for 10M instructions */
  89. FAIL_IF(do_count_loop(events, 0xa00000, overhead, true));
  90. /* Run for 100M instructions */
  91. FAIL_IF(do_count_loop(events, 0x6400000, overhead, true));
  92. /* Run for 1G instructions */
  93. FAIL_IF(do_count_loop(events, 0x40000000, overhead, true));
  94. event_close(&events[0]);
  95. event_close(&events[1]);
  96. return 0;
  97. }
  98. int main(void)
  99. {
  100. return test_harness(count_instructions, "count_instructions");
  101. }