root/tools/virtio/ringtest/main.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. wait_cycles
  2. wait_cycles
  3. wait_cycles
  4. vmexit
  5. vmentry
  6. busy_wait
  7. __read_once_size
  8. __write_once_size

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

/* [<][>][^][v][top][bottom][index][help] */