5 #include <darwintest.h>
6 #include <darwintest_multiprocess.h>
7 #include <darwintest_utils.h>
10 #include <servers/bootstrap.h>
12 #include <sys/event.h>
14 #include <crt_externs.h>
15 #include <sys/sysctl.h>
16 #include <sys/types.h>
20 T_GLOBAL_META(T_META_NAMESPACE("xnu.kernel_mtx_perf_test"));
23 #define TEST_MTX_MAX_STATS 8
25 #define TEST_MTX_LOCK_STATS 0
26 #define TEST_MTX_UNLOCK_MTX_STATS 6
29 test_from_kernel_lock_unlock_contended(void)
31 int i
, ret
, name_size
;
32 uint64_t avg
, run
, tot
;
35 char *buff
, *buff_p
, *avg_p
, *name
, *end_name
;
37 T_LOG("Testing locking/unlocking mutex from kernel with contention.\n");
38 T_LOG("Requesting test with %d iterations\n", ITER
);
41 buff
= calloc(size
, sizeof(char));
42 T_QUIET
;T_ASSERT_NOTNULL(buff
, "Allocating buffer fo sysctl");
44 snprintf(iter
, sizeof(iter
), "%d", ITER
);
45 ret
= sysctlbyname("kern.test_mtx_contended", buff
, &size
, iter
, sizeof(iter
));
46 T_ASSERT_POSIX_SUCCESS(ret
, "sysctlbyname kern.test_mtx_contended");
48 T_LOG("%s stats:\n%s\n", __func__
, buff
);
50 /* first line is "STATS INNER LOOP" */
52 while( *buff_p
!= '\n' ) buff_p
++;
56 * Sequence of statistic lines like
57 * { samples 100000, tot 3586175 ns, avg 35 ns, max 3997 ns, min 33 ns } TEST_MTX_LOCK_STATS
58 * for all TEST_MTX_MAX_STATS statistics
60 for (i
= 0; i
< TEST_MTX_MAX_STATS
; i
++) {
61 avg_p
= strstr(buff_p
, "avg ");
63 /* contended test records statistics only for lock/unlock for now */
64 if (i
== TEST_MTX_LOCK_STATS
|| i
== TEST_MTX_UNLOCK_MTX_STATS
) {
65 T_QUIET
;T_ASSERT_NOTNULL(avg_p
, "contended %i average not found", i
);
66 sscanf(avg_p
, "avg %llu", &avg
);
68 name
= strstr(buff_p
, "TEST_MTX_");
69 end_name
= strstr(buff_p
, "_STATS");
70 name_size
= end_name
- name
- strlen("TEST_MTX_") + 1;
73 char avg_name_string
[50];
74 char *pre_string
= "contended ";
75 snprintf(name_string
, name_size
+ strlen(pre_string
), "%s%s", pre_string
, &name
[strlen("TEST_MTX_")]);
76 pre_string
= "avg contended ";
77 snprintf(avg_name_string
, name_size
+ strlen(pre_string
), "%s%s", pre_string
, &name
[strlen("TEST_MTX_")]);
78 T_PERF(name_string
, avg
, "ns", avg_name_string
);
82 while( *buff_p
!= '\n' ) buff_p
++;
87 while( *buff_p
!= '\n' ) buff_p
++;
90 /* next line is "STATS OUTER LOOP" */
91 while( *buff_p
!= '\n' ) buff_p
++;
94 /* contended test records statistics only for lock/unlock for now */
95 avg_p
= strstr(buff_p
, "run time ");
96 T_QUIET
;T_ASSERT_NOTNULL(avg_p
, "contended %d loop run time not found", 0);
97 sscanf(avg_p
, "run time %llu", &run
);
99 avg_p
= strstr(buff_p
, "total time ");
100 T_QUIET
;T_ASSERT_NOTNULL(avg_p
, "uncontended %d loop total time not found", 0);
101 sscanf(avg_p
, "total time %llu", &tot
);
108 name
= strstr(buff_p
, "TEST_MTX_");
109 end_name
= strstr(buff_p
, "_STATS");
110 name_size
= end_name
- name
- strlen("TEST_MTX_") + 1;
112 char name_string
[50];
113 char avg_name_string
[60];
114 char *pre_string
= "contended loop ";
115 snprintf(name_string
, name_size
+ strlen(pre_string
), "%s%s", pre_string
, &name
[strlen("TEST_MTX_")]);
116 pre_string
= "avg time contended loop ";
117 snprintf(avg_name_string
, name_size
+ strlen(pre_string
), "%s%s", pre_string
, &name
[strlen("TEST_MTX_")]);
118 T_PERF(name_string
, avg
/ITER
, "ns", avg_name_string
);
124 test_from_kernel_lock_unlock_uncontended(void)
126 int i
, ret
, name_size
;
127 uint64_t avg
, run
, tot
;
130 char *buff
, *buff_p
, *avg_p
, *name
, *end_name
;
132 T_LOG("Testing locking/unlocking mutex from kernel without contention.\n");
133 T_LOG("Requesting test with %d iterations\n", ITER
);
136 buff
= calloc(size
, sizeof(char));
137 T_QUIET
;T_ASSERT_NOTNULL(buff
, "Allocating buffer fo sysctl");
139 snprintf(iter
, sizeof(iter
), "%d", ITER
);
140 ret
= sysctlbyname("kern.test_mtx_uncontended", buff
, &size
, iter
, sizeof(iter
));
141 T_ASSERT_POSIX_SUCCESS(ret
, "sysctlbyname kern.test_mtx_uncontended");
143 T_LOG("%s stats:\n%s\n", __func__
, buff
);
145 /* first line is "STATS INNER LOOP" */
147 while( *buff_p
!= '\n' ) buff_p
++;
151 * Sequence of statistic lines like
152 * { samples 100000, tot 3586175 ns, avg 35 ns, max 3997 ns, min 33 ns } TEST_MTX_LOCK_STATS
153 * for all TEST_MTX_MAX_STATS statistics
155 for (i
= 0; i
< TEST_MTX_MAX_STATS
; i
++) {
156 avg_p
= strstr(buff_p
, "avg ");
157 T_QUIET
;T_ASSERT_NOTNULL(avg_p
, "uncontended %i average not found", i
);
158 sscanf(avg_p
, "avg %llu", &avg
);
160 name
= strstr(buff_p
, "TEST_MTX_");
161 end_name
= strstr(buff_p
, "_STATS");
162 name_size
= end_name
- name
- strlen("TEST_MTX_") + 1;
164 char name_string
[40];
165 char avg_name_string
[50];
166 char *pre_string
= "uncontended ";
167 snprintf(name_string
, name_size
+ strlen(pre_string
), "%s%s", pre_string
, &name
[strlen("TEST_MTX_")]);
168 pre_string
= "avg time uncontended ";
169 snprintf(avg_name_string
, name_size
+ strlen(pre_string
), "%s%s", pre_string
, &name
[strlen("TEST_MTX_")]);
170 T_PERF(name_string
, avg
, "ns", avg_name_string
);
173 while( *buff_p
!= '\n' ) buff_p
++;
177 while( *buff_p
!= '\n' ) buff_p
++;
180 /* next line is "STATS OUTER LOOP" */
181 while( *buff_p
!= '\n' ) buff_p
++;
185 * Sequence of statistic lines like
186 * total time 4040673 ns total run time 3981080 ns TEST_MTX_LOCK_STATS
187 * for all TEST_MTX_MAX_STATS statistics exept UNLOCK
189 for (i
= 0; i
< TEST_MTX_MAX_STATS
- 2; i
++) {
190 avg_p
= strstr(buff_p
, "run time ");
191 T_QUIET
;T_ASSERT_NOTNULL(avg_p
, "uncontended %d loop run time not found", i
);
192 sscanf(avg_p
, "run time %llu", &run
);
194 avg_p
= strstr(buff_p
, "total time ");
195 T_QUIET
;T_ASSERT_NOTNULL(avg_p
, "uncontended %d loop total time not found", i
);
196 sscanf(avg_p
, "total time %llu", &tot
);
203 name
= strstr(buff_p
, "TEST_MTX_");
204 end_name
= strstr(buff_p
, "_STATS");
205 name_size
= end_name
- name
- strlen("TEST_MTX_") + 1;
207 char name_string
[50];
208 char avg_name_string
[60];
209 char *pre_string
= "uncontended loop ";
210 snprintf(name_string
, name_size
+ strlen(pre_string
), "%s%s", pre_string
, &name
[strlen("TEST_MTX_")]);
211 pre_string
= "avg time uncontended loop ";
212 snprintf(avg_name_string
, name_size
+ strlen(pre_string
), "%s%s", pre_string
, &name
[strlen("TEST_MTX_")]);
213 T_PERF(name_string
, avg
/ITER
, "ns", avg_name_string
);
216 while( *buff_p
!= '\n' ) buff_p
++;
223 extern char **environ
;
225 fix_cpu_frequency(void)
229 char *const clpcctrl_args
[] = {"/usr/local/bin/clpcctrl", "-f", "5000", NULL
};
231 T_LOG("Setting cpu frequency to %d\n", 5000);
233 spawn_ret
= posix_spawn(&pid
, clpcctrl_args
[0], NULL
, NULL
, clpcctrl_args
, environ
);
234 waitpid(pid
, &spawn_ret
, 0);
236 #else /*CONFIG_EMBEDDED*/
243 char *buffer
, *cpu_freq
;
246 ret
= sysctlbyname("machdep.cpu.brand_string", NULL
, &len
, NULL
, 0);
247 T_QUIET
;T_ASSERT_POSIX_SUCCESS(ret
, "sysctlbyname machdep.cpu.brand_string");
249 buffer
= malloc(len
+2);
250 ret
= sysctlbyname("machdep.cpu.brand_string", buffer
, &len
, NULL
, 0);
251 T_QUIET
;T_ASSERT_POSIX_SUCCESS(ret
, "sysctlbyname machdep.cpu.brand_string");
252 buffer
[len
+1] = '\0';
254 cpu_freq
= strstr(buffer
, "CPU @ ");
255 if (cpu_freq
== NULL
) {
256 T_LOG("Could not fix frequency, %s field not present\n", "CPU @ ");
260 if (strstr(cpu_freq
, "Hz") != NULL
) {
261 sscanf(cpu_freq
, "CPU @ %f%cHz", &val
, &scale
);
263 if (strstr(cpu_freq
, "hz") != NULL
) {
264 sscanf(cpu_freq
, "CPU @ %f%chz", &val
, &scale
);
266 T_LOG("Could not fix frequency, %s field not present\n", "Hz");
274 nom_freq
= (int) val
;
278 nom_freq
= (int) (val
*1000);
281 T_LOG("Could not fix frequency, scale field is %c\n", scale
);
285 snprintf(str_val
, 10, "%d", nom_freq
);
286 T_LOG("Setting min and max cpu frequency to %d (%s)\n", nom_freq
, str_val
);
287 char *xcpm_args
[] = {"/usr/local/bin/xcpm", "limits", str_val
, str_val
, NULL
};
288 spawn_ret
= posix_spawn(&pid
, xcpm_args
[0], NULL
, NULL
, xcpm_args
, environ
);
289 waitpid(pid
, &spawn_ret
, 0);
294 #endif /*CONFIG_EMBEDDED*/
297 T_DECL(kernel_mtx_perf_test
,
298 "Kernel mutex performance test",
299 T_META_ASROOT(YES
), T_META_CHECK_LEAKS(NO
))
303 test_from_kernel_lock_unlock_uncontended();
304 test_from_kernel_lock_unlock_contended();