From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1879) id F23403858428; Tue, 8 Nov 2022 21:52:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F23403858428 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1667944368; bh=2/bvbnFiN3Bo9XK31BBWI9iFXTixbViA+aKGDRRiFM4=; h=From:To:Subject:Date:From; b=ao6sWigezkgyyQoAmhyq0lYpRrEVcY+BQhIMrL6zv6deaHji4FztpzRqsPT7jfsW4 1g6+Tz8O+CMuoamfNvLFf5lXUo1u54Bh/lbkRpvnjkkUmCqzrDTGRlQaEPJnE+yY7w 3VHDiEvF1raDeNfFkhPgybQTWZrLKGK59gglHwe4= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Simon Marchi To: gdb-cvs@sourceware.org Subject: [binutils-gdb] gdb/linux-nat: get core count using /sys/devices/system/cpu/possible X-Act-Checkin: binutils-gdb X-Git-Author: Simon Marchi X-Git-Refname: refs/heads/master X-Git-Oldrev: 7a283d9cf5ccf26321f33812e79cf1515288ac94 X-Git-Newrev: 2b142a9f83f56fbbc1c9fe45f2ea19cd11db2795 Message-Id: <20221108215248.F23403858428@sourceware.org> Date: Tue, 8 Nov 2022 21:52:48 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D2b142a9f83f5= 6fbbc1c9fe45f2ea19cd11db2795 commit 2b142a9f83f56fbbc1c9fe45f2ea19cd11db2795 Author: Simon Marchi Date: Fri Nov 4 10:07:09 2022 -0400 gdb/linux-nat: get core count using /sys/devices/system/cpu/possible =20 I get this test failure on my CI; =20 FAIL: gdb.base/info-os.exp: get process list =20 The particularity of this setup is that builds are done in containers who are allocated 4 CPUs on a machine that has 40. The code in nat/linux-osdata.c fails to properly fetch the core number for each task. =20 linux_xfer_osdata_processes uses `sysconf (_SC_NPROCESSORS_ONLN)`, which returns 4, so it allocates an array of 4 integers. However, the core numbers read from /proc/pid/task/tid/stat, by function linux_common_core_of_thread, returns a value anywhere between 0 and 39. The core numbers above 3 are therefore ignored, many processes end up with no core value, and the regexp in the test doesn't match (it requires an integer as the core field). =20 The way this the CPUs are exposed to the container is that the container sees 40 CPUs "present" and "possible", but only 4 arbitrary CPUs actually online: =20 root@ci-node-jammy-amd64-04-08:~# cat /sys/devices/system/cpu/prese= nt 0-39 root@ci-node-jammy-amd64-04-08:~# cat /sys/devices/system/cpu/online 5,11,24,31 root@ci-node-jammy-amd64-04-08:~# cat /sys/devices/system/cpu/possi= ble 0-39 =20 The solution proposed in this patch is to find out the number of possible CPUs using /sys/devices/system/cpu/possible. In practice, this will probably always contain `0-N`, where N is the number of CPUs, minus one. But the documentation [1] doesn't such guarantee, so I'll assume that it can contain a more complex range list such as `2,4-31,32-63`, like the other files in that directory can have. The solution is to iterate over these numbers to find the highest possible CPU id, and use that that value plus one as the size of the array to allocate. =20 [1] https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst =20 Change-Id: I7abce2e43b000c1327fa94cd7b99d46e49d7ccf3 Diff: --- gdb/nat/linux-osdata.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++= +--- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/gdb/nat/linux-osdata.c b/gdb/nat/linux-osdata.c index f9c43f6691e..8639f090910 100644 --- a/gdb/nat/linux-osdata.c +++ b/gdb/nat/linux-osdata.c @@ -271,6 +271,68 @@ get_cores_used_by_process (PID_T pid, int *cores, cons= t int num_cores) return task_count; } =20 +/* get_core_array_size helper that uses /sys/devices/system/cpu/possible. = */ + +static gdb::optional +get_core_array_size_using_sys_possible () +{ + gdb::optional possible + =3D read_text_file_to_string ("/sys/devices/system/cpu/possible"); + + if (!possible.has_value ()) + return {}; + + /* The format is documented here: + + https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst + + For the purpose of this function, we assume the file can contain a co= mplex + set of ranges, like `2,4-31,32-63`. Read all number, disregarding co= mmands + and dashes, in order to find the largest possible core number. The s= ize + of the array to allocate is that plus one. */ + + unsigned long max_id =3D 0; + for (std::string::size_type start =3D 0; start < possible->size ();) + { + const char *start_p =3D &(*possible)[start]; + char *end_p; + + /* Parse one number. */ + errno =3D 0; + unsigned long id =3D strtoul (start_p, &end_p, 10); + if (errno !=3D 0) + return {}; + + max_id =3D std::max (max_id, id); + + start +=3D end_p - start_p; + gdb_assert (start <=3D possible->size ()); + + /* Skip comma, dash, or new line (if we are at the end). */ + ++start; + } + + return max_id + 1; +} + +/* Return the array size to allocate in order to be able to index it using + CPU core numbers. This may be more than the actual number of cores if + the core numbers are not contiguous. */ + +static size_t +get_core_array_size () +{ + /* Using /sys/.../possible is prefered, because it handles the case where + we are in a container that has access to a subset of the host's cores. + It will return a size that considers all the CPU cores available to t= he + host. If that fials for some reason, fall back to sysconf. */ + gdb::optional count =3D get_core_array_size_using_sys_possible (= ); + if (count.has_value ()) + return *count; + + return sysconf (_SC_NPROCESSORS_ONLN); +} + static void linux_xfer_osdata_processes (struct buffer *buffer) { @@ -281,7 +343,7 @@ linux_xfer_osdata_processes (struct buffer *buffer) dirp =3D opendir ("/proc"); if (dirp) { - const int num_cores =3D sysconf (_SC_NPROCESSORS_ONLN); + const int core_array_size =3D get_core_array_size (); struct dirent *dp; =20 while ((dp =3D readdir (dirp)) !=3D NULL) @@ -308,10 +370,10 @@ linux_xfer_osdata_processes (struct buffer *buffer) strcpy (user, "?"); =20 /* Find CPU cores used by the process. */ - cores =3D XCNEWVEC (int, num_cores); - task_count =3D get_cores_used_by_process (pid, cores, num_cores); + cores =3D XCNEWVEC (int, core_array_size); + task_count =3D get_cores_used_by_process (pid, cores, core_array_size); =20 - for (i =3D 0; i < num_cores && task_count > 0; ++i) + for (i =3D 0; i < core_array_size && task_count > 0; ++i) if (cores[i]) { string_appendf (cores_str, "%d", i);