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 9E4BA4582E; Wed, 21 Aug 2024 11:45:07 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id CB02340E44; Wed, 21 Aug 2024 11:45:05 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.20]) by mails.dpdk.org (Postfix) with ESMTP id EECF04003C for ; Wed, 21 Aug 2024 11:45:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724233503; x=1755769503; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZMXhWZdJoie9TYf9Xr1QVc9sk/UD7NxlfWG/CUaC+bA=; b=L4UJFk/kZfSUK4H75VoArY56QV2z7SmkaT6PB/M0gm4GlBt/55Oi6pCM Furu83dgf/GcQUIMelSWJAjVu3dxMDo3m1HpME+yktaxkPnXv5TrndyBk 0f+mHga7mk/NFWP6aQPAxlmR5SqFoZdY1/7rWXI15OobS2UEb6qjphv4L MTS/5eQ7ubhcG90WNgSJKxM3Abx0oRVZF5/Be0N/WQcyroxnnLE9f+0hj ZuXF2GU+EO3igpTsAocMjzrXqmMFm93niZaUQd43SVEEihy8SpCXKZjSF yq/P9fQWgx/wJu6WurjwpwBYfzulXLB/uzlzPrUWom9HDFmJJ6ery9bRp w==; X-CSE-ConnectionGUID: jn/2A13vRaOGNOA1Qg3hbg== X-CSE-MsgGUID: s759Z0YNRRuEbyPgFiSYSA== X-IronPort-AV: E=McAfee;i="6700,10204,11170"; a="22390523" X-IronPort-AV: E=Sophos;i="6.10,164,1719903600"; d="scan'208";a="22390523" 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:02 -0700 X-CSE-ConnectionGUID: aTl/ryhxRjGWC9X8BHnbRw== X-CSE-MsgGUID: K+qIxoWrQAqLei8kXS8mUA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,164,1719903600"; d="scan'208";a="91831868" Received: from silpixa00401119.ir.intel.com ([10.55.129.167]) by fmviesa001.fm.intel.com with ESMTP; 21 Aug 2024 02:45:02 -0700 From: Anatoly Burakov To: dev@dpdk.org, Robin Jarry Cc: bruce.richardson@intel.com Subject: [PATCH v5 1/4] usertools/cpu_layout: update coding style Date: Wed, 21 Aug 2024 10:44:56 +0100 Message-ID: <6646f59acc5a1d93481a06fe7374453d40aad990.1724233499.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: 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 Update coding style: - make it PEP-484 compliant - format code with Ruff - address all mypy etc. warnings - use f-strings in place of old-style string interpolation - refactor printing to make the code more readable - read valid CPU ID's from "online" sysfs node Signed-off-by: Anatoly Burakov --- Notes: v4-v5: - Format with Ruff on default settings v3->v4: - Format with Ruff, line width 79 v1,v2 -> v3: - Import typing as T instead of individual types usertools/cpu_layout.py | 161 ++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 55 deletions(-) diff --git a/usertools/cpu_layout.py b/usertools/cpu_layout.py index 891b9238fa..e133fb8ad3 100755 --- a/usertools/cpu_layout.py +++ b/usertools/cpu_layout.py @@ -3,62 +3,113 @@ # Copyright(c) 2010-2014 Intel Corporation # Copyright(c) 2017 Cavium, Inc. All rights reserved. -sockets = [] -cores = [] -core_map = {} -base_path = "/sys/devices/system/cpu" -fd = open("{}/kernel_max".format(base_path)) -max_cpus = int(fd.read()) -fd.close() -for cpu in range(max_cpus + 1): - try: - fd = open("{}/cpu{}/topology/core_id".format(base_path, cpu)) - except IOError: - continue - core = int(fd.read()) - fd.close() - fd = open("{}/cpu{}/topology/physical_package_id".format(base_path, cpu)) - socket = int(fd.read()) - fd.close() - if core not in cores: - cores.append(core) - if socket not in sockets: - sockets.append(socket) - key = (socket, core) - if key not in core_map: - core_map[key] = [] - core_map[key].append(cpu) +"""Display CPU topology information.""" -print(format("=" * (47 + len(base_path)))) -print("Core and Socket Information (as reported by '{}')".format(base_path)) -print("{}\n".format("=" * (47 + len(base_path)))) -print("cores = ", cores) -print("sockets = ", sockets) -print("") +import typing as T -max_processor_len = len(str(len(cores) * len(sockets) * 2 - 1)) -max_thread_count = len(list(core_map.values())[0]) -max_core_map_len = (max_processor_len * max_thread_count) \ - + len(", ") * (max_thread_count - 1) \ - + len('[]') + len('Socket ') -max_core_id_len = len(str(max(cores))) -output = " ".ljust(max_core_id_len + len('Core ')) -for s in sockets: - output += " Socket %s" % str(s).ljust(max_core_map_len - len('Socket ')) -print(output) - -output = " ".ljust(max_core_id_len + len('Core ')) -for s in sockets: - output += " --------".ljust(max_core_map_len) - output += " " -print(output) - -for c in cores: - output = "Core %s" % str(c).ljust(max_core_id_len) - for s in sockets: - if (s, c) in core_map: - output += " " + str(core_map[(s, c)]).ljust(max_core_map_len) +def range_expand(rstr: str) -> T.List[int]: + """Expand a range string into a list of integers.""" + # 0,1-3 => [0, 1-3] + ranges = rstr.split(",") + valset: T.List[int] = [] + for r in ranges: + # 1-3 => [1, 2, 3] + if "-" in r: + start, end = r.split("-") + valset.extend(range(int(start), int(end) + 1)) else: - output += " " * (max_core_map_len + 1) - print(output) + valset.append(int(r)) + return valset + + +def read_sysfs(path: str) -> str: + """Read a sysfs file and return its contents.""" + with open(path, encoding="utf-8") as fd: + return fd.read().strip() + + +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 + + print(first.ljust(w_first), end=first_end) + for cell, width in zip(rest, w_rest): + print(cell.rjust(width), end=rest_end) + print() + + +def print_section(heading: str) -> None: + """Print a section heading.""" + sep = "=" * len(heading) + print(sep) + print(heading) + print(sep) + print() + + +def main() -> None: + """Print CPU topology information.""" + sockets_s: T.Set[int] = set() + cores_s: T.Set[int] = set() + core_map: T.Dict[T.Tuple[int, int], T.List[int]] = {} + base_path = "/sys/devices/system/cpu" + + cpus = range_expand(read_sysfs(f"{base_path}/online")) + + for cpu in cpus: + 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")) + + cores_s.add(core) + sockets_s.add(socket) + key = (socket, core) + core_map.setdefault(key, []) + core_map[key].append(cpu) + + cores = sorted(cores_s) + sockets = sorted(sockets_s) + + print_section(f"Core and Socket Information (as reported by '{base_path}')") + + print("cores = ", cores) + print("sockets = ", sockets) + print() + + # Core, [Socket, Socket, ...] + heading_strs = "", *[f"Socket {s}" for s in sockets] + sep_strs = tuple("-" * len(hstr) for hstr in heading_strs) + rows: T.List[T.Tuple[str, ...]] = [] + + for c in cores: + # Core, + row: T.Tuple[str, ...] = (f"Core {c}",) + + # [lcores, lcores, ...] + for s in sockets: + try: + lcores = core_map[(s, c)] + row += (str(lcores),) + except KeyError: + row += ("",) + rows += [row] + + # find max widths for each column, including header and rows + col_widths = [ + max(len(tup[col_idx]) for tup in rows + [heading_strs]) + for col_idx in range(len(heading_strs)) + ] + + # print out table taking row widths into account + print_row(heading_strs, col_widths) + print_row(sep_strs, col_widths) + for row in rows: + print_row(row, col_widths) + + +if __name__ == "__main__": + main() -- 2.43.5