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 645AB4582E; Wed, 21 Aug 2024 11:22:52 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5E2B640E54; Wed, 21 Aug 2024 11:22:47 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) by mails.dpdk.org (Postfix) with ESMTP id D9EA440E44 for ; Wed, 21 Aug 2024 11:22:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724232165; x=1755768165; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=fHBrcLTblDOmBWRWD86tcqlJwhFDQdXZaiuZblOkJvo=; b=EkE62KwR+Z2CLeCumwZvhtd8uJT8smz7xdtsXAzyDQ+Iq2bRyKhol1IG Uu/BEgZDhrEM27sfRiE+fXkUyzJZ7Il9WfRE6j9a0vauIuUgGhlPDMFHY tFph8jncvZULsj7298XNGTdZW0rcLx4eB7rHePJo9aO1cSTxTsoEuKsQg 5DRRLSxCxum/e7rD0vuVew9MTaj+lAgY9y/4VOUwyA9tiOhlVBg5vLz1a Aakwye5HULWtWShuBpeYAOjNrrrTIie4QtXwSun2T9u1E5OuWbvAjiDGD 8cLSM0dSKrzR2cOUu+oXi5kyNef7y5wsOWBRw9LHIQuPH4y+2NWxHUpnf w==; X-CSE-ConnectionGUID: u20kVS75Q76dLKuKkgksQQ== X-CSE-MsgGUID: HhWLD1F9RKW/2BUd2mv5rQ== X-IronPort-AV: E=McAfee;i="6700,10204,11170"; a="33734685" X-IronPort-AV: E=Sophos;i="6.10,164,1719903600"; d="scan'208";a="33734685" Received: from orviesa008.jf.intel.com ([10.64.159.148]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Aug 2024 02:22:44 -0700 X-CSE-ConnectionGUID: hOhZOSW2R6CqwyXIJewRQw== X-CSE-MsgGUID: 07iR7M6cSP6QDDopioV/Aw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,164,1719903600"; d="scan'208";a="61795134" Received: from silpixa00401119.ir.intel.com ([10.55.129.167]) by orviesa008.jf.intel.com with ESMTP; 21 Aug 2024 02:22:43 -0700 From: Anatoly Burakov To: dev@dpdk.org, Robin Jarry Cc: bruce.richardson@intel.com Subject: [PATCH v4 2/4] usertools/cpu_layout: print out NUMA nodes Date: Wed, 21 Aug 2024 10:22:37 +0100 Message-ID: X-Mailer: git-send-email 2.43.5 In-Reply-To: <5483d1671d456392c769e5f5dd9330ce3c528f04.1724232159.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 8812ea286b..e4720e27db 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) @@ -80,24 +93,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