test_perfmon_cpu.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Copyright (c) 2014-2018 Remy Noel.
  3. * Copyright (c) 2014-2018 Richard Braun.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. *
  19. * This test checks the behavior of performance monitoring on a CPU.
  20. * It creates a group with two events, cycle and instruction, and attaches
  21. * that group to CPU1, where a thread is bound and runs a tight loop to
  22. * make sure the target CPU is never idle. After some time, the measurement
  23. * stops and values are reported.
  24. */
  25. #include <errno.h>
  26. #include <stdbool.h>
  27. #include <stddef.h>
  28. #include <stdint.h>
  29. #include <string.h>
  30. #include <kern/atomic.h>
  31. #include <kern/clock.h>
  32. #include <kern/cpumap.h>
  33. #include <kern/error.h>
  34. #include <kern/list.h>
  35. #include <kern/log.h>
  36. #include <kern/panic.h>
  37. #include <kern/perfmon.h>
  38. #include <kern/thread.h>
  39. #include <machine/cpu.h>
  40. #include <test/test.h>
  41. #define TEST_WAIT_DELAY_MS 1000
  42. /*
  43. * Using another CPU than the BSP as the monitored CPU checks that PMUs are
  44. * correctly initialized on APs.
  45. */
  46. #define TEST_CONTROL_CPU 0
  47. #define TEST_MONITORED_CPU (TEST_CONTROL_CPU + 1)
  48. #define TEST_MIN_CPUS (TEST_MONITORED_CPU + 1)
  49. #define TEST_EVENT_NAME_MAX_SIZE 32
  50. struct test_event {
  51. struct list node;
  52. struct perfmon_event pm_event;
  53. char name[TEST_EVENT_NAME_MAX_SIZE];
  54. };
  55. struct test_group {
  56. struct list events;
  57. };
  58. static unsigned int test_run_stop;
  59. static void
  60. test_wait(void)
  61. {
  62. thread_delay(clock_ticks_from_ms(TEST_WAIT_DELAY_MS), false);
  63. }
  64. static void
  65. test_event_init(struct test_event *event, unsigned int id, const char *name)
  66. {
  67. int error;
  68. error = perfmon_event_init(&event->pm_event, id, PERFMON_EF_KERN);
  69. error_check(error, "perfmon_event_init");
  70. strlcpy(event->name, name, sizeof(event->name));
  71. }
  72. static void
  73. test_event_report(struct test_event *event)
  74. {
  75. uint64_t count;
  76. int error;
  77. count = perfmon_event_read(&event->pm_event);
  78. error = (count == 0) ? EINVAL : 0;
  79. error_check(error, __func__);
  80. log_info("test: %s: %llu", event->name, (unsigned long long)count);
  81. }
  82. static void
  83. test_event_attach_cpu(struct test_event *event, unsigned int cpu)
  84. {
  85. int error;
  86. error = perfmon_event_attach_cpu(&event->pm_event, cpu);
  87. error_check(error, "perfmon_event_attach_cpu");
  88. }
  89. static void
  90. test_event_detach(struct test_event *event)
  91. {
  92. int error;
  93. error = perfmon_event_detach(&event->pm_event);
  94. error_check(error, "perfmon_event_detach");
  95. }
  96. static void
  97. test_group_init(struct test_group *group)
  98. {
  99. list_init(&group->events);
  100. }
  101. static void
  102. test_group_add(struct test_group *group, struct test_event *event)
  103. {
  104. list_insert_tail(&group->events, &event->node);
  105. }
  106. static void
  107. test_group_attach_cpu(struct test_group *group, unsigned int cpu)
  108. {
  109. struct test_event *event;
  110. list_for_each_entry(&group->events, event, node) {
  111. test_event_attach_cpu(event, cpu);
  112. }
  113. }
  114. static void
  115. test_group_detach(struct test_group *group)
  116. {
  117. struct test_event *event;
  118. list_for_each_entry(&group->events, event, node) {
  119. test_event_detach(event);
  120. }
  121. }
  122. static void
  123. test_group_report(struct test_group *group)
  124. {
  125. struct test_event *event;
  126. list_for_each_entry(&group->events, event, node) {
  127. test_event_report(event);
  128. }
  129. }
  130. static void
  131. test_run(void *arg)
  132. {
  133. unsigned int stop;
  134. (void)arg;
  135. do {
  136. stop = atomic_load(&test_run_stop, ATOMIC_RELAXED);
  137. } while (!stop);
  138. }
  139. static void
  140. test_control(void *arg)
  141. {
  142. struct test_event cycle, instruction;
  143. struct test_group group;
  144. struct thread *thread;
  145. thread = arg;
  146. test_event_init(&cycle, PERFMON_EV_CYCLE, "cycle");
  147. test_event_init(&instruction, PERFMON_EV_INSTRUCTION, "instruction");
  148. test_group_init(&group);
  149. test_group_add(&group, &cycle);
  150. test_group_add(&group, &instruction);
  151. test_group_attach_cpu(&group, TEST_MONITORED_CPU);
  152. test_wait();
  153. test_group_report(&group);
  154. test_wait();
  155. test_group_detach(&group);
  156. test_group_report(&group);
  157. atomic_store(&test_run_stop, 1, ATOMIC_RELAXED);
  158. thread_join(thread);
  159. log_info("test: done");
  160. }
  161. void
  162. test_setup(void)
  163. {
  164. struct thread *thread;
  165. struct thread_attr attr;
  166. struct cpumap *cpumap;
  167. int error;
  168. if (cpu_count() < TEST_MIN_CPUS) {
  169. panic("test: %u processors required", TEST_MIN_CPUS);
  170. }
  171. error = cpumap_create(&cpumap);
  172. error_check(error, "cpumap_create");
  173. thread_attr_init(&attr, THREAD_KERNEL_PREFIX "test_run");
  174. cpumap_zero(cpumap);
  175. cpumap_set(cpumap, TEST_MONITORED_CPU);
  176. thread_attr_set_cpumap(&attr, cpumap);
  177. error = thread_create(&thread, &attr, test_run, NULL);
  178. error_check(error, "thread_create");
  179. thread_attr_init(&attr, THREAD_KERNEL_PREFIX "test_control");
  180. thread_attr_set_detached(&attr);
  181. cpumap_zero(cpumap);
  182. cpumap_set(cpumap, TEST_CONTROL_CPU);
  183. thread_attr_set_cpumap(&attr, cpumap);
  184. error = thread_create(NULL, &attr, test_control, thread);
  185. error_check(error, "thread_create");
  186. cpumap_destroy(cpumap);
  187. }