]> git.saurik.com Git - apple/xnu.git/blobdiff - tests/kernel_mtx_perf.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / tests / kernel_mtx_perf.c
index 76af0603a67d331f9bb71494d0670ca01d4de869..39a73a070d29ce96a58b390f0700dfd4e7e2437b 100644 (file)
@@ -21,6 +21,10 @@ T_GLOBAL_META(T_META_NAMESPACE("xnu.kernel_mtx_perf_test"));
 
 #define ITER 100000
 #define TEST_MTX_MAX_STATS              8
+#define FULL_CONTENDED 0
+#define HALF_CONTENDED 1
+#define MAX_CONDENDED  2
+
 
 #define TEST_MTX_LOCK_STATS             0
 #define TEST_MTX_UNLOCK_MTX_STATS       6
@@ -28,7 +32,8 @@ T_GLOBAL_META(T_META_NAMESPACE("xnu.kernel_mtx_perf_test"));
 static void
 test_from_kernel_lock_unlock_contended(void)
 {
-       int i, ret, name_size;
+       int i, ret;
+       unsigned long name_size;
        uint64_t avg, run, tot;
        size_t size;
        char iter[35];
@@ -37,7 +42,7 @@ test_from_kernel_lock_unlock_contended(void)
        T_LOG("Testing locking/unlocking mutex from kernel with contention.\n");
        T_LOG("Requesting test with %d iterations\n", ITER);
 
-       size = 1000;
+       size = 2000;
        buff = calloc(size, sizeof(char));
        T_QUIET; T_ASSERT_NOTNULL(buff, "Allocating buffer fo sysctl");
 
@@ -45,85 +50,95 @@ test_from_kernel_lock_unlock_contended(void)
        ret = sysctlbyname("kern.test_mtx_contended", buff, &size, iter, sizeof(iter));
        T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname kern.test_mtx_contended");
 
-       T_LOG("%s stats:\n%s\n", __func__, buff);
+       T_LOG("\n%s stats :\n%s\n", __func__, buff);
 
-       /* first line is "STATS INNER LOOP" */
        buff_p = buff;
-       while (*buff_p != '\n') {
-               buff_p++;
-       }
-       buff_p++;
-
-       /*
-        * Sequence of statistic lines like
-        * { samples 100000, tot 3586175 ns, avg 35 ns, max 3997 ns, min 33 ns } TEST_MTX_LOCK_STATS
-        * for all TEST_MTX_MAX_STATS statistics
-        */
-       for (i = 0; i < TEST_MTX_MAX_STATS; i++) {
-               avg_p = strstr(buff_p, "avg ");
-
-               /* contended test records statistics only for lock/unlock for now */
-               if (i == TEST_MTX_LOCK_STATS || i == TEST_MTX_UNLOCK_MTX_STATS) {
-                       T_QUIET; T_ASSERT_NOTNULL(avg_p, "contended %i average not found", i);
-                       sscanf(avg_p, "avg %llu", &avg);
-
-                       name = strstr(buff_p, "TEST_MTX_");
-                       end_name = strstr(buff_p, "_STATS");
-                       name_size = end_name - name - strlen("TEST_MTX_") + 1;
-
-                       char name_string[40];
-                       char avg_name_string[50];
-                       char *pre_string = "contended ";
-                       snprintf(name_string, name_size + strlen(pre_string), "%s%s", pre_string, &name[strlen("TEST_MTX_")]);
-                       pre_string = "avg contended ";
-                       snprintf(avg_name_string, name_size + strlen(pre_string), "%s%s", pre_string, &name[strlen("TEST_MTX_")]);
-                       T_PERF(name_string, avg, "ns", avg_name_string);
+       int t;
+       for (t = 0; t < MAX_CONDENDED; t++) {
+               char *type;
+               if (t == FULL_CONTENDED) {
+                       type = "FULL_CONTENDED ";
+               } else {
+                       type = "HALF_CONTENDED ";
                }
 
-               buff_p = avg_p;
+               /* first line is "STATS INNER LOOP" */
                while (*buff_p != '\n') {
                        buff_p++;
                }
                buff_p++;
-       }
 
-       while (*buff_p != '\n') {
+               /*
+                * Sequence of statistic lines like
+                * { samples 100000, tot 3586175 ns, avg 35 ns, max 3997 ns, min 33 ns } TEST_MTX_LOCK_STATS
+                * for all TEST_MTX_MAX_STATS statistics
+                */
+               for (i = 0; i < TEST_MTX_MAX_STATS; i++) {
+                       avg_p = strstr(buff_p, "avg ");
+
+                       /* contended test records statistics only for lock/unlock for now */
+                       if (i == TEST_MTX_LOCK_STATS || i == TEST_MTX_UNLOCK_MTX_STATS) {
+                               T_QUIET; T_ASSERT_NOTNULL(avg_p, "contended %i average not found", i);
+                               sscanf(avg_p, "avg %llu", &avg);
+
+                               name = strstr(buff_p, "TEST_MTX_");
+                               end_name = strstr(buff_p, "_STATS");
+                               name_size = (unsigned long) end_name - (unsigned long) name - strlen("TEST_MTX_") + 1;
+
+                               char name_string[40];
+                               char avg_name_string[50];
+                               char *pre_string = "contended ";
+                               snprintf(name_string, name_size + strlen(pre_string) + strlen(type), "%s%s%s", pre_string, type, &name[strlen("TEST_MTX_")]);
+                               pre_string = "avg contended ";
+                               snprintf(avg_name_string, name_size + strlen(pre_string) + strlen(type), "%s%s%s", pre_string, type, &name[strlen("TEST_MTX_")]);
+                               T_PERF(name_string, avg, "ns", avg_name_string);
+                       }
+
+                       buff_p = avg_p;
+                       while (*buff_p != '\n') {
+                               buff_p++;
+                       }
+                       buff_p++;
+               }
+
+               while (*buff_p != '\n') {
+                       buff_p++;
+               }
                buff_p++;
-       }
-       buff_p++;
 
-       /* next line is "STATS OUTER LOOP" */
-       while (*buff_p != '\n') {
+               /* next line is "STATS OUTER LOOP" */
+               while (*buff_p != '\n') {
+                       buff_p++;
+               }
                buff_p++;
-       }
-       buff_p++;
 
-       /* contended test records statistics only for lock/unlock for now */
-       avg_p = strstr(buff_p, "run time ");
-       T_QUIET; T_ASSERT_NOTNULL(avg_p, "contended %d loop run time not found", 0);
-       sscanf(avg_p, "run time %llu", &run);
+               /* contended test records statistics only for lock/unlock for now */
+               avg_p = strstr(buff_p, "run time ");
+               T_QUIET; T_ASSERT_NOTNULL(avg_p, "contended %d loop run time not found", 0);
+               sscanf(avg_p, "run time %llu", &run);
 
-       avg_p = strstr(buff_p, "total time ");
-       T_QUIET; T_ASSERT_NOTNULL(avg_p, "uncontended %d loop total time not found", 0);
-       sscanf(avg_p, "total time %llu", &tot);
+               avg_p = strstr(buff_p, "total time ");
+               T_QUIET; T_ASSERT_NOTNULL(avg_p, "uncontended %d loop total time not found", 0);
+               sscanf(avg_p, "total time %llu", &tot);
 
-       if (run < tot) {
-               avg = run;
-       } else {
-               avg = tot;
-       }
+               if (run < tot) {
+                       avg = run;
+               } else {
+                       avg = tot;
+               }
 
-       name = strstr(buff_p, "TEST_MTX_");
-       end_name = strstr(buff_p, "_STATS");
-       name_size = end_name - name - strlen("TEST_MTX_") + 1;
+               name = strstr(buff_p, "TEST_MTX_");
+               end_name = strstr(buff_p, "_STATS");
+               name_size = (unsigned long) end_name - (unsigned long) name - strlen("TEST_MTX_") + 1;
 
-       char name_string[50];
-       char avg_name_string[60];
-       char *pre_string = "contended loop ";
-       snprintf(name_string, name_size + strlen(pre_string), "%s%s", pre_string, &name[strlen("TEST_MTX_")]);
-       pre_string = "avg time contended loop ";
-       snprintf(avg_name_string, name_size + strlen(pre_string), "%s%s", pre_string, &name[strlen("TEST_MTX_")]);
-       T_PERF(name_string, avg / ITER, "ns", avg_name_string);
+               char name_string[50];
+               char avg_name_string[60];
+               char *pre_string = "contended loop ";
+               snprintf(name_string, name_size + strlen(pre_string) + strlen(type), "%s%s%s", pre_string, type, &name[strlen("TEST_MTX_")]);
+               pre_string = "avg time contended loop ";
+               snprintf(avg_name_string, name_size + strlen(pre_string) + strlen(type), "%s%s%s", pre_string, type, &name[strlen("TEST_MTX_")]);
+               T_PERF(name_string, avg / ITER, "ns", avg_name_string);
+       }
 
        free(buff);
 }
@@ -131,7 +146,8 @@ test_from_kernel_lock_unlock_contended(void)
 static void
 test_from_kernel_lock_unlock_uncontended(void)
 {
-       int i, ret, name_size;
+       int i, ret;
+       unsigned long name_size;
        uint64_t avg, run, tot;
        size_t size;
        char iter[35];
@@ -169,7 +185,7 @@ test_from_kernel_lock_unlock_uncontended(void)
 
                name = strstr(buff_p, "TEST_MTX_");
                end_name = strstr(buff_p, "_STATS");
-               name_size = end_name - name - strlen("TEST_MTX_") + 1;
+               name_size = (unsigned long) end_name - (unsigned long) name - strlen("TEST_MTX_") + 1;
 
                char name_string[40];
                char avg_name_string[50];
@@ -219,7 +235,7 @@ test_from_kernel_lock_unlock_uncontended(void)
 
                name = strstr(buff_p, "TEST_MTX_");
                end_name = strstr(buff_p, "_STATS");
-               name_size = end_name - name - strlen("TEST_MTX_") + 1;
+               name_size = (unsigned long) end_name - (unsigned long) name - strlen("TEST_MTX_") + 1;
 
                char name_string[50];
                char avg_name_string[60];
@@ -238,78 +254,175 @@ test_from_kernel_lock_unlock_uncontended(void)
        free(buff);
 }
 
-extern char **environ;
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+static bool
+get_freq(float val, char scale, int *int_val)
+{
+       switch (scale) {
+       case 'M':
+       case 'm':
+               *int_val = (int) val;
+               break;
+       case 'G':
+       case 'g':
+               *int_val = (int) (val * 1000);
+               break;
+       default:
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static bool
+parse_freq(char* buff, int buff_size, const char* string_start, int string_start_size, char* to_parse)
+{
+       char* start;
+       float val;
+       char scale;
+       int int_val;
+
+       start = strstr(to_parse, string_start);
+       if (start == NULL) {
+               return FALSE;
+       }
+
+       if (strstr(start, "Hz") != NULL) {
+               sscanf(start + string_start_size, "%f%cHz", &val, &scale);
+       } else {
+               if (strstr(start, "hz") != NULL) {
+                       sscanf(start + string_start_size, "%f%chz", &val, &scale);
+               } else {
+                       return FALSE;
+               }
+       }
+
+       if (!get_freq(val, scale, &int_val)) {
+               return FALSE;
+       }
+
+       snprintf(buff, buff_size, "%d", int_val);
+
+       return TRUE;
+}
+
+static bool freq_fixed = FALSE;
+static char str_val_min[10];
+static char str_val_max[10];
+
+static bool
+get_previous_freq_values(void)
+{
+       FILE *fp;
+       char out_xcpm[1035];
+       bool min_scan = FALSE;
+       bool max_scan = FALSE;
+
+       memset(str_val_min, 0, sizeof(str_val_min));
+       memset(str_val_max, 0, sizeof(str_val_max));
+
+       fp = popen("/usr/local/bin/xcpm limits", "r");
+       if (fp == NULL) {
+               return FALSE;
+       }
+
+       while (fgets(out_xcpm, sizeof(out_xcpm) - 1, fp) != NULL && (!max_scan || !min_scan)) {
+               if (!max_scan) {
+                       max_scan = parse_freq(str_val_max, sizeof(str_val_max), "Max frequency:", sizeof("Max frequency:"), out_xcpm);
+               }
+               if (!min_scan) {
+                       min_scan = parse_freq(str_val_min, sizeof(str_val_min), "Min frequency:", sizeof("Min frequency:"), out_xcpm);
+               }
+       }
+
+       pclose(fp);
+
+       if (!max_scan || !min_scan) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+#endif
+
 static void
 fix_cpu_frequency(void)
 {
-#if CONFIG_EMBEDDED
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
        int spawn_ret, pid;
        char *const clpcctrl_args[] = {"/usr/local/bin/clpcctrl", "-f", "5000", NULL};
 
        T_LOG("Setting cpu frequency to %d\n", 5000);
 
-       spawn_ret = posix_spawn(&pid, clpcctrl_args[0], NULL, NULL, clpcctrl_args, environ);
-       waitpid(pid, &spawn_ret, 0);
+       spawn_ret = posix_spawn(&pid, clpcctrl_args[0], NULL, NULL, clpcctrl_args, *_NSGetEnviron());
+       T_QUIET; T_ASSERT_POSIX_ZERO(spawn_ret, "posix_spawn");
+       T_QUIET; T_ASSERT_EQ(waitpid(pid, &spawn_ret, 0), pid, "waitpid failed");
+       T_QUIET; T_ASSERT_EQ(spawn_ret, 0, " clpcctrl failed");
 
-#else /*CONFIG_EMBEDDED*/
+#else /*(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)*/
 
        int spawn_ret, pid;
-       int ret, nom_freq;
+       int ret;
        size_t len;
-       float val;
-       char scale;
-       char *buffer, *cpu_freq;
+       char *buffer;
        char str_val[10];
 
+       if (!get_previous_freq_values()) {
+               T_LOG("Impossible to parse freq values from xcpm");
+               freq_fixed = FALSE;
+               return;
+       }
+
        ret = sysctlbyname("machdep.cpu.brand_string", NULL, &len, NULL, 0);
        T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname machdep.cpu.brand_string");
 
-       buffer = malloc(len + 2);
+       buffer = calloc(len + 2, sizeof(char));
        ret = sysctlbyname("machdep.cpu.brand_string", buffer, &len, NULL, 0);
        T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname machdep.cpu.brand_string");
        buffer[len + 1] = '\0';
 
-       cpu_freq = strstr(buffer, "CPU @ ");
-       if (cpu_freq == NULL) {
-               T_LOG("Could not fix frequency, %s field not present\n", "CPU @ ");
-               goto out;
-       }
-
-       if (strstr(cpu_freq, "Hz") != NULL) {
-               sscanf(cpu_freq, "CPU @ %f%cHz", &val, &scale);
-       } else {
-               if (strstr(cpu_freq, "hz") != NULL) {
-                       sscanf(cpu_freq, "CPU @ %f%chz", &val, &scale);
-               } else {
-                       T_LOG("Could not fix frequency, %s field not present\n", "Hz");
-                       goto out;
-               }
+       memset(str_val, 0, sizeof(str_val));
+       if (!parse_freq(str_val, sizeof(str_val), "CPU @", sizeof("CPU @"), buffer)) {
+               T_LOG("Impossible to parse freq values from machdep.cpu.brand_string (string was %s)", buffer);
+               freq_fixed = FALSE;
+               return;
        }
 
-       switch (scale) {
-       case 'M':
-       case 'm':
-               nom_freq = (int) val;
-               break;
-       case 'G':
-       case 'g':
-               nom_freq = (int) (val * 1000);
-               break;
-       default:
-               T_LOG("Could not fix frequency, scale field is %c\n", scale);
-               goto out;
-       }
-
-       snprintf(str_val, 10, "%d", nom_freq);
-       T_LOG("Setting min and max cpu frequency to %d (%s)\n", nom_freq, str_val);
+       T_LOG("Previous min and max cpu frequency (%s) (%s)\n", str_val_min, str_val_max);
+       T_LOG("Setting min and max cpu frequency to (%s)\n", str_val);
        char *xcpm_args[] = {"/usr/local/bin/xcpm", "limits", str_val, str_val, NULL};
-       spawn_ret = posix_spawn(&pid, xcpm_args[0], NULL, NULL, xcpm_args, environ);
-       waitpid(pid, &spawn_ret, 0);
+       spawn_ret = posix_spawn(&pid, xcpm_args[0], NULL, NULL, xcpm_args, *_NSGetEnviron());
+       T_QUIET; T_ASSERT_POSIX_ZERO(spawn_ret, "posix_spawn");
+       T_QUIET; T_ASSERT_EQ(waitpid(pid, &spawn_ret, 0), pid, "waitpid failed");
+       T_QUIET; T_ASSERT_EQ(spawn_ret, 0, "xcpm limits failed");
+
+       freq_fixed = TRUE;
 
-out:
        free(buffer);
        return;
-#endif /*CONFIG_EMBEDDED*/
+#endif /*(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)*/
+}
+
+static void
+cleanup_cpu_freq(void)
+{
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+       int spawn_ret, pid;
+       char *const clpcctrl_args[] = {"/usr/local/bin/clpcctrl", "-d", NULL};
+       spawn_ret = posix_spawn(&pid, clpcctrl_args[0], NULL, NULL, clpcctrl_args, *_NSGetEnviron());
+       T_QUIET; T_ASSERT_POSIX_ZERO(spawn_ret, "posix_spawn");
+       T_QUIET; T_ASSERT_EQ(waitpid(pid, &spawn_ret, 0), pid, "waitpid failed");
+       T_QUIET; T_ASSERT_EQ(spawn_ret, 0, "clpcctrl failed");
+
+#else
+       if (freq_fixed) {
+               int spawn_ret, pid;
+               char *xcpm_args[] = {"/usr/local/bin/xcpm", "limits", str_val_min, str_val_max, NULL};
+               spawn_ret = posix_spawn(&pid, xcpm_args[0], NULL, NULL, xcpm_args, *_NSGetEnviron());
+               T_QUIET; T_ASSERT_POSIX_ZERO(spawn_ret, "posix_spawn");
+               T_QUIET; T_ASSERT_EQ(waitpid(pid, &spawn_ret, 0), pid, "waitpid failed");
+               T_QUIET; T_ASSERT_EQ(spawn_ret, 0, "xcpm limits failed");
+       }
+#endif
 }
 
 T_DECL(kernel_mtx_perf_test,
@@ -318,6 +431,8 @@ T_DECL(kernel_mtx_perf_test,
 {
        fix_cpu_frequency();
 
+       T_ATEND(cleanup_cpu_freq);
+
        test_from_kernel_lock_unlock_uncontended();
        test_from_kernel_lock_unlock_contended();
 }