1 /* Measure mutex_lock for different threads and critical sections.
2 Copyright (C) 2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
20 #define TEST_NAME "pthread-mutex-locks"
21 #define TIMEOUT (20 * 60)
30 #include <sys/sysinfo.h>
31 #include "bench-timing.h"
34 static pthread_mutex_t lock
;
35 static pthread_mutexattr_t attr
;
36 static pthread_barrier_t barrier
;
38 #define START_ITERS 1000
40 #pragma GCC push_options
41 #pragma GCC optimize(1)
43 static int __attribute__ ((noinline
)) fibonacci (int i
)
47 return fibonacci (i
- 1) + fibonacci (i
- 2);
54 char buf1
[512], buf2
[512];
55 int f
= fibonacci (4);
56 memcpy (buf1
, buf2
, f
);
60 do_filler_shared (void)
62 static char buf1
[512], buf2
[512];
63 int f
= fibonacci (4);
64 memcpy (buf1
, buf2
, f
);
67 #pragma GCC pop_options
69 #define UNIT_WORK_CRT do_filler_shared ()
70 #define UNIT_WORK_NON_CRT do_filler ()
73 critical_section (int length
)
75 for (int i
= length
; i
>= 0; i
--)
80 non_critical_section (int length
)
82 for (int i
= length
; i
>= 0; i
--)
86 typedef struct Worker_Params
98 Worker_Params
*p
= (Worker_Params
*) v
;
99 long iters
= p
->iters
;
100 int crt_len
= p
->crt_len
;
101 int non_crt_len
= p
->non_crt_len
;
103 pthread_barrier_wait (&barrier
);
107 pthread_mutex_lock (&lock
);
108 critical_section (crt_len
);
109 pthread_mutex_unlock (&lock
);
110 non_critical_section (non_crt_len
);
114 TIMING_DIFF (p
->duration
, start
, stop
);
119 do_one_test (int num_threads
, int crt_len
, int non_crt_len
, long iters
)
123 Worker_Params
*p
, params
[num_threads
];
124 pthread_t threads
[num_threads
];
126 pthread_mutex_init (&lock
, &attr
);
127 pthread_barrier_init (&barrier
, NULL
, num_threads
);
129 for (i
= 0; i
< num_threads
; i
++)
133 p
->crt_len
= crt_len
;
134 p
->non_crt_len
= non_crt_len
;
135 pthread_create (&threads
[i
], NULL
, worker
, (void *) p
);
137 for (i
= 0; i
< num_threads
; i
++)
138 pthread_join (threads
[i
], NULL
);
140 pthread_mutex_destroy (&lock
);
141 pthread_barrier_destroy (&barrier
);
144 for (i
= 0; i
< num_threads
; i
++)
145 mean
+= params
[i
].duration
;
151 #define MIN_TEST_SEC 0.01
154 do_bench_one (const char *name
, int num_threads
, int crt_len
, int non_crt_len
,
158 struct timeval ts
, te
;
160 long iters
, iters_limit
, total_iters
;
161 timing_t curs
[RUN_COUNT
+ 2];
166 iters_limit
= LONG_MAX
/ 100;
170 gettimeofday (&ts
, NULL
);
171 cur
= do_one_test (num_threads
, crt_len
, non_crt_len
, iters
);
172 gettimeofday (&te
, NULL
);
173 /* Make sure the test to run at least MIN_TEST_SEC. */
174 tsd
= ts
.tv_sec
+ ts
.tv_usec
/ 1000000.0;
175 ted
= te
.tv_sec
+ te
.tv_usec
/ 1000000.0;
177 if (td
>= MIN_TEST_SEC
|| iters
>= iters_limit
)
184 for (i
= 1; i
< RUN_COUNT
+ 2; i
++)
185 curs
[i
] = do_one_test (num_threads
, crt_len
, non_crt_len
, iters
);
187 /* Sort the results so we can discard the fastest and slowest
188 times as outliers. */
189 for (i
= 0; i
< RUN_COUNT
+ 1; i
++)
190 for (j
= i
+ 1; j
< RUN_COUNT
+ 2; j
++)
191 if (curs
[i
] > curs
[j
])
193 timing_t temp
= curs
[i
];
198 /* Calculate mean and standard deviation. */
200 total_iters
= iters
* num_threads
;
201 for (i
= 1; i
< RUN_COUNT
+ 1; i
++)
202 mean
+= (double) curs
[i
] / (double) total_iters
;
206 for (i
= 1; i
< RUN_COUNT
+ 1; i
++)
208 double s
= (double) curs
[i
] / (double) total_iters
- mean
;
211 stdev
= sqrt (stdev
/ (RUN_COUNT
- 1));
214 snprintf (buf
, sizeof buf
, "%s,non_crt_len=%d,crt_len=%d,threads=%d", name
,
215 non_crt_len
, crt_len
, num_threads
);
217 json_attr_object_begin (js
, buf
);
219 json_attr_double (js
, "duration", (double) cur
);
220 json_attr_double (js
, "iterations", (double) total_iters
);
221 json_attr_double (js
, "mean", mean
);
222 json_attr_double (js
, "stdev", stdev
);
223 json_attr_double (js
, "min-outlier",
224 (double) curs
[0] / (double) total_iters
);
225 json_attr_double (js
, "min", (double) curs
[1] / (double) total_iters
);
226 json_attr_double (js
, "max",
227 (double) curs
[RUN_COUNT
] / (double) total_iters
);
228 json_attr_double (js
, "max-outlier",
229 (double) curs
[RUN_COUNT
+ 1] / (double) total_iters
);
231 json_attr_object_end (js
);
234 #define TH_CONF_MAX 10
242 int th_num
, th_conf
, nprocs
;
243 int threads
[TH_CONF_MAX
];
244 int crt_lens
[] = { 0, 1, 2, 4, 8, 16, 32, 64, 128 };
245 int non_crt_lens
[] = { 1, 32, 128 };
248 json_init (&json_ctx
, 2, stdout
);
249 json_attr_object_begin (&json_ctx
, "pthread_mutex_locks");
251 /* The thread config begins from 1, and increases by 2x until nprocs.
252 We also wants to test over-saturation case (1.25*nprocs). */
253 nprocs
= get_nprocs ();
255 for (th_conf
= 0; th_conf
< (TH_CONF_MAX
- 2) && th_num
< nprocs
; th_conf
++)
257 threads
[th_conf
] = th_num
;
260 threads
[th_conf
++] = nprocs
;
261 threads
[th_conf
++] = nprocs
+ nprocs
/ 4;
263 pthread_mutexattr_init (&attr
);
264 pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_ADAPTIVE_NP
);
265 snprintf (name
, sizeof name
, "type=adaptive");
267 for (k
= 0; k
< (sizeof (non_crt_lens
) / sizeof (int)); k
++)
269 int non_crt_len
= non_crt_lens
[k
];
270 for (j
= 0; j
< (sizeof (crt_lens
) / sizeof (int)); j
++)
272 int crt_len
= crt_lens
[j
];
273 for (i
= 0; i
< th_conf
; i
++)
276 do_bench_one (name
, th_num
, crt_len
, non_crt_len
, &json_ctx
);
281 json_attr_object_end (&json_ctx
);
286 #define TEST_FUNCTION do_bench ()
288 #include "../test-skeleton.c"