/tests/regression/abi0-conflict/app_ust_indirect_abi0_abi1
/tests/regression/abi0-conflict/app_ust_indirect_abi1
/tests/unit/gcc-weak-hidden/test_gcc_weak_hidden
-/tests/unit/libcommon/test_smp
+/tests/unit/libcommon/get_cpu_mask_from_sysfs
+/tests/unit/libcommon/get_max_cpuid_from_sysfs
+/tests/unit/libcommon/test_get_max_cpuid_from_mask
+/tests/unit/libcommon/test_get_possible_cpus_array_len
/tests/unit/libmsgpack/test_msgpack
/tests/unit/libringbuffer/test_shm
/tests/unit/pthread_name/test_pthread_name
static int possible_cpus_array_len_cache;
/*
- * As a fallback to parsing the CPU mask in "/sys/devices/system/cpu/possible",
- * iterate on all the folders in "/sys/devices/system/cpu" that start with
+ * Get the highest CPU id from sysfs.
+ *
+ * Iterate on all the folders in "/sys/devices/system/cpu" that start with
* "cpu" followed by an integer, keep the highest CPU id encountered during
* this iteration and add 1 to get a number of CPUs.
*
- * Then get the value from sysconf(_SC_NPROCESSORS_CONF) as a fallback and
- * return the highest one.
- *
- * On Linux, using the value from sysconf can be unreliable since the way it
- * counts CPUs varies between C libraries and even between versions of the same
- * library. If we used it directly, getcpu() could return a value greater than
- * this sysconf, in which case the arrays indexed by processor would overflow.
- *
- * As another example, the MUSL libc implementation of the _SC_NPROCESSORS_CONF
- * sysconf does not return the number of configured CPUs in the system but
- * relies on the cpu affinity mask of the current task.
- *
- * Returns 0 or less on error.
+ * Returns the highest CPU id, or -1 on error.
*/
-int get_num_possible_cpus_fallback(void)
+int get_max_cpuid_from_sysfs(void)
+{
+ return _get_max_cpuid_from_sysfs("/sys/devices/system/cpu");
+}
+
+int _get_max_cpuid_from_sysfs(const char *path)
{
long max_cpuid = -1;
DIR *cpudir;
struct dirent *entry;
- cpudir = opendir("/sys/devices/system/cpu");
+ assert(path);
+
+ cpudir = opendir(path);
if (cpudir == NULL)
goto end;
max_cpuid = -1;
end:
+ return max_cpuid;
+}
+
+/*
+ * As a fallback to parsing the CPU mask in "/sys/devices/system/cpu/possible",
+ * iterate on all the folders in "/sys/devices/system/cpu" that start with
+ * "cpu" followed by an integer, keep the highest CPU id encountered during
+ * this iteration and add 1 to get a number of CPUs.
+ *
+ * Then get the value from sysconf(_SC_NPROCESSORS_CONF) as a fallback and
+ * return the highest one.
+ *
+ * On Linux, using the value from sysconf can be unreliable since the way it
+ * counts CPUs varies between C libraries and even between versions of the same
+ * library. If we used it directly, getcpu() could return a value greater than
+ * this sysconf, in which case the arrays indexed by processor would overflow.
+ *
+ * As another example, the MUSL libc implementation of the _SC_NPROCESSORS_CONF
+ * sysconf does not return the number of configured CPUs in the system but
+ * relies on the cpu affinity mask of the current task.
+ *
+ * Returns 0 or less on error.
+ */
+int get_num_possible_cpus_fallback(void)
+{
/*
* Get the sysconf value as a last resort. Keep the highest number.
*/
- return __max(sysconf(_SC_NPROCESSORS_CONF), max_cpuid + 1);
+ return __max(sysconf(_SC_NPROCESSORS_CONF), get_max_cpuid_from_sysfs() + 1);
}
/*
* Returns the number of bytes read or -1 on error.
*/
int get_possible_cpu_mask_from_sysfs(char *buf, size_t max_bytes)
+{
+ return get_cpu_mask_from_sysfs(buf, max_bytes,
+ "/sys/devices/system/cpu/possible");
+}
+
+/*
+ * Get a CPU mask string from sysfs.
+ *
+ * buf: the buffer where the mask will be read.
+ * max_bytes: the maximum number of bytes to write in the buffer.
+ * path: file path to read the mask from.
+ *
+ * Returns the number of bytes read or -1 on error.
+ */
+int get_cpu_mask_from_sysfs(char *buf, size_t max_bytes, const char *path)
{
ssize_t bytes_read = 0;
size_t total_bytes_read = 0;
int fd = -1, ret = -1;
+ assert(path);
+
if (buf == NULL)
goto end;
- fd = open("/sys/devices/system/cpu/possible", O_RDONLY);
+ fd = open(path, O_RDONLY);
if (fd < 0)
goto end;
#define LTTNG_UST_CPUMASK_SIZE 4096
+/*
+ * Get a CPU mask string from sysfs.
+ *
+ * buf: the buffer where the mask will be read.
+ * max_bytes: the maximum number of bytes to write in the buffer.
+ * path: file path to read the mask from.
+ *
+ * Returns the number of bytes read or -1 on error.
+ */
+int get_cpu_mask_from_sysfs(char *buf, size_t max_bytes, const char *path)
+ __attribute__((visibility("hidden")));
+
/*
* Get the CPU possible mask string from sysfs.
*
int get_possible_cpu_mask_from_sysfs(char *buf, size_t max_bytes)
__attribute__((visibility("hidden")));
+/*
+ * Get the highest CPU id from sysfs.
+ *
+ * Iterate on all the folders in "/sys/devices/system/cpu" that start with
+ * "cpu" followed by an integer, keep the highest CPU id encountered during
+ * this iteration and add 1 to get a number of CPUs.
+ *
+ * Returns the highest CPU id, or -1 on error.
+ */
+int get_max_cpuid_from_sysfs(void)
+ __attribute__((visibility("hidden")));
+
+int _get_max_cpuid_from_sysfs(const char *path)
+ __attribute__((visibility("hidden")));
+
/*
* Get the number of possible CPUs in the system from either
* sysconf(_SC_NPROCESSORS_CONF) or some other mechanism depending on the libc.
TESTS = \
unit/libringbuffer/test_shm \
unit/gcc-weak-hidden/test_gcc_weak_hidden \
- unit/libcommon/test_smp \
+ unit/libcommon/test_get_cpu_mask_from_sysfs \
+ unit/libcommon/test_get_max_cpuid_from_mask \
+ unit/libcommon/test_get_max_cpuid_from_sysfs \
+ unit/libcommon/test_get_possible_cpus_array_len \
unit/libmsgpack/test_msgpack \
unit/pthread_name/test_pthread_name \
unit/snprintf/test_snprintf \
AM_CPPFLAGS += -I$(top_srcdir)/tests/utils
-noinst_PROGRAMS = test_smp
-test_smp_SOURCES = test_smp.c
-test_smp_LDADD = \
+noinst_PROGRAMS = \
+ get_cpu_mask_from_sysfs \
+ get_max_cpuid_from_sysfs \
+ test_get_max_cpuid_from_mask \
+ test_get_possible_cpus_array_len
+
+dist_noinst_SCRIPTS = \
+ test_get_cpu_mask_from_sysfs \
+ test_get_max_cpuid_from_sysfs
+
+get_cpu_mask_from_sysfs_SOURCES = get_cpu_mask_from_sysfs.c
+get_cpu_mask_from_sysfs_LDADD = \
+ $(top_builddir)/src/common/libcommon.la
+
+get_max_cpuid_from_sysfs_SOURCES = get_max_cpuid_from_sysfs.c
+get_max_cpuid_from_sysfs_LDADD = \
+ $(top_builddir)/src/common/libcommon.la
+
+test_get_max_cpuid_from_mask_SOURCES = test_get_max_cpuid_from_mask.c
+test_get_max_cpuid_from_mask_LDADD = \
+ $(top_builddir)/src/common/libcommon.la \
+ $(top_builddir)/tests/utils/libtap.a
+
+test_get_possible_cpus_array_len_SOURCES = test_get_possible_cpus_array_len.c
+test_get_possible_cpus_array_len_LDADD = \
$(top_builddir)/src/common/libcommon.la \
$(top_builddir)/tests/utils/libtap.a
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2022 Michael Jeanson <mjeanson@efficios.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common/smp.h"
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ char buf[LTTNG_UST_CPUMASK_SIZE];
+
+ if( argc < 2 ) {
+ fprintf(stderr, "Missing argument.\n");
+ return EXIT_FAILURE;
+ }
+
+ ret = get_cpu_mask_from_sysfs((char *) &buf, LTTNG_UST_CPUMASK_SIZE, argv[1]);
+
+ printf("%s", buf);
+
+ if (ret >= 0)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2022 Michael Jeanson <mjeanson@efficios.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common/smp.h"
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if( argc < 2 ) {
+ fprintf(stderr, "Missing argument.\n");
+ return EXIT_FAILURE;
+ }
+
+ ret = _get_max_cpuid_from_sysfs(argv[1]);
+
+ printf("%d\n", ret);
+
+ if (ret >= 0)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
--- /dev/null
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-only
+
+if [ "x${UST_TESTS_SRCDIR:-}" != "x" ]; then
+ UTILSSH="$UST_TESTS_SRCDIR/utils/utils.sh"
+else
+ UTILSSH="$(dirname "$0")/../../utils/utils.sh"
+fi
+
+# shellcheck source=../../utils/utils.sh
+source "$UTILSSH"
+
+# shellcheck source=../../utils/tap.sh
+source "$UST_TESTS_SRCDIR/utils/tap.sh"
+
+CURDIR="${UST_TESTS_BUILDDIR}/unit/libcommon"
+
+NUM_TESTS=8
+
+TESTFILE=$(mktemp)
+
+populate_testfile() {
+ local cpumask="$1"
+
+ # shellcheck disable=SC2059
+ printf "$cpumask" > "$TESTFILE"
+}
+
+test_test_get_cpu_mask_from_sysfs() {
+ local cpumask="$1"
+ local result
+
+ # Without '\n'
+ populate_testfile "$cpumask"
+ result=$("${CURDIR}/get_cpu_mask_from_sysfs" "$TESTFILE")
+ test "$cpumask" == "$result"
+ ok $? "test_get_cpu_mask_from_sysfs - without '\n' expected: '$cpumask', result: '$result'"
+
+ # With '\n'
+ populate_testfile "$cpumask\n"
+ result=$("${CURDIR}/get_cpu_mask_from_sysfs" "$TESTFILE")
+ test "$cpumask" == "$result"
+ ok $? "test_get_cpu_mask_from_sysfs - with '\n' expected: '$cpumask', result: '$result'"
+}
+
+plan_tests $NUM_TESTS
+
+test_test_get_cpu_mask_from_sysfs ""
+test_test_get_cpu_mask_from_sysfs "0"
+test_test_get_cpu_mask_from_sysfs "0-3"
+test_test_get_cpu_mask_from_sysfs "0,3-7,9"
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2022 Michael Jeanson <mjeanson@efficios.com>
+ */
+
+#include <string.h>
+
+#include "tap.h"
+
+#include "common/smp.h"
+
+struct parse_test_data {
+ const char *buf;
+ int expected;
+};
+
+static struct parse_test_data parse_test_data[] = {
+ { "", -1 },
+ { "abc", -1 },
+ { ",,,", -1 },
+ { "--", -1 },
+ { ",", -1 },
+ { "-", -1 },
+ { "2147483647", -1 },
+ { "18446744073709551615", -1 },
+ { "0-2147483647", -1 },
+ { "0-18446744073709551615", -1 },
+ { "0", 0 },
+ { "1", 1 },
+ { "0-1", 1 },
+ { "1-3", 3 },
+ { "0,2", 2 },
+ { "1,2", 2 },
+ { "0,4-6,127", 127 },
+ { "0-4095", 4095 },
+
+ { "\n", -1 },
+ { "abc\n", -1 },
+ { ",,,\n", -1 },
+ { "--\n", -1 },
+ { ",\n", -1 },
+ { "-\n", -1 },
+ { "2147483647\n", -1 },
+ { "18446744073709551615\n", -1 },
+ { "0-2147483647\n", -1 },
+ { "0-18446744073709551615\n", -1 },
+ { "0\n", 0 },
+ { "1\n", 1 },
+ { "0-1\n", 1 },
+ { "1-3\n", 3 },
+ { "0,2\n", 2 },
+ { "1,2\n", 2 },
+ { "0,4-6,127\n", 127 },
+ { "0-4095\n", 4095 },
+};
+
+static int parse_test_data_len = sizeof(parse_test_data) / sizeof(parse_test_data[0]);
+
+int main(void)
+{
+ int ret, i;
+
+ plan_tests(parse_test_data_len);
+
+ diag("Testing smp helpers");
+
+ for (i = 0; i < parse_test_data_len; i++) {
+ ret = get_max_cpuid_from_mask(parse_test_data[i].buf,
+ strlen(parse_test_data[i].buf));
+ ok(ret == parse_test_data[i].expected,
+ "get_max_cpuid_from_mask '%s', expected: '%d', result: '%d'",
+ parse_test_data[i].buf, parse_test_data[i].expected, ret);
+ }
+
+ return exit_status();
+}
--- /dev/null
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-only
+
+if [ "x${UST_TESTS_SRCDIR:-}" != "x" ]; then
+ UTILSSH="$UST_TESTS_SRCDIR/utils/utils.sh"
+else
+ UTILSSH="$(dirname "$0")/../../utils/utils.sh"
+fi
+
+# shellcheck source=../../utils/utils.sh
+source "$UTILSSH"
+
+# shellcheck source=../../utils/tap.sh
+source "$UST_TESTS_SRCDIR/utils/tap.sh"
+
+CURDIR="${UST_TESTS_BUILDDIR}/unit/libcommon"
+
+STD_OUTPUT="/dev/null"
+STD_ERROR="/dev/null"
+
+NUM_TESTS=13
+
+TESTDIR=$(mktemp -d)
+
+populate_testdir() {
+ local cpus=("$@")
+
+ mkdir "$TESTDIR"
+
+ for i in "${cpus[@]}"; do
+ mkdir "$TESTDIR/$i"
+ done
+}
+
+test_get_max_cpuid_from_sysfs() {
+ local num_cpus=$1
+ shift
+ local current_cpus=("$@")
+ local result
+
+ populate_testdir "${current_cpus[@]}" >"$STD_OUTPUT" 2>"$STD_ERROR"
+ result=$("${CURDIR}/get_max_cpuid_from_sysfs" "$TESTDIR")
+ is "$result" "$num_cpus" "get_max_cpuid_from_sysfs - cpu set: '${current_cpus[*]}', expected: '$num_cpus', result: '$result'"
+ rm -rf "$TESTDIR"
+}
+
+plan_tests $NUM_TESTS
+
+diag "get_max_cpuid_from_sysfs"
+
+test_data=(0 "cpu0")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(1 "cpu0" "cpu1")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(1 "cpu1" "cpu0")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(3 "cpu3")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(99 "cpu99")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(3 "cpu0" "cpu3")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(3 "cpufreq" "cpuidle" "cpu0" "cpu1" "cpu2" "cpu3")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(0 "cpu" "cpu0")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(5 "cpu" "cpu5")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+
+test_data=(-1 "toto")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(-1 "cpu")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(-1 "cpua" "cpud")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
+
+test_data=(-1 "cpufreq" "cpuidle")
+test_get_max_cpuid_from_sysfs "${test_data[@]}"
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2022 Michael Jeanson <mjeanson@efficios.com>
+ */
+
+#include <stdio.h>
+
+#include "tap.h"
+
+#include "common/smp.h"
+
+int main(void)
+{
+ int ret;
+
+ plan_tests(2);
+
+ ret = get_possible_cpus_array_len();
+ ok(ret > 0, "get_possible_cpus_array_len (%d > 0)", ret);
+
+ ret = get_num_possible_cpus_fallback();
+ ok(ret > 0, "get_num_possible_cpus_fallback (%d > 0)", ret);
+
+ return exit_status();
+}
+++ /dev/null
-/*
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
- */
-
-#include <assert.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "tap.h"
-
-#include "common/smp.h"
-
-struct parse_test_data {
- const char *buf;
- int expected;
-};
-
-static struct parse_test_data parse_test_data[] = {
- { "", -1 },
- { "abc", -1 },
- { ",,,", -1 },
- { "--", -1 },
- { ",", -1 },
- { "-", -1 },
- { "2147483647", -1 },
- { "18446744073709551615", -1 },
- { "0-2147483647", -1 },
- { "0-18446744073709551615", -1 },
- { "0", 0 },
- { "1", 1 },
- { "0-1", 1 },
- { "1-3", 3 },
- { "0,2", 2 },
- { "1,2", 2 },
- { "0,4-6,127", 127 },
- { "0-4095", 4095 },
-
- { "\n", -1 },
- { "abc\n", -1 },
- { ",,,\n", -1 },
- { "--\n", -1 },
- { ",\n", -1 },
- { "-\n", -1 },
- { "2147483647\n", -1 },
- { "18446744073709551615\n", -1 },
- { "0-2147483647\n", -1 },
- { "0-18446744073709551615\n", -1 },
- { "0\n", 0 },
- { "1\n", 1 },
- { "0-1\n", 1 },
- { "1-3\n", 3 },
- { "0,2\n", 2 },
- { "1,2\n", 2 },
- { "0,4-6,127\n", 127 },
- { "0-4095\n", 4095 },
-};
-
-static int parse_test_data_len = sizeof(parse_test_data) / sizeof(parse_test_data[0]);
-
-int main(void)
-{
- int ret, i;
-
- plan_tests(parse_test_data_len + 1);
-
- diag("Testing smp helpers");
-
- for (i = 0; i < parse_test_data_len; i++) {
- ret = get_max_cpuid_from_mask(parse_test_data[i].buf,
- strlen(parse_test_data[i].buf));
- ok(ret == parse_test_data[i].expected,
- "get_max_cpuid_from_mask '%s', expected: '%d', result: '%d'",
- parse_test_data[i].buf, parse_test_data[i].expected, ret);
- }
-
- ok(get_possible_cpus_array_len() > 0, "get_possible_cpus_array_len (%d > 0)", get_possible_cpus_array_len());
-
- return exit_status();
-}