main.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * Copyright (C) 2016 Red Hat, Inc.
  3. * Author: Michael S. Tsirkin <mst@redhat.com>
  4. * This work is licensed under the terms of the GNU GPL, version 2.
  5. *
  6. * Common macros and functions for ring benchmarking.
  7. */
  8. #ifndef MAIN_H
  9. #define MAIN_H
  10. #include <stdbool.h>
  11. extern int param;
  12. extern bool do_exit;
  13. #if defined(__x86_64__) || defined(__i386__)
  14. #include "x86intrin.h"
  15. static inline void wait_cycles(unsigned long long cycles)
  16. {
  17. unsigned long long t;
  18. t = __rdtsc();
  19. while (__rdtsc() - t < cycles) {}
  20. }
  21. #define VMEXIT_CYCLES 500
  22. #define VMENTRY_CYCLES 500
  23. #elif defined(__s390x__)
  24. static inline void wait_cycles(unsigned long long cycles)
  25. {
  26. asm volatile("0: brctg %0,0b" : : "d" (cycles));
  27. }
  28. /* tweak me */
  29. #define VMEXIT_CYCLES 200
  30. #define VMENTRY_CYCLES 200
  31. #else
  32. static inline void wait_cycles(unsigned long long cycles)
  33. {
  34. _Exit(5);
  35. }
  36. #define VMEXIT_CYCLES 0
  37. #define VMENTRY_CYCLES 0
  38. #endif
  39. static inline void vmexit(void)
  40. {
  41. if (!do_exit)
  42. return;
  43. wait_cycles(VMEXIT_CYCLES);
  44. }
  45. static inline void vmentry(void)
  46. {
  47. if (!do_exit)
  48. return;
  49. wait_cycles(VMENTRY_CYCLES);
  50. }
  51. /* implemented by ring */
  52. void alloc_ring(void);
  53. /* guest side */
  54. int add_inbuf(unsigned, void *, void *);
  55. void *get_buf(unsigned *, void **);
  56. void disable_call();
  57. bool used_empty();
  58. bool enable_call();
  59. void kick_available();
  60. /* host side */
  61. void disable_kick();
  62. bool avail_empty();
  63. bool enable_kick();
  64. bool use_buf(unsigned *, void **);
  65. void call_used();
  66. /* implemented by main */
  67. extern bool do_sleep;
  68. void kick(void);
  69. void wait_for_kick(void);
  70. void call(void);
  71. void wait_for_call(void);
  72. extern unsigned ring_size;
  73. /* Compiler barrier - similar to what Linux uses */
  74. #define barrier() asm volatile("" ::: "memory")
  75. /* Is there a portable way to do this? */
  76. #if defined(__x86_64__) || defined(__i386__)
  77. #define cpu_relax() asm ("rep; nop" ::: "memory")
  78. #elif defined(__s390x__)
  79. #define cpu_relax() barrier()
  80. #else
  81. #define cpu_relax() assert(0)
  82. #endif
  83. extern bool do_relax;
  84. static inline void busy_wait(void)
  85. {
  86. if (do_relax)
  87. cpu_relax();
  88. else
  89. /* prevent compiler from removing busy loops */
  90. barrier();
  91. }
  92. #if defined(__x86_64__) || defined(__i386__)
  93. #define smp_mb() asm volatile("lock; addl $0,-132(%%rsp)" ::: "memory", "cc")
  94. #else
  95. /*
  96. * Not using __ATOMIC_SEQ_CST since gcc docs say they are only synchronized
  97. * with other __ATOMIC_SEQ_CST calls.
  98. */
  99. #define smp_mb() __sync_synchronize()
  100. #endif
  101. /*
  102. * This abuses the atomic builtins for thread fences, and
  103. * adds a compiler barrier.
  104. */
  105. #define smp_release() do { \
  106. barrier(); \
  107. __atomic_thread_fence(__ATOMIC_RELEASE); \
  108. } while (0)
  109. #define smp_acquire() do { \
  110. __atomic_thread_fence(__ATOMIC_ACQUIRE); \
  111. barrier(); \
  112. } while (0)
  113. #if defined(__i386__) || defined(__x86_64__) || defined(__s390x__)
  114. #define smp_wmb() barrier()
  115. #else
  116. #define smp_wmb() smp_release()
  117. #endif
  118. #ifdef __alpha__
  119. #define smp_read_barrier_depends() smp_acquire()
  120. #else
  121. #define smp_read_barrier_depends() do {} while(0)
  122. #endif
  123. static __always_inline
  124. void __read_once_size(const volatile void *p, void *res, int size)
  125. {
  126. switch (size) { \
  127. case 1: *(unsigned char *)res = *(volatile unsigned char *)p; break; \
  128. case 2: *(unsigned short *)res = *(volatile unsigned short *)p; break; \
  129. case 4: *(unsigned int *)res = *(volatile unsigned int *)p; break; \
  130. case 8: *(unsigned long long *)res = *(volatile unsigned long long *)p; break; \
  131. default: \
  132. barrier(); \
  133. __builtin_memcpy((void *)res, (const void *)p, size); \
  134. barrier(); \
  135. } \
  136. }
  137. static __always_inline void __write_once_size(volatile void *p, void *res, int size)
  138. {
  139. switch (size) {
  140. case 1: *(volatile unsigned char *)p = *(unsigned char *)res; break;
  141. case 2: *(volatile unsigned short *)p = *(unsigned short *)res; break;
  142. case 4: *(volatile unsigned int *)p = *(unsigned int *)res; break;
  143. case 8: *(volatile unsigned long long *)p = *(unsigned long long *)res; break;
  144. default:
  145. barrier();
  146. __builtin_memcpy((void *)p, (const void *)res, size);
  147. barrier();
  148. }
  149. }
  150. #define READ_ONCE(x) \
  151. ({ \
  152. union { typeof(x) __val; char __c[1]; } __u; \
  153. __read_once_size(&(x), __u.__c, sizeof(x)); \
  154. smp_read_barrier_depends(); /* Enforce dependency ordering from x */ \
  155. __u.__val; \
  156. })
  157. #define WRITE_ONCE(x, val) \
  158. ({ \
  159. union { typeof(x) __val; char __c[1]; } __u = \
  160. { .__val = (typeof(x)) (val) }; \
  161. __write_once_size(&(x), __u.__c, sizeof(x)); \
  162. __u.__val; \
  163. })
  164. #endif