2
0

atomic_add-bench.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #include "qemu/osdep.h"
  2. #include "qemu/thread.h"
  3. #include "qemu/host-utils.h"
  4. #include "qemu/processor.h"
  5. struct thread_info {
  6. uint64_t r;
  7. } QEMU_ALIGNED(64);
  8. struct count {
  9. QemuMutex lock;
  10. unsigned long val;
  11. } QEMU_ALIGNED(64);
  12. static QemuThread *threads;
  13. static struct thread_info *th_info;
  14. static unsigned int n_threads = 1;
  15. static unsigned int n_ready_threads;
  16. static struct count *counts;
  17. static unsigned int duration = 1;
  18. static unsigned int range = 1024;
  19. static bool use_mutex;
  20. static bool test_start;
  21. static bool test_stop;
  22. static const char commands_string[] =
  23. " -n = number of threads\n"
  24. " -m = use mutexes instead of atomic increments\n"
  25. " -p = enable sync profiler\n"
  26. " -d = duration in seconds\n"
  27. " -r = range (will be rounded up to pow2)";
  28. static void usage_complete(char *argv[])
  29. {
  30. fprintf(stderr, "Usage: %s [options]\n", argv[0]);
  31. fprintf(stderr, "options:\n%s\n", commands_string);
  32. }
  33. /*
  34. * From: https://en.wikipedia.org/wiki/Xorshift
  35. * This is faster than rand_r(), and gives us a wider range (RAND_MAX is only
  36. * guaranteed to be >= INT_MAX).
  37. */
  38. static uint64_t xorshift64star(uint64_t x)
  39. {
  40. x ^= x >> 12; /* a */
  41. x ^= x << 25; /* b */
  42. x ^= x >> 27; /* c */
  43. return x * UINT64_C(2685821657736338717);
  44. }
  45. static void *thread_func(void *arg)
  46. {
  47. struct thread_info *info = arg;
  48. atomic_inc(&n_ready_threads);
  49. while (!atomic_read(&test_start)) {
  50. cpu_relax();
  51. }
  52. while (!atomic_read(&test_stop)) {
  53. unsigned int index;
  54. info->r = xorshift64star(info->r);
  55. index = info->r & (range - 1);
  56. if (use_mutex) {
  57. qemu_mutex_lock(&counts[index].lock);
  58. counts[index].val += 1;
  59. qemu_mutex_unlock(&counts[index].lock);
  60. } else {
  61. atomic_inc(&counts[index].val);
  62. }
  63. }
  64. return NULL;
  65. }
  66. static void run_test(void)
  67. {
  68. unsigned int i;
  69. while (atomic_read(&n_ready_threads) != n_threads) {
  70. cpu_relax();
  71. }
  72. atomic_set(&test_start, true);
  73. g_usleep(duration * G_USEC_PER_SEC);
  74. atomic_set(&test_stop, true);
  75. for (i = 0; i < n_threads; i++) {
  76. qemu_thread_join(&threads[i]);
  77. }
  78. }
  79. static void create_threads(void)
  80. {
  81. unsigned int i;
  82. threads = g_new(QemuThread, n_threads);
  83. th_info = g_new(struct thread_info, n_threads);
  84. counts = qemu_memalign(64, sizeof(*counts) * range);
  85. memset(counts, 0, sizeof(*counts) * range);
  86. for (i = 0; i < range; i++) {
  87. qemu_mutex_init(&counts[i].lock);
  88. }
  89. for (i = 0; i < n_threads; i++) {
  90. struct thread_info *info = &th_info[i];
  91. info->r = (i + 1) ^ time(NULL);
  92. qemu_thread_create(&threads[i], NULL, thread_func, info,
  93. QEMU_THREAD_JOINABLE);
  94. }
  95. }
  96. static void pr_params(void)
  97. {
  98. printf("Parameters:\n");
  99. printf(" # of threads: %u\n", n_threads);
  100. printf(" duration: %u\n", duration);
  101. printf(" ops' range: %u\n", range);
  102. }
  103. static void pr_stats(void)
  104. {
  105. unsigned long long val = 0;
  106. unsigned int i;
  107. double tx;
  108. for (i = 0; i < range; i++) {
  109. val += counts[i].val;
  110. }
  111. tx = val / duration / 1e6;
  112. printf("Results:\n");
  113. printf("Duration: %u s\n", duration);
  114. printf(" Throughput: %.2f Mops/s\n", tx);
  115. printf(" Throughput/thread: %.2f Mops/s/thread\n", tx / n_threads);
  116. }
  117. static void parse_args(int argc, char *argv[])
  118. {
  119. int c;
  120. for (;;) {
  121. c = getopt(argc, argv, "hd:n:mpr:");
  122. if (c < 0) {
  123. break;
  124. }
  125. switch (c) {
  126. case 'h':
  127. usage_complete(argv);
  128. exit(0);
  129. case 'd':
  130. duration = atoi(optarg);
  131. break;
  132. case 'n':
  133. n_threads = atoi(optarg);
  134. break;
  135. case 'm':
  136. use_mutex = true;
  137. break;
  138. case 'p':
  139. qsp_enable();
  140. break;
  141. case 'r':
  142. range = pow2ceil(atoi(optarg));
  143. break;
  144. }
  145. }
  146. }
  147. int main(int argc, char *argv[])
  148. {
  149. parse_args(argc, argv);
  150. pr_params();
  151. create_threads();
  152. run_test();
  153. pr_stats();
  154. return 0;
  155. }