From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 3E14E4582E; Wed, 21 Aug 2024 11:45:16 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 72F4A40EE6; Wed, 21 Aug 2024 11:45:07 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.20]) by mails.dpdk.org (Postfix) with ESMTP id 9F62C4003C for ; Wed, 21 Aug 2024 11:45:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724233504; x=1755769504; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VhBjAfuOAKig3mEaLsIhgFzh2dNqgoqBJz19Fl/eMfc=; b=ItWe7HKxGSq1c682OYe5k4LoB3C+vd6QoJ1ZeqjqFmcSkb4cZ2wQLbX3 RFFxiKv6MbtAULXdQUhO8Huz/KqRUgwj7lPG+qD2UcWKVh5eCf71JOOkD xsLE8udpJbDkOzsl9Q8NpxlDyK9wQ6qWTqLxEcXLZLABK1pFVxj3QpO9w +vpaDv+SuF5MrukcW1+aw6rOEJGEmBZSTDQ0+jdMWZ1X9FxwpUu47QdKh j+P4OvXXxJRt5EX1D1aiGNGNxFjJg5/JCEssuuwQkgotgvEWt2+FDM7wK KMIolxrF9kXCI+L0W3rt6p0dzOlLC5FOgw9ec3as3mN7tmq2g3/S5/7P4 w==; X-CSE-ConnectionGUID: SJRk5uxOQ560lKXlDGIGlw== X-CSE-MsgGUID: ZFcfK2/XT0WI9RZNc0bDyA== X-IronPort-AV: E=McAfee;i="6700,10204,11170"; a="22390527" X-IronPort-AV: E=Sophos;i="6.10,164,1719903600"; d="scan'208";a="22390527" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa112.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Aug 2024 02:45:03 -0700 X-CSE-ConnectionGUID: 3rjznFaET9mayXRmszj3IQ== X-CSE-MsgGUID: tHAUzQxUTGSuUrWxd1qr4w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,164,1719903600"; d="scan'208";a="91831890" Received: from silpixa00401119.ir.intel.com ([10.55.129.167]) by fmviesa001.fm.intel.com with ESMTP; 21 Aug 2024 02:45:03 -0700 From: Anatoly Burakov To: dev@dpdk.org, Robin Jarry Cc: bruce.richardson@intel.com Subject: [PATCH v5 2/4] usertools/cpu_layout: print out NUMA nodes Date: Wed, 21 Aug 2024 10:44:57 +0100 Message-ID: <9a16f43aa622fb4cd250fa21b0f7fbbaedd4afdb.1724233499.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <6646f59acc5a1d93481a06fe7374453d40aad990.1724233499.git.anatoly.burakov@intel.com> References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org In traditional NUMA case, NUMA nodes and physical sockets were used interchangeably, but there are cases where there can be multiple NUMA nodes per socket, as well as all CPU's being assigned NUMA node 0 even in cases of multiple sockets. Use sysfs to print out NUMA information. Signed-off-by: Anatoly Burakov --- Notes: v2 -> v3: - Sort imports alphabetically usertools/cpu_layout.py | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/usertools/cpu_layout.py b/usertools/cpu_layout.py index e133fb8ad3..976be1f8b2 100755 --- a/usertools/cpu_layout.py +++ b/usertools/cpu_layout.py @@ -5,6 +5,7 @@ """Display CPU topology information.""" +import glob import typing as T @@ -29,12 +30,21 @@ def read_sysfs(path: str) -> str: return fd.read().strip() +def read_numa_node(base: str) -> int: + """Read the NUMA node of a CPU.""" + node_glob = f"{base}/node*" + node_dirs = glob.glob(node_glob) + if not node_dirs: + return 0 # default to node 0 + return int(node_dirs[0].split("node")[1]) + + def print_row(row: T.Tuple[str, ...], col_widths: T.List[int]) -> None: """Print a row of a table with the given column widths.""" first, *rest = row w_first, *w_rest = col_widths first_end = " " * 4 - rest_end = " " * 10 + rest_end = " " * 4 print(first.ljust(w_first), end=first_end) for cell, width in zip(rest, w_rest): @@ -56,6 +66,7 @@ def main() -> None: sockets_s: T.Set[int] = set() cores_s: T.Set[int] = set() core_map: T.Dict[T.Tuple[int, int], T.List[int]] = {} + numa_map: T.Dict[int, int] = {} base_path = "/sys/devices/system/cpu" cpus = range_expand(read_sysfs(f"{base_path}/online")) @@ -64,12 +75,14 @@ def main() -> None: lcore_base = f"{base_path}/cpu{cpu}" core = int(read_sysfs(f"{lcore_base}/topology/core_id")) socket = int(read_sysfs(f"{lcore_base}/topology/physical_package_id")) + node = read_numa_node(lcore_base) cores_s.add(core) sockets_s.add(socket) key = (socket, core) core_map.setdefault(key, []) core_map[key].append(cpu) + numa_map[cpu] = node cores = sorted(cores_s) sockets = sorted(sockets_s) @@ -78,24 +91,37 @@ def main() -> None: print("cores = ", cores) print("sockets = ", sockets) + print("numa = ", sorted(set(numa_map.values()))) print() - # Core, [Socket, Socket, ...] - heading_strs = "", *[f"Socket {s}" for s in sockets] + # Core, [NUMA, Socket, NUMA, Socket, ...] + heading_strs = "", *[v for s in sockets for v in ("", f"Socket {s}")] sep_strs = tuple("-" * len(hstr) for hstr in heading_strs) rows: T.List[T.Tuple[str, ...]] = [] + prev_numa = None for c in cores: # Core, row: T.Tuple[str, ...] = (f"Core {c}",) - # [lcores, lcores, ...] + # assume NUMA changes symmetrically + first_lcore = core_map[(0, c)][0] + cur_numa = numa_map[first_lcore] + numa_changed = prev_numa != cur_numa + prev_numa = cur_numa + + # [NUMA, lcores, NUMA, lcores, ...] for s in sockets: try: lcores = core_map[(s, c)] + numa = numa_map[lcores[0]] + if numa_changed: + row += (f"NUMA {numa}",) + else: + row += ("",) row += (str(lcores),) except KeyError: - row += ("",) + row += ("", "") rows += [row] # find max widths for each column, including header and rows -- 2.43.5