1b4da6186a2262cc84784ca76b5a8da702399370
[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 271234567
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 += hval;
94     hval3 = hval2 + i;
95     if (hval > max_locks)
96       hval = 0;
97     if (hval < max_locks)
98       hval = max_locks;
99     hval += hval;
100     hval3 += hval;
101     if (silc_unlikely(hval3 != hval2 + i + hval)) {
102       fprintf(stderr, "MUTEX CORRUPT 1\n");
103       exit(1);
104     }
105     if (silc_unlikely(hval2 != i)) {
106       fprintf(stderr, "MUTEX CORRUPT 2 (%llu != %d)\n", hval2, i);
107       exit(1);
108     }
109     silc_mutex_unlock(mutex);
110   }
111   c->time = rdtsc() - s;
112   c->time /= cpu_freq;
113
114   return NULL;
115 }
116
117 int main(int argc, char **argv)
118 {
119   Context c[MAX_THREADS * MAX_MUL];
120   SilcInt64 val;
121   int k, i, j, o = 0;
122   SilcBool success;
123
124   if (argc <= 1) {
125     fprintf(stderr, "Usage: ./test_silcmutex <cpu_freq_mhz>\n");
126     fprintf(stderr, "Example: ./test_silcmutex 3000\n");
127     exit(1);
128   }
129   cpu_freq = (SilcUInt64)atoi(argv[1]);
130   cpu_freq *= 1000;     /* Will give us milliseconds */
131
132   max_locks = MAX_LOCKS;
133
134   fprintf(stderr, "lock/unlock per second\n");
135
136   for (j = 0; j < MAX_ROUND; j++) {
137     for (i = 0; i < 1; i++)
138       c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
139
140     val = 0;
141     for (i = 0; i < 1; i++) {
142       silc_thread_wait(c[i].thread, NULL);
143       val += c[i].time;
144     }
145     fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
146                       (1000LL * max_locks * 1) / val, 1);
147
148     if (o == 0) {
149       /* If MAX_LOCKS is too large for this CPU, optimize.  We don't want to
150          wait a whole day for this test. */
151       if ((SilcInt64)(max_locks / 10) >
152           (SilcInt64)((1000LL * max_locks) / val))
153         max_locks /= 10;
154       o = 1;
155     }
156   }
157   puts("");
158
159   max_locks2 = max_locks;
160   for (k = 0; k < MAX_MUL; k++) {
161     sleep(16);
162     max_locks = max_locks2 / (k + 1);
163     for (j = 0; j < MAX_ROUND; j++) {
164       for (i = 0; i < MAX_THREADS * (k + 1); i++)
165         c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
166
167       val = 0;
168       for (i = 0; i < MAX_THREADS * (k + 1); i++) {
169         silc_thread_wait(c[i].thread, NULL);
170         val += c[i].time;
171       }
172       fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
173                       (1000LL * max_locks * (MAX_THREADS * (k + 1))) / val,
174                       MAX_THREADS * (k + 1));
175     }
176     puts("");
177   }
178   max_locks = max_locks2;
179
180   fprintf(stderr, "Spinning/holding lock, lock/unlock per second\n");
181
182   sleep(16);
183   for (j = 0; j < MAX_ROUND; j++) {
184     for (i = 0; i < 1; i++)
185       c[i].thread = silc_thread_create(mutex_thread_hold, &c[i], TRUE);
186
187     val = 0;
188     for (i = 0; i < 1; i++) {
189       silc_thread_wait(c[i].thread, NULL);
190       val += c[i].time;
191     }
192     fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
193                       (1000LL * (max_locks / 4)) / val, 1);
194   }
195   puts("");
196
197   max_locks2 = max_locks;
198   for (k = 0; k < MAX_MUL; k++) {
199     sleep(16);
200     max_locks = max_locks2 / (k + 1);
201     for (j = 0; j < MAX_ROUND; j++) {
202       hval = hval2 = 1;
203       for (i = 0; i < MAX_THREADS * (k + 1); i++)
204         c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
205
206       val = 0;
207       for (i = 0; i < MAX_THREADS * (k + 1); i++) {
208         silc_thread_wait(c[i].thread, NULL);
209         val += c[i].time;
210       }
211       fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
212                       (1000LL * (max_locks / 4) *
213                        (MAX_THREADS * (k + 1))) / val,
214                       MAX_THREADS * (k + 1));
215     }
216     puts("");
217   }
218   max_locks = max_locks2;
219
220   success = TRUE;
221
222   fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
223
224   return success;
225 }