From 200961ffd9fc8950482001f4ce84d128ad5df519 Mon Sep 17 00:00:00 2001 From: Nicholas Curtis Date: Thu, 29 Feb 2024 10:21:29 -0500 Subject: [PATCH] Re-implement machine-specs to contain documentation, units, etc. Print using tabulate Signed-off-by: Nicholas Curtis --- src/omniperf_base.py | 7 +- src/omniperf_soc/soc_base.py | 2 +- src/utils/specs.py | 471 ++++++++++++++++++++++------------- src/utils/tty.py | 23 +- src/utils/utils.py | 4 +- 5 files changed, 319 insertions(+), 188 deletions(-) diff --git a/src/omniperf_base.py b/src/omniperf_base.py index e23dd989a8..57ef9176e7 100644 --- a/src/omniperf_base.py +++ b/src/omniperf_base.py @@ -28,7 +28,7 @@ import sys import os from pathlib import Path import shutil -from utils.specs import MachineSpecs +from utils.specs import generate_machine_specs from utils.utils import demarcate, trace_logger, get_version, get_version_display, detect_rocprof, error, get_submodules from argparser import omniarg_parser import config @@ -160,7 +160,7 @@ class Omniperf: def load_soc_specs(self, sysinfo:dict=None): """Load OmniSoC instance for Omniperf run """ - self.__mspec = MachineSpecs(self.__args, sysinfo) + self.__mspec = generate_machine_specs(self.__args, sysinfo) if self.__args.specs: print(self.__mspec) sys.exit(0) @@ -193,7 +193,7 @@ class Omniperf: if self.__args.mode == None: if self.__args.specs: - print(MachineSpecs(self.__args)) + print(generate_machine_specs(self.__args)) sys.exit(0) parser.print_help(sys.stderr) error("Omniperf requires a valid mode.") @@ -280,6 +280,7 @@ class Omniperf: for d in analyzer.get_args().path: sys_info = pd.read_csv(Path(d[0], "sysinfo.csv")) sys_info = sys_info.to_dict('list') + sys_info = {key: value[0] for key, value in sys_info.items()} self.load_soc_specs(sys_info) analyzer.set_soc(self.__soc) diff --git a/src/omniperf_soc/soc_base.py b/src/omniperf_soc/soc_base.py index 0c100c2c8a..e5d197943e 100644 --- a/src/omniperf_soc/soc_base.py +++ b/src/omniperf_soc/soc_base.py @@ -92,7 +92,7 @@ class OmniSoC_Base(): def populate_mspec(self): from utils.specs import search, run, total_sqc, total_xcds - if not hasattr(self._mspec, "_rocminfo"): + if not hasattr(self._mspec, "_rocminfo") or self._mspec._rocminfo is None: return # load stats from rocminfo diff --git a/src/utils/specs.py b/src/utils/specs.py index cbe8844a06..27af079c81 100644 --- a/src/utils/specs.py +++ b/src/utils/specs.py @@ -36,10 +36,11 @@ import pandas as pd from datetime import datetime from math import ceil -from dataclasses import dataclass +from dataclasses import dataclass, field, asdict, fields from pathlib import Path as path from textwrap import dedent from utils.utils import error, get_hbm_stack_num, get_version +from utils.tty import get_table_string VERSION_LOC = [ "version", @@ -52,129 +53,264 @@ VERSION_LOC = [ "version-utils", ] -@dataclass +def detect_arch(_rocminfo): + from omniperf_base import SUPPORTED_ARCHS + + for idx1, linetext in enumerate(_rocminfo): + gpu_arch = search(r"^\s*Name\s*:\s+ ([a-zA-Z0-9]+)\s*$", linetext) + if gpu_arch in SUPPORTED_ARCHS.keys(): + break + if str(gpu_arch) in SUPPORTED_ARCHS.keys(): + gpu_arch = str(gpu_arch) + break + if not gpu_arch in SUPPORTED_ARCHS.keys(): + error("[profiling] Cannot find a supported arch in rocminfo") + else: + return (gpu_arch, idx1) + +def generate_machine_specs(args, sysinfo:dict=None): + if not sysinfo is None: + sysinfo_ver = str(sysinfo['version']) + version = get_version(config.omniperf_home)['version'] + if sysinfo_ver != version[:version.find(".")]: + logging.warning("WARNING: Detected mismatch in sysinfo versioning. You may need to reprofile to update data.") + return MachineSpecs(**sysinfo) + # read timestamp info + now = datetime.now() + local_now = now.astimezone() + local_tz = local_now.tzinfo + local_tzname = local_tz.tzname(local_now) + timestamp = now.strftime("%c") + " (" + local_tzname + ")" + hostname = socket.gethostname() + + # set specs version + vData = get_version(config.omniperf_home) + version = vData["version"] + # NB: Just taking major as specs version. May want to make this more specific in the future + specs_version = version[:version.find(".")] # version will always follow 'major.minor.patch' format + + ########################################## + ## A. Machine Specs + ########################################## + cpuinfo = path("/proc/cpuinfo").read_text() + meminfo = path("/proc/meminfo").read_text() + version = path("/proc/version").read_text() + os_release = path("/etc/os-release").read_text() + cpu_model = search(r"^model name\s*: (.*?)$", cpuinfo) + sbios = path("/sys/class/dmi/id/bios_vendor").read_text().strip() + \ + path("/sys/class/dmi/id/bios_version").read_text().strip() + linux_kernel_version = search(r"version (\S*)", version) + amd_gpu_kernel_version = "" #TODO: Extract amdgpu kernel version + cpu_memory = search(r"MemTotal:\s*(\S*)", meminfo) + gpu_memory = "" #TODO: Extract gpu memory + linux_distro = search(r'PRETTY_NAME="(.*?)"', os_release) + if linux_distro is None: + linux_distro = "" + rocm_version = get_rocm_ver().strip() + #FIXME: use device + vbios = search( + r"VBIOS version: (.*?)$", run(["rocm-smi", "-v"], exit_on_error=True)) + compute_partition = search( + r"Compute Partition:\s*(\w+)", run(["rocm-smi", "--showcomputepartition"])) + if compute_partition is None: + compute_partition = "NA" + memory_partition = search( + r"Memory Partition:\s*(\w+)", run(["rocm-smi", "--showmemorypartition"])) + if memory_partition is None: + memory_partition = "NA" + + ########################################## + ## B. SoC Specs + ########################################## + # read rocminfo + rocminfo_full = run(["rocminfo"]) + _rocminfo = rocminfo_full.split("\n") + gpu_arch, idx = detect_arch(_rocminfo) + _rocminfo = _rocminfo[idx + 1 :] # update rocminfo for target section + specs = MachineSpecs(version=specs_version, + timestamp=timestamp, + _rocminfo=_rocminfo, + hostname=hostname, + cpu_model=cpu_model, + sbios=sbios, + linux_kernel_version=linux_kernel_version, + amd_gpu_kernel_version=amd_gpu_kernel_version, + cpu_memory=cpu_memory, + gpu_memory=gpu_memory, + linux_distro=linux_distro, + rocm_version=rocm_version, + vbios=vbios, + compute_partition=compute_partition, + memory_partition=memory_partition, + gpu_arch=gpu_arch) + # Load above SoC specs via module import + try: + soc_module = importlib.import_module('omniperf_soc.soc_'+ specs.gpu_arch) + except ModuleNotFoundError as e: + error("Arch %s marked as supported, but couldn't find class implementation %s." % (specs.gpu_arch, e)) + soc_class = getattr(soc_module, specs.gpu_arch+'_soc') + soc_obj = soc_class(args, specs) + # Update arch specific specs + specs.total_l2_chan: str = total_l2_banks( + specs.gpu_model, int(specs._l2_banks), specs.memory_partition + ) + specs.hbm_bw: str = str(int(specs.max_mclk) / 1000 * 32 * specs.get_hbm_channels()) + return specs + +@dataclass(kw_only=True) class MachineSpecs: - def __init__(self, args, sysinfo:dict=None): - if not sysinfo is None: - sysinfo_ver = str(sysinfo['specs_version'][0]) - version = get_version(config.omniperf_home)['version'] - if sysinfo_ver != version[:version.find(".")]: - logging.warning("WARNING: Detected mismatch in sysinfo versioning. You may need to reprofile to update data.") - for key, value in sysinfo.items(): - setattr(self, key, value[0]) - return - # set specs version - vData = get_version(config.omniperf_home) - version = vData["version"] - # NB: Just taking major as specs version. May want to make this more specific in the future - self.specs_version = version[:version.find(".")] # version will alway follow 'major.minor.patch' format + ########################################## + ## A. Workload / Spec info + ########################################## - # read timestamp info - now = datetime.now() - local_now = now.astimezone() - local_tz = local_now.tzinfo - local_tzname = local_tz.tzname(local_now) - self.timestamp = now.strftime("%c") + " (" + local_tzname + ")" + # these three fields are special in that they're not included + # when you use (e.g.,) --specs to view the machinespecs, but they + # _are_ included in profiling/analysis, so we mark them as 'optional' + # in the metadata to avoid erroring out on missing fields on + # serialization + workload_name: str = field(default=None, metadata={ + 'doc': 'The name of the workload data was collected for.', + 'name': 'Workload Name', + 'optional': True}) + command: str = field(default=None, metadata={ + 'doc': 'The command the workload was executed with.', + 'name': 'Command', + 'optional': True}) + ip_blocks: str = field(default=None, metadata={ + 'doc': 'The hardware blocks profiling information was collected for.', + 'name': 'IP Blocks', + 'optional': True + }) + timestamp: str = field(default=None, metadata={ + 'doc': 'The time (in local system time) when data was collected', + 'name': 'Timestamp'}) + version: str = field(default=None, metadata={ + 'doc': 'The version of the machine specification file format.', + 'name': 'MachineSpecs Version'}) + timestamp: str = field(default=None, metadata={ + 'doc': 'The time (in local system time) when data was collected', + 'name': 'Timestamp'}) + _rocminfo: list = field(default=None) + ########################################## + ## A. Machine Specs + ########################################## + hostname: str = field(default=None, metadata={'doc': 'The hostname of the machine.', + 'name': 'Hostname'}) + cpu_model: str = field(default=None, metadata={'doc': 'The model name of the CPU used.', + 'name': 'CPU Model'}) + sbios: str = field(default=None, metadata={'doc': 'The system management bios version and vendor.', + 'name': "SBIOS"}) + linux_distro: str = field(default=None, metadata={'doc': 'The Linux distribution installed on the machine.', + 'name': 'Linux Distribution'}) + linux_kernel_version: str = field(default=None, + metadata={'doc': 'The Linux kernel version running on the machine.', + 'name': 'Linux Kernel Version'}) + amd_gpu_kernel_version: str = field(default=None, metadata={ + 'doc': '[RESERVED] The version of the AMDGPU driver installed on the machine. Unimplemented.', + 'name': "AMD GPU Kernel Version"}) + cpu_memory: str = field(default=None, metadata={ + 'doc': 'The total amount of memory available to the CPU.', 'unit': 'KB', + 'name': 'CPU Memory'}) + gpu_memory: str = field(default=None, metadata={ + 'doc': '[RESERVED] The total amount of memory available to accelerators/GPUs in the system. Unimplemented.', + 'unit': 'KB', + 'name': 'GPU Memory'}) + rocm_version: str = field(default=None, + metadata={'doc': 'The ROCm version used during data-collection.', + 'name': "ROCm Version"}) + vbios: str = field(default=None, + metadata={'doc': 'The version of the accelerators/GPUs video bios in the system.', + 'name': 'VBIOS'}) + compute_partition: str = field(default=None, + metadata={'doc': 'The compute partitioning mode active on the accelerators/GPUs in the system (MI300 only).', + 'name': 'Compute Partition'}) + memory_partition: str = field(default=None, + metadata={'doc': 'The memory partitioning mode active on the accelerators/GPUs in the system (MI300 only).', + 'name': 'Memory Partition'}) - # read rocminfo - rocminfo_full = run(["rocminfo"]) - self._rocminfo = rocminfo_full.split("\n") + ########################################## + ## B. SoC Specs + ########################################## + gpu_model: str = field( + default=None, + metadata={ + 'doc': 'The product name of the accelerators/GPUs in the system.', + 'name': 'GPU Model'}) + gpu_arch: str = field( + default=None, + metadata={ + 'doc': 'The architecture name of the accelerators/GPUs in the system,\n' + 'as used by (e.g.,) the AMDGPU backed of LLVM.', + 'name': 'GPU Arch'}) + gpu_l1: str = field(default=None, metadata={'doc': + "The size of the vL1D cache (per compute-unit) on the accelerators/GPUs in the system in KiB", + 'name': 'GPU L1'}) + gpu_l2: str = field(default=None, metadata={'doc': + "The size of the vL1D cache (per compute-unit) on the accelerators/GPUs in the system in KiB", + 'name': 'GPU L2'}) + cu_per_gpu: str = field(default=None, metadata={'doc': + "The total number of compute units per accelerator/GPU in the system. On systems with configurable\n" + "partitioning, (e.g., MI300) this is the total number of compute units in a partition.", + 'name': 'CU per GPU'}) + simd_per_cu: str = field(default=None, metadata={'doc': + "The number of SIMD processors in a compute unit for the accelerators/GPUs in the system.", + 'name': 'SIMD per CU'}) + se_per_gpu: str = field(default=None, metadata={'doc': + 'The number of shader engines on the accelerators/GPUs in the system. On systems with configurable\n' + 'partitioning, (e.g., MI300) this is the total number of shader engines in a partition.', + 'name': 'SE per GPU'}) + wave_size: str = field(default=None, metadata={'doc': + 'The number work-items in a wavefront on the accelerators/GPUs in the system.', + 'name': 'Wave Size'}) + workgroup_max_size: str = field(default=None, metadata={'doc': + 'The maximum number of work-items in a workgroup on the accelerators/GPUs in the system.', + 'name': 'Workgroup Max Size'}) + max_waves_per_cu: str = field(default=None, metadata={'doc': + 'The maximum number of wavefronts that can be resident on a compute unit on the\n' + 'accelerators/GPUs in the system', + 'name': 'Max Waves per CU'}) + max_sclk: str = field(default=None, metadata={'doc': + 'The maximum engine (compute-unit) clock rate of the accelerators/GPUs in the system.', + 'name': 'Max SCLK', + 'unit': 'MHz'}) + max_mclk: str = field(default=None, metadata={'doc': + 'The maximum memory clock rate of the accelerators/GPUs in the system.', + 'name': 'Max MCLK', + 'unit': 'MHz'}) + cur_sclk: str = field(default=None, metadata={'doc': + '[RESERVED] The current engine (compute unit) clock rate of the accelerators/GPUs in the system. Unused.', + 'name': 'Max SCLK', + 'unit': 'MHz'}) + cur_mclk: str = field(default=None, metadata={'doc': + '[RESERVED] The current memory clock rate of the accelerators/GPUs in the system. Unused.', + 'name': 'Max MCLK', + 'unit': 'MHz'}) + _l2_banks: str = None # NB: This only used in flatten_tcc_info_across_hbm_stacks() + total_l2_chan: str = field(default=None, metadata={ + 'doc': 'The maximum number of L2 cache channels on the accelerators/GPUs in the system. On systems with\n' + 'configurable partitioning, (e.g., MI300) this is the total number of L2 cache channels in a partition.', + 'name': 'Total L2 Channels'}) + lds_banks_per_cu: str = field(default=None, metadata={'doc': + 'The number of banks in the LDS for a compute unit on the accelerators/GPUs in the system.', + 'name': 'LDS Banks per CU'}) + sqc_per_gpu: str = field(default=None, metadata={ + 'doc': 'The number of L1I/sL1D caches on the accelerators/GPUs in the system. On systems with\n' + 'configurable partitioning, (e.g., MI300) this is the total number of L1I/sL1D caches in a partition.', + 'name': 'SQC per GPU'}) + pipes_per_gpu: str = field(default=None, metadata={ + 'doc': 'The number of scheduler-pipes on the accelerators/GPUs in the system.', + 'name': 'Pipes per GPU'}) + hbm_bw: str = field(default=None, metadata={ + 'doc': 'The peak theoretical HBM bandwidth for the accelerators/GPUs in the system. On systems with\n' + 'configurable partitioning, (e.g., MI300) this is the peak theoretical HBM bandwidth for a partition.', + 'name': 'HBM BW', + 'unit': 'MB/s'}) + num_xcd: str = field(default=None, metadata={ + 'doc': 'The total number of accelerator complex dies in a compute partition on the accelerators/GPUs in the\n' + 'system. For accelerators without partitioning (i.e., pre-MI300), this is considered to be one.', + 'name': 'Num XCDs', + 'unit': 'MB/s'}) - ########################################## - ## A. Machine Specs - ########################################## - cpuinfo = path("/proc/cpuinfo").read_text() - meminfo = path("/proc/meminfo").read_text() - version = path("/proc/version").read_text() - os_release = path("/etc/os-release").read_text() - - self.hostname: str = socket.gethostname() - self.cpu_model: str = search(r"^model name\s*: (.*?)$", cpuinfo) - self.sbios: str = ( - path("/sys/class/dmi/id/bios_vendor").read_text().strip() - + path("/sys/class/dmi/id/bios_version").read_text().strip() - ) - self.linux_kernel_version: str = search(r"version (\S*)", version) - self.amd_gpu_kernel_version: str = None - if self.amd_gpu_kernel_version is None: #TODO: Extract amdgpu kernel version - self.amd_gpu_kernel_version = "" - self.cpu_memory: str = search(r"MemTotal:\s*(\S*)", meminfo) - self.gpu_memory: str = None #TODO: Extract total gpu memory - if self.gpu_memory is None: - self.gpu_memory = "" - self.linux_distro: str = search(r'PRETTY_NAME="(.*?)"', os_release) - if self.linux_distro is None: - self.linux_distro = "" - self.rocm_version: str = get_rocm_ver().strip() - #FIXME: use device - self.vbios: str = search( - r"VBIOS version: (.*?)$", run(["rocm-smi", "-v"], exit_on_error=True) - ) - self.compute_partition: str = search( - r"Compute Partition:\s*(\w+)", run(["rocm-smi", "--showcomputepartition"]) - ) - if self.compute_partition is None: - self.compute_partition = "NA" - self.memory_partition: str = search( - r"Memory Partition:\s*(\w+)", run(["rocm-smi", "--showmemorypartition"]) - ) - if self.memory_partition is None: - self.memory_partition = "NA" - - ########################################## - ## B. SoC Specs - ########################################## - self.gpu_arch: str = self.detect_arch()[0] - self.gpu_l1: str = None - self.gpu_l2: str = None - self.cu_per_gpu: str = None - self.simd_per_cu: str = None - self.se_per_gpu: str = None - self.wave_size: str = None - self.workgroup_max_size: str = None - self.max_sclk: str = None - self.max_mclk: str = None - self.cur_sclk: str = None - self.cur_mclk: str = None - self.max_waves_per_cu: str = None - self.gpu_model: str = None - self._l2_banks: str = None #NB: This only used in flatten_tcc_info_across_hbm_stacks() - self.lds_banks_per_cu: str = None - self.sqc_per_gpu: str = None - self.pipes_per_gpu: str = None - self.total_l2_chan: str = None - self.hbm_bw: str = None - self.num_xcd: str = None - # Load above SoC specs via module import - try: - soc_module = importlib.import_module('omniperf_soc.soc_'+ self.gpu_arch) - except ModuleNotFoundError as e: - error("Arch %s marked as supported, but couldn't find class implementation %s." % (self.gpu_arch, e)) - soc_class = getattr(soc_module, self.gpu_arch+'_soc') - self._rocminfo = self._rocminfo[self.detect_arch()[1] + 1 :] # update rocminfo for target section - soc_obj = soc_class(args, self) - # Update arch specific specs - self.total_l2_chan: str = total_l2_banks( - self.gpu_model, int(self._l2_banks), self.memory_partition - ) - self.hbm_bw: str = str(int(self.max_mclk) / 1000 * 32 * self.get_hbm_channels()) - - - def detect_arch(self): - from omniperf_base import SUPPORTED_ARCHS - - for idx1, linetext in enumerate(self._rocminfo): - gpu_arch = search(r"^\s*Name\s*:\s+ ([a-zA-Z0-9]+)\s*$", linetext) - if gpu_arch in SUPPORTED_ARCHS.keys(): - break - if str(gpu_arch) in SUPPORTED_ARCHS.keys(): - gpu_arch = str(gpu_arch) - break - if not gpu_arch in SUPPORTED_ARCHS.keys(): - error("[profiling] Cannot find a supported arch in rocminfo") - else: - return (gpu_arch, idx1) - def get_hbm_channels(self): hbmchannels = int(self.total_l2_chan) if ( @@ -189,60 +325,55 @@ class MachineSpecs: all_populated = True data = {} # dataclass uses an OrderedDict for member variables, ensuring order consistency - for attr_name in self.__dict__.keys(): - if not attr_name.startswith("_"): - attr_value = getattr(self, attr_name) - if attr_value is None: - #TODO: use proper logging function when that's merged - logging.warning(f"WARNING: Incomplete class definition for {self.gpu_arch}. Expecting populated {attr_name} but detected None.") - all_populated = False - data[attr_name] = attr_value + for field in fields(self): + name = field.name + if not name.startswith("_"): + value = getattr(self, name) + if value is None: + # check if we've marked it optional + if field.metadata and 'optional' in field.metadata and field.metadata['optional']: + pass + else: + #TODO: use proper logging function when that's merged + logging.warning( + f"WARNING: Incomplete class definition for {self.gpu_arch}. " + f"Expecting populated {name} but detected None.") + all_populated = False + data[name] = value if not all_populated: error("Missing specs fields for %s" % self.gpu_arch) return pd.DataFrame(data, index=[0]) - - def __str__(self): - return dedent( - f"""\ - Specs version: v{self.specs_version} - Host info: - Hostname: {self.hostname} - CPU Model: {self.cpu_model} - sbios: {self.sbios} - CPU Memory: {self.cpu_memory} - GPU Memory: {self.gpu_memory} - Linux Distro: {self.linux_distro} - Linux Kernel Version: {self.linux_kernel_version} - AMD GPU Kernel Version: {self.amd_gpu_kernel_version} - ROCm Version: {self.rocm_version} - Device info: - GPU Model: {self.gpu_model} - GPU Arch: {self.gpu_arch} - vbios: {self.vbios} - GPU L1: {self.gpu_l1} KB - GPU L2: {self.gpu_l2} KB - Max SCLK: {self.max_sclk} MHz - Max MCLK: {self.max_mclk} MHz - Cur SCLK: {self.cur_sclk} MHz - Cur MCLK: {self.cur_mclk} MHz - CU per GPU: {self.cu_per_gpu} - SIMD per CU: {self.simd_per_cu} - SE per GPU: {self.se_per_gpu} - Wave Size: {self.wave_size} - Workgroup Max Size: {self.workgroup_max_size} - Max Waves per CU: {self.max_waves_per_cu} - Total L2 Channels: {self.total_l2_chan} - LDS Banks per CU: {self.lds_banks_per_cu} - SQC per GPU: {self.sqc_per_gpu} - Pipes per GPU: {self.pipes_per_gpu} - HBM BW: {self.hbm_bw} MB/s - Compute Partition: {self.compute_partition} - Memory Partition: {self.memory_partition} - Num XCDs: {self.num_xcd} - """ - ) + def __repr__(self): + data = [] + for field in fields(self): + name = field.name + if not name.startswith("_"): + _data = {} + value = getattr(self, name) + if field.metadata: + if 'name' in field.metadata: + name = field.metadata['name'] + if 'unit' in field.metadata: + _data['Unit'] = field.metadata['unit'] + if 'doc' in field.metadata: + _data['Description'] = field.metadata['doc'] + _data['Spec'] = name + _data['Value'] = value + data.append(_data) + df = pd.DataFrame(data) + columns = ['Spec', 'Value'] + if 'Description' in df.columns: + columns += ['Description'] + if 'Unit' in df.columns: + columns += ['Unit'] + df = df[columns] + df = df.fillna('') + return ( + "Machine Specifications: describing the state of the machine that Omniperf data was collected on." + + "\n" + + get_table_string(df, transpose=False, decimal=2)) def get_rocm_ver(): @@ -350,4 +481,4 @@ def total_xcds(archname, compute_partition): if __name__ == "__main__": - print(MachineSpecs()) + print(generate_machine_specs()) diff --git a/src/utils/tty.py b/src/utils/tty.py index 5d1f68a701..eae3dc2849 100644 --- a/src/utils/tty.py +++ b/src/utils/tty.py @@ -50,6 +50,13 @@ def string_multiple_lines(source, width, max_rows): return "\n".join(lines) +def get_table_string(df, transpose=False, decimal=2): + return tabulate(df.transpose() if transpose else df, + headers="keys", + tablefmt="fancy_grid", + floatfmt="." + str(decimal) + "f") + + def show_all(args, runs, archConfigs, output): """ Show all panels with their data in plain text mode. @@ -214,19 +221,11 @@ def show_all(args, runs, archConfigs, output): # df when load it, because we need those items in column. # For metric_table, we only need to show the data in column # fash for now. + transpose = (type != "raw_csv_table" + and "columnwise" in table_config + and table_config["columnwise"] == True) ss += ( - tabulate( - ( - df.transpose() - if type != "raw_csv_table" - and "columnwise" in table_config - and table_config["columnwise"] == True - else df - ), - headers="keys", - tablefmt="fancy_grid", - floatfmt="." + str(args.decimal) + "f", - ) + get_table_string(df, transpose=transpose, decimal=args.decimal) + "\n" ) diff --git a/src/utils/utils.py b/src/utils/utils.py index ccf5bcd005..c1ed0e9ce1 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -299,8 +299,8 @@ def gen_sysinfo(workload_name, workload_dir, ip_blocks, app_cmd, skip_roof, roof df = mspec.get_class_members() # Append workload information to machine specs - df.insert(0, 'command', app_cmd) - df.insert(0,'workload_name', workload_name) + df['command'] = app_cmd + df['workload_name'] = workload_name blocks = [] if ip_blocks == None: