updates.
[silc.git] / lib / silcutil / tests / test_silcmutex.c
1 /* Locking performance tests.  Gives locsk&unlocks/second. */
2 /* Version 1.0 */
3
4 #include "silc.h"
5
6 typedef struct {
7   SilcThread thread;
8   SilcInt64 time;
9 } Context;
10
11 #define MAX_ROUND 8
12 #define MAX_MUL 4
13 #define MAX_THREADS 4
14 #define MAX_LOCKS 471234567
15
16 SilcMutex mutex;
17 SilcUInt64 cpu_freq = 0;
18 int max_locks, max_locks2;
19
20 /* RDTSC */
21 #ifdef SILC_I486
22 static __inline__ unsigned long long rdtsc(void)
23 {
24   unsigned long long int x;
25   __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
26   return x;
27 }
28
29 #elif SILC_X86_64
30 typedef unsigned long long int unsigned long long;
31 static __inline__ unsigned long long rdtsc(void)
32 {
33   unsigned hi, lo;
34   __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
35   return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
36 }
37
38 #elif SILC_POWERPC
39 typedef unsigned long long int unsigned long long;
40 static __inline__ unsigned long long rdtsc(void)
41 {
42   unsigned long long int result = 0;
43   unsigned long int upper, lower,tmp;
44   __asm__ volatile(
45                 "0:                  \n"
46                 "\tmftbu   %0           \n"
47                 "\tmftb    %1           \n"
48                 "\tmftbu   %2           \n"
49                 "\tcmpw    %2,%0        \n"
50                 "\tbne     0b         \n"
51                 : "=r"(upper),"=r"(lower),"=r"(tmp)
52                 );
53   result = upper;
54   result = result << 32;
55   result = result | lower;
56
57   return result;
58 }
59 #endif
60
61 void *mutex_thread(void *context)
62 {
63   Context *c = context;
64   SilcInt64 s;
65   register int i;
66
67   s = rdtsc();
68   for (i = 0; i < max_locks; i++) {
69     silc_mutex_lock(mutex);
70     silc_mutex_unlock(mutex);
71   }
72   c->time = rdtsc() - s;
73   c->time /= cpu_freq;
74
75   return NULL;
76 }
77
78 SilcUInt64 hval;
79 SilcUInt64 hval2;
80 SilcUInt64 hval3;
81
82 void *mutex_thread_hold(void *context)
83 {
84   Context *c = context;
85   SilcInt64 s;
86   register int i;
87
88   s = rdtsc();
89   for (i = 0; i < max_locks / 4; i++) {
90     silc_mutex_lock(mutex);
91     hval2 = i;
92     hval3 = 0;
93     hval++;
94     hval3 = hval2 + i;
95     hval += hval2;
96     hval3 += hval;
97     if (silc_unlikely(hval3 != hval2 + i + hval)) {
98       fprintf(stderr, "MUTEX CORRUPT 1\n");
99       exit(1);
100     }
101     if (silc_unlikely(hval2 != i)) {
102       fprintf(stderr, "MUTEX CORRUPT 2 (%llu != %d)\n", hval2, i);
103       exit(1);
104     }
105     silc_mutex_unlock(mutex);
106   }
107   c->time = rdtsc() - s;
108   c->time /= cpu_freq;
109
110   return NULL;
111 }
112
113 int main(int argc, char **argv)
114 {
115   Context c[MAX_THREADS * MAX_MUL];
116   SilcInt64 val;
117   int k, i, j, o = 0;
118   SilcBool success;
119
120   if (argc <= 1) {
121     fprintf(stderr, "Usage: ./test_silcmutex <cpu_freq_mhz>\n");
122     fprintf(stderr, "Example: ./test_silcmutex 3000\n");
123     exit(1);
124   }
125   cpu_freq = (SilcUInt64)atoi(argv[1]);
126   cpu_freq *= 1000;     /* Will give us milliseconds */
127
128   max_locks = MAX_LOCKS;
129
130   fprintf(stderr, "lock/unlock per second\n");
131
132   for (j = 0; j < MAX_ROUND; j++) {
133     for (i = 0; i < 1; i++)
134       c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
135
136     val = 0;
137     for (i = 0; i < 1; i++) {
138       silc_thread_wait(c[i].thread, NULL);
139       val += c[i].time;
140     }
141     fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
142                       (1000LL * max_locks * 1) / val, 1);
143
144     if (o == 0) {
145       /* If MAX_LOCKS is too large for this CPU, optimize.  We don't want to
146          wait a whole day for this test. */
147       if ((SilcInt64)(max_locks / 10) >
148           (SilcInt64)((1000LL * max_locks) / val))
149         max_locks /= 10;
150       o = 1;
151     }
152   }
153   puts("");
154
155   max_locks2 = max_locks;
156   for (k = 0; k < MAX_MUL; k++) {
157     sleep(16);
158     max_locks = max_locks2 / (k + 1);
159     for (j = 0; j < MAX_ROUND; j++) {
160       for (i = 0; i < MAX_THREADS * (k + 1); i++)
161         c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
162
163       val = 0;
164       for (i = 0; i < MAX_THREADS * (k + 1); i++) {
165         silc_thread_wait(c[i].thread, NULL);
166         val += c[i].time;
167       }
168       fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
169                       (1000LL * max_locks * (MAX_THREADS * (k + 1))) / val,
170                       MAX_THREADS * (k + 1));
171     }
172     puts("");
173   }
174   max_locks = max_locks2;
175
176   fprintf(stderr, "Spinning/holding lock, lock/unlock per second\n");
177
178   max_locks /= 2;
179   sleep(5);
180   for (j = 0; j < MAX_ROUND / 2; j++) {
181     for (i = 0; i < 1; i++)
182       c[i].thread = silc_thread_create(mutex_thread_hold, &c[i], TRUE);
183
184     val = 0;
185     for (i = 0; i < 1; i++) {
186       silc_thread_wait(c[i].thread, NULL);
187       val += c[i].time;
188     }
189     fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
190                       (1000LL * (max_locks / 4) * 1) / val, 1);
191   }
192   puts("");
193
194   max_locks2 = max_locks;
195   max_locks2 /= 2;
196   for (k = 0; k < MAX_MUL; k++) {
197     sleep(2);
198     max_locks = max_locks2 / (k + 1);
199     for (j = 0; j < MAX_ROUND / 2; j++) {
200       hval = hval2 = 1;
201       for (i = 0; i < MAX_THREADS * (k + 1); i++)
202         c[i].thread = silc_thread_create(mutex_thread_hold, &c[i], TRUE);
203
204       val = 0;
205       for (i = 0; i < MAX_THREADS * (k + 1); i++) {
206         silc_thread_wait(c[i].thread, NULL);
207         val += c[i].time;
208       }
209       fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
210                       (1000LL * (max_locks / 4) *
211                        (MAX_THREADS * (k + 1))) / val,
212                       MAX_THREADS * (k + 1));
213     }
214     puts("");
215   }
216
217   success = TRUE;
218
219   fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
220
221   return success;
222 }