/* SPDX-License-Identifier: LGPL-2.1+ */ #include "alloc-util.h" #include "cpu-set-util.h" #include "string-util.h" #include "macro.h" static void test_parse_cpu_set(void) { CPUSet c = {}; _cleanup_free_ char *str = NULL; int cpu; log_info("/* %s */", __func__); /* Single value */ assert_se(parse_cpu_set_full("0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.set); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_ISSET_S(0, c.allocated, c.set)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 1); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "0")); str = mfree(str); cpu_set_reset(&c); /* Simple range (from CPUAffinity example) */ assert_se(parse_cpu_set_full("1 2 4", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.set); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_ISSET_S(1, c.allocated, c.set)); assert_se(CPU_ISSET_S(2, c.allocated, c.set)); assert_se(CPU_ISSET_S(4, c.allocated, c.set)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 3); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "1-2 4")); str = mfree(str); cpu_set_reset(&c); /* A more interesting range */ assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); for (cpu = 0; cpu < 4; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); for (cpu = 8; cpu < 12; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "0-3 8-11")); str = mfree(str); cpu_set_reset(&c); /* Quoted strings */ assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 4); for (cpu = 8; cpu < 12; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "8-11")); str = mfree(str); cpu_set_reset(&c); /* Use commas as separators */ assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); for (cpu = 0; cpu < 4; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); for (cpu = 8; cpu < 12; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); cpu_set_reset(&c); /* Commas with spaces (and trailing comma, space) */ assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, 63, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 9); for (cpu = 0; cpu < 8; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); assert_se(CPU_ISSET_S(63, c.allocated, c.set)); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "0-7 63")); str = mfree(str); cpu_set_reset(&c); /* Ranges */ assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); for (cpu = 0; cpu < 4; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); for (cpu = 8; cpu < 12; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); cpu_set_reset(&c); /* Ranges with trailing comma, space */ assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); for (cpu = 0; cpu < 4; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); for (cpu = 8; cpu < 12; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "0-3 8-11")); str = mfree(str); cpu_set_reset(&c); /* Negative range (returns empty cpu_set) */ assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 0); cpu_set_reset(&c); /* Overlapping ranges */ assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 12); for (cpu = 0; cpu < 12; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "0-11")); str = mfree(str); cpu_set_reset(&c); /* Mix ranges and individual CPUs */ assert_se(parse_cpu_set_full("0,2 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); assert_se(CPU_COUNT_S(c.allocated, c.set) == 10); assert_se(CPU_ISSET_S(0, c.allocated, c.set)); assert_se(CPU_ISSET_S(2, c.allocated, c.set)); for (cpu = 4; cpu < 12; cpu++) assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "0 2 4-11")); str = mfree(str); cpu_set_reset(&c); /* Garbage */ assert_se(parse_cpu_set_full("0 1 2 3 garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); assert_se(!c.set); assert_se(c.allocated == 0); /* Range with garbage */ assert_se(parse_cpu_set_full("0-3 8-garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); assert_se(!c.set); assert_se(c.allocated == 0); /* Empty string */ assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); assert_se(!c.set); /* empty string returns NULL */ assert_se(c.allocated == 0); /* Runaway quoted string */ assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); assert_se(!c.set); assert_se(c.allocated == 0); /* Maximum allocation */ assert_se(parse_cpu_set_full("8000-8191", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); assert_se(CPU_COUNT_S(c.allocated, c.set) == 192); assert_se(str = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", str); str = mfree(str); assert_se(str = cpu_set_to_range_string(&c)); log_info("cpu_set_to_range_string: %s", str); assert_se(streq(str, "8000-8191")); str = mfree(str); cpu_set_reset(&c); } static void test_parse_cpu_set_extend(void) { CPUSet c = {}; _cleanup_free_ char *s1 = NULL, *s2 = NULL; log_info("/* %s */", __func__); assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 1); assert_se(CPU_COUNT_S(c.allocated, c.set) == 2); assert_se(s1 = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", s1); assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 1); assert_se(CPU_COUNT_S(c.allocated, c.set) == 3); assert_se(s2 = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", s2); assert_se(parse_cpu_set_extend("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); assert_se(!c.set); assert_se(c.allocated == 0); log_info("cpu_set_to_string: (null)"); } static void test_cpu_set_to_from_dbus(void) { _cleanup_(cpu_set_reset) CPUSet c = {}, c2 = {}; _cleanup_free_ char *s = NULL; log_info("/* %s */", __func__); assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 1); assert_se(s = cpu_set_to_string(&c)); log_info("cpu_set_to_string: %s", s); assert_se(CPU_COUNT_S(c.allocated, c.set) == 104); _cleanup_free_ uint8_t *array = NULL; size_t allocated; static const char expected[32] = "\x0A\x01\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\xF0\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\xFF\xFF\xFF\xFF\xFF\x01"; assert_se(cpu_set_to_dbus(&c, &array, &allocated) == 0); assert_se(array); assert_se(allocated == c.allocated); assert_se(allocated <= sizeof expected); assert_se(allocated >= DIV_ROUND_UP(201u, 8u)); /* We need at least 201 bits for our mask */ assert(memcmp(array, expected, allocated) == 0); assert_se(cpu_set_from_dbus(array, allocated, &c2) == 0); assert_se(c2.set); assert_se(c2.allocated == c.allocated); assert_se(memcmp(c.set, c2.set, c.allocated) == 0); } static void test_cpus_in_affinity_mask(void) { int r; r = cpus_in_affinity_mask(); assert(r > 0); log_info("cpus_in_affinity_mask: %d", r); } int main(int argc, char *argv[]) { log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1)); log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9)); log_info("CPU_ALLOC_SIZE(64) = %zu", CPU_ALLOC_SIZE(64)); log_info("CPU_ALLOC_SIZE(65) = %zu", CPU_ALLOC_SIZE(65)); log_info("CPU_ALLOC_SIZE(1024) = %zu", CPU_ALLOC_SIZE(1024)); log_info("CPU_ALLOC_SIZE(1025) = %zu", CPU_ALLOC_SIZE(1025)); log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191)); test_parse_cpu_set(); test_parse_cpu_set_extend(); test_cpus_in_affinity_mask(); test_cpu_set_to_from_dbus(); return 0; }