From d756aeb3fd764835a9d8f49e2c077ab193937249 Mon Sep 17 00:00:00 2001 From: Fei Zheng <44449748+feizheng10@users.noreply.github.com> Date: Fri, 6 Jun 2025 12:43:52 -0600 Subject: [PATCH] Support stochastic pc sampling --- CHANGELOG.md | 4 + CONTRIBUTING.md | 2 +- LICENSE | 2 +- docker/Dockerfile.standalone | 2 +- docker/docker-compose.standalone.yml | 2 +- docs/how-to/pc_sampling.rst | 48 +++++ docs/sphinx/_toc.yml.in | 2 + docs/tutorial/learning-resources.rst | 2 +- src/argparser.py | 31 ++- src/rocprof_compute_analyze/analysis_cli.py | 6 +- src/rocprof_compute_analyze/analysis_webui.py | 3 +- src/rocprof_compute_profile/profiler_base.py | 1 + src/utils/parser.py | 200 ++++++++++++++---- src/utils/utils.py | 11 +- 14 files changed, 249 insertions(+), 67 deletions(-) create mode 100644 docs/how-to/pc_sampling.rst diff --git a/CHANGELOG.md b/CHANGELOG.md index dfdbef1a0b..1931a1e10c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Full documentation for ROCm Compute Profiler is available at [https://rocm.docs. ### Added +* Stochastic (hardware-based) PC sampling has been enabled for AMD Instinct MI300X series and later accelerators. + +* Sorting of PC sampling by type: offset or count. + * Add rocprof-compute Text User Interface (TUI) support for analyze mode * A command line based user interface to support interactive single-run analysis * launch with `--tui` option in analyze mode. i.e., `rocprof-compute analyze --tui` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0cb27703d6..de7f57b890 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,4 +56,4 @@ Please see the [pre-commit documentation](https://pre-commit.com/#quick-start) f Below are some repository specific guidelines which are followed througout the repository. Any future contributions should adhere to these guidelines: -* Use pathlib library functions instead of os.path for manipulating file paths \ No newline at end of file +* Use the `pathlib` library functions instead of `os.path` for manipulating the file paths. diff --git a/LICENSE b/LICENSE index b1d8215245..7a7c12c897 100644 --- a/LICENSE +++ b/LICENSE @@ -41,4 +41,4 @@ tabulate python library: MIT textual python library: MIT textual_plotext python library: MIT textual-fspicker python library: MIT -tqdm python library: MIT \ No newline at end of file +tqdm python library: MIT diff --git a/docker/Dockerfile.standalone b/docker/Dockerfile.standalone index 4f32c01d8c..fe498476d7 100644 --- a/docker/Dockerfile.standalone +++ b/docker/Dockerfile.standalone @@ -19,4 +19,4 @@ CMD ["/bin/bash", "-c", "\ && rm -rf build \ && cmake -B build -S . \ && make -C build standalonebinary \ -"] \ No newline at end of file +"] diff --git a/docker/docker-compose.standalone.yml b/docker/docker-compose.standalone.yml index 4df2557368..f02b3b276a 100644 --- a/docker/docker-compose.standalone.yml +++ b/docker/docker-compose.standalone.yml @@ -9,4 +9,4 @@ services: security_opt: - seccomp:unconfined volumes: - - ../:/app \ No newline at end of file + - ../:/app diff --git a/docs/how-to/pc_sampling.rst b/docs/how-to/pc_sampling.rst new file mode 100644 index 0000000000..a89721c5f7 --- /dev/null +++ b/docs/how-to/pc_sampling.rst @@ -0,0 +1,48 @@ +.. meta:: + :description: ROCm Compute Profiler: using PC sampling + :keywords: ROCm Compute Profiler, PC sampling + +******************************************** +Using PC sampling in ROCm Compute Profiler +******************************************** + +Program Counter (PC) sampling service for GPU profiling is a profiling technique that periodically samples the program counter during the GPU kernel execution to understand code execution patterns and hotspots. + +ROCm Compute Profiler supports Host Trap PC sampling and Stochastic (Hardware-Based) PC sampling. +Host Trap PC sampling is enabled for AMD Instinct MI200 series and later +accelerators. Stochastic (hardware-based) PC sampling is enabled for +AMD Instinct MI300 series and later accelerators. Stochastic PC sampling provides additional information that tells whether a sampled wave issued an instruction for a particular PC. It also provides the reason +for not issuing the instruction (stall reason). This type of information is +particularly useful for understanding stalls during the kernel execution. The PC sampling can be used with profiling and analysis options. + +--------------------- +Profiling options +--------------------- +For using profiling options for PC sampling the configuration needed are: +- ``--pc-sampling-method``: Should be either ``stochastic`` or ``host_trap`` +- ``--pc-sampling-interval``: For stochastic sampling, the interval is in cycles. The finest granularity is 1 cycle. For host_trap sampling, the interval is in microsecond (DEFAULT: 1048576). The interval should be the power of 2. You are recommended to try to starting from 1048576, and lowering until reaching 65536. + +**Sample command:** +.. code-block:: bash + + rocprof-compute profile -n pc_test -b 21 --no-roof --pc-sampling-method stochastic --pc-sampling-interval 1048576 -VVV -- target_app + +----------------------- +Analysis options +----------------------- +For using analysis options for PC sampling the configuration needed are: + +- ``--pc-sampling-sorting-type``: ``offset`` or ``count``. The default option is ``offset``. ``offset`` is an assembly instruction offset in the code object. + +**Sample command:** +.. code-block:: bash + + rocprof-compute analyze -p workloads/pc_test/MI300A_A1/ -b 21 -k 0 --pc-sampling-sorting-type offset + + +.. note:: + + - PC sampling feature is currently in BETA version. To enable PC sampling, + you have to explicitly enable it with block index 21. + - To associate PC sampling info back to HIP source code, you need to build the profiling target app with ``-g`` to keep the symbols. Otherwise, PC sampling info would be only associated with assembly lines. + diff --git a/docs/sphinx/_toc.yml.in b/docs/sphinx/_toc.yml.in index 7df82fc8bd..a5e776cc43 100644 --- a/docs/sphinx/_toc.yml.in +++ b/docs/sphinx/_toc.yml.in @@ -18,7 +18,9 @@ subtrees: - caption: How to entries: - file: how-to/use.rst + - file: how-to/pc_sampling.rst - file: how-to/profile/mode.rst + title: Use PC sampling - file: how-to/analyze/mode.rst entries: - file: how-to/analyze/cli.rst diff --git a/docs/tutorial/learning-resources.rst b/docs/tutorial/learning-resources.rst index d9a1f4b889..96ccba3b0c 100644 --- a/docs/tutorial/learning-resources.rst +++ b/docs/tutorial/learning-resources.rst @@ -1,6 +1,6 @@ .. meta:: :description: ROCm Compute Profiler external training resources - :keywords: Omniperf, examples, tutorials, videos, lesson, lessons, how + :keywords: ROCm Compute Profiler, examples, tutorials, videos, lesson, lessons, how ****************** Learning resources diff --git a/src/argparser.py b/src/argparser.py index 1a83a0c44d..2460a08712 100644 --- a/src/argparser.py +++ b/src/argparser.py @@ -30,7 +30,7 @@ from pathlib import Path def print_avail_arch(avail_arch: list): - ret_str = "\t\t\tList all available metrics for analysis on specified arch:" + ret_str = "\t\tList all available metrics for analysis on specified arch:" for arch in avail_arch: ret_str += "\n\t\t\t {}".format(arch) return ret_str @@ -324,13 +324,22 @@ Examples: help="\t\t\tSet the format of output file of rocprof.", ) + profile_group.add_argument( + "--pc-sampling-method", + required=False, + metavar="", + dest="pc_sampling_method", + default="stochastic", + help="\t\t\tSet the method of pc sampling, stochastic or host_trap. Support stochastic only >= MI300", + ) + profile_group.add_argument( "--pc-sampling-interval", required=False, metavar="", dest="pc_sampling_interval", - default=1, - help="\t\t\tSet the interval of pc sampling in microsecond (DEFAULT: 1).", + default=1048576, + help="\t\t\tSet the interval of pc sampling.\n\t\t\t For stochastic sampling, the interval is in cycles.\n\t\t\t For host_trap sampling, the interval is in microsecond (DEFAULT: 1048576).", ) profile_group.add_argument( @@ -395,7 +404,7 @@ Examples: nargs="+", type=str, default=["FP32"], - help="Choose datatypes to view roofline PDFs for: (DEFAULT: FP32)\n\t\t\t FP4\n\t\t\t FP6\n\t\t\t FP8\n\t\t\t FP16\n\t\t\t BF16\n\t\t\t FP32\n\t\t\t FP64\n\t\t\t I8\n\t\t\t I32\n\t\t\t I64\n\t\t\t ", + help="\t\t\tChoose datatypes to view roofline PDFs for: (DEFAULT: FP32)\n\t\t\t FP4\n\t\t\t FP6\n\t\t\t FP8\n\t\t\t FP16\n\t\t\t BF16\n\t\t\t FP32\n\t\t\t FP64\n\t\t\t I8\n\t\t\t I32\n\t\t\t I64\n\t\t\t ", ) # roofline_group.add_argument('-w', '--workgroups', required=False, default=-1, type=int, help="\t\t\tNumber of kernel workgroups (DEFAULT: 1024)") @@ -584,7 +593,7 @@ Examples: required=False, default=False, action="store_true", - help="\t\t\tMode of spatial multiplexing.", + help="\t\tMode of spatial multiplexing.", ) analyze_group.add_argument( "-o", @@ -614,7 +623,17 @@ Examples: nargs="+", type=str, default=["FP32"], - help="\t\t\tChoose datatypes to view roofline PDFs for: (DEFAULT: FP32)\n\t\t\t FP4\n\t\t\t FP6\n\t\t\t FP8\n\t\t\t FP16\n\t\t\t BF16\n\t\t\t FP32\n\t\t\t FP64\n\t\t\t I8\n\t\t\t I32\n\t\t\t I64\n\t\t\t ", + help="\t\tChoose datatypes to view roofline PDFs for: (DEFAULT: FP32)\n\t\t\t FP4\n\t\t\t FP6\n\t\t\t FP8\n\t\t\t FP16\n\t\t\t BF16\n\t\t\t FP32\n\t\t\t FP64\n\t\t\t I8\n\t\t\t I32\n\t\t\t I64\n\t\t\t ", + ) + + analyze_group.add_argument( + "--pc-sampling-sorting-type", + required=False, + metavar="", + dest="pc_sampling_sorting_type", + default="offset", + type=str, + help="\t\tSet the sorting type of pc sampling: offset or count (DEFAULT: offset).", ) analyze_advanced_group.add_argument( diff --git a/src/rocprof_compute_analyze/analysis_cli.py b/src/rocprof_compute_analyze/analysis_cli.py index 394b5024da..83895dd707 100644 --- a/src/rocprof_compute_analyze/analysis_cli.py +++ b/src/rocprof_compute_analyze/analysis_cli.py @@ -72,11 +72,7 @@ class cli_analysis(OmniAnalyze_Base): # create the loaded table parser.load_table_data( - workload=self._runs[d[0]], - dir=d[0], - is_gui=False, - debug=self.get_args().debug, - verbose=self.get_args().verbose, + workload=self._runs[d[0]], dir=d[0], is_gui=False, args=self.get_args() ) @demarcate diff --git a/src/rocprof_compute_analyze/analysis_webui.py b/src/rocprof_compute_analyze/analysis_webui.py index 297f80f32e..b8bcbc89f5 100644 --- a/src/rocprof_compute_analyze/analysis_webui.py +++ b/src/rocprof_compute_analyze/analysis_webui.py @@ -164,8 +164,7 @@ class webui_analysis(OmniAnalyze_Base): workload=base_data[base_run], dir=self.dest_dir, is_gui=True, - debug=self.get_args().debug, - verbose=self.get_args().verbose, + args=self.get_args(), ) # ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/rocprof_compute_profile/profiler_base.py b/src/rocprof_compute_profile/profiler_base.py index dd47a62497..3e3eac8da6 100644 --- a/src/rocprof_compute_profile/profiler_base.py +++ b/src/rocprof_compute_profile/profiler_base.py @@ -442,6 +442,7 @@ class RocProfCompute_Base: ): start_run_prof = time.time() pc_sampling_prof( + method=self.get_args().pc_sampling_method, interval=self.get_args().pc_sampling_interval, workload_dir=self.get_args().path, appcmd=self.get_args().remaining, diff --git a/src/utils/parser.py b/src/utils/parser.py index b9a1e22bfd..c6eaee231a 100644 --- a/src/utils/parser.py +++ b/src/utils/parser.py @@ -1043,33 +1043,83 @@ def search_pc_sampling_record(records): """ Search PC sampling records, and group and sort them """ + + # NB: + # The field stall_reason is vailid only for HW stochastic pc sampling. + + # Todo: might save wavefront count for HW stochastic pc sampling? + grouped_data = defaultdict( - lambda: defaultdict(lambda: {"count": 0, "inst_index": None}) + lambda: defaultdict( + lambda: { + "count": 0, + "inst_index": None, + "stall_reason": { + "NONE": 0, + "NO_INSTRUCTION_AVAILABLE": 0, # No instruction available in the instruction cache. + "ALU_DEPENDENCY": 0, # ALU dependency not resolved. + "WAITCNT": 0, + "INTERNAL_INSTRUCTION": 0, # Wave executes an internal instruction. + "BARRIER_WAIT": 0, + "ARBITER_NOT_WIN": 0, # The instruction did not win the arbiter. + "ARBITER_WIN_EX_STALL": 0, # Arbiter issued an instruction, but the execution pipe pushed it back from execution. + "OTHER_WAIT": 0, # Other types of wait (e.g., wait for XNACK acknowledgment). + "SLEEP_WAIT": 0, + "LAST": 0, + }, + } + ) ) # Populate grouped_data - for item in records: + for i, item in enumerate(records): pc_info = item["record"].get("pc", {}) code_object_id = pc_info.get("code_object_id") code_object_offset = pc_info.get("code_object_offset") + snapshot = item["record"].get("snapshot", {}) inst_index = item.get("inst_index") + # Todo: opt me if ( code_object_id is not None and code_object_offset is not None and inst_index is not None ): grouped_data[code_object_id][code_object_offset]["count"] += 1 + # NB: the write here could be duplicated. If there is perf issue, We might want to opt it. grouped_data[code_object_id][code_object_offset]["inst_index"] = inst_index + if len(snapshot): + # NB: 54 is the length of prefix "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_" + grouped_data[code_object_id][code_object_offset]["stall_reason"][ + snapshot.get("stall_reason")[54:] + ] += 1 + # print( + # inst_index, + # grouped_data[code_object_id][code_object_offset]["stall_reason"], + # ) + if len(grouped_data) == 0: console_warning("PC sampling: no pc sampling record found!") return None + # print(grouped_data) + # Convert to sorted list of tuples (code_object_id, inst_index, code_object_offset, count) sorted_counts = sorted( [ - (code_object_id, info["inst_index"], offset, info["count"]) + ( + code_object_id, + info["inst_index"], + offset, + info["count"], + # For info["stall_reason"], remove the zero entries, sorting the remaining items by their values in descending order + sorted( + ((k, v) for k, v in info["stall_reason"].items() if v > 0), + key=lambda item: item[1], + reverse=True, + ), + ) for code_object_id, offsets in grouped_data.items() for offset, info in offsets.items() ], @@ -1083,10 +1133,24 @@ def search_pc_sampling_record(records): @demarcate -def load_pc_sampling_data_per_kernel(file_name, kernel_name): +def load_pc_sampling_data_per_kernel( + method: str, file_name: Path, kernel_name: str, sorting_type: str +) -> pd.DataFrame: """ - Load PC sampling raw data from json file with given kernel name, + Load PC sampling raw data from json file with given method and kernel name, + count pc sampling and sort it in the order of compiled asm and associate with kernel source code if available, then return df. + + :param method: "host_trap" or "stochastic". + :type method: str + :param file_name: The pc sampling json file. + :type file_name: Path + :param kernel_name: The kernel name to be filtered out. + :type kernel_name: str + :param sorting_type: "offset" or "count". + :type sorting_type: str + :return: The counted and reordering pc sampling info. + :rtype: pd.DataFrame: """ kernel_info_list = search_key_in_json(file_name, "kernel_symbols") @@ -1132,25 +1196,31 @@ def load_pc_sampling_data_per_kernel(file_name, kernel_name): # print("kernel_info", kernel_info) - pc_sample_host_trap = search_key_in_json(file_name, "pc_sample_host_trap") + pc_sample_key_loc = ( + search_key_in_json(file_name, "pc_sample_host_trap") + if method == "host_trap" + else search_key_in_json(file_name, "pc_sample_stochastic") + ) - # print(type(pc_sample_host_trap), len(pc_sample_host_trap)) - # print(pc_sample_host_trap[0]["record"].get("pc", {}).get("code_object_offset")) - # print(search_pc_sampling_record(pc_sample_host_trap)) + # print(type(pc_sample_key_loc), len(pc_sample_key_loc)) + # print(pc_sample_key_loc[0]["record"].get("pc", {}).get("code_object_offset")) + # print(search_pc_sampling_record(pc_sample_key_loc)) df = pd.DataFrame( - search_pc_sampling_record(pc_sample_host_trap), - columns=["code_object_id", "inst_index", "offset", "count"], + search_pc_sampling_record(pc_sample_key_loc), + columns=["code_object_id", "inst_index", "offset", "count", "stall_reason"], ) df = df[ (df["code_object_id"] == kernel_info["code_object_id"]) & (df["offset"] > kernel_info["entry_byte_offset"]) & (df["offset"] < kernel_info["potential_end_offset"]) - ][["inst_index", "offset", "count"]] + ][["inst_index", "offset", "count", "stall_reason"]] df["offset"] = df["offset"].apply(lambda x: hex(x)) + # df["stall_reason"] = df["stall_reason"].apply(lambda x: ', '.join(f"{k}: {v}" for k, v in x)) + pc_sample_instructions = search_key_in_json(file_name, "pc_sample_instructions") # print(pc_sample_instructions) df["instruction"] = df["inst_index"].apply( @@ -1166,11 +1236,29 @@ def load_pc_sampling_data_per_kernel(file_name, kernel_name): ) ) - return df[["source_line", "instruction", "offset", "count"]] + # print(df[["source_line", "instruction", "offset", "count", "stall_reason"]]) + + if sorting_type == "offset": + return ( + df[["source_line", "instruction", "offset", "count"]] + if method == "host_trap" + else df[["source_line", "instruction", "offset", "count", "stall_reason"]] + ) + else: # sort by "count" + return ( + df[["source_line", "instruction", "offset", "count"]].sort_values( + by="count", ascending=False + ) + if method == "host_trap" + else df[ + ["source_line", "instruction", "offset", "count", "stall_reason"] + ].sort_values(by="count", ascending=False) + ) + # might support sort by stall reason in the future @demarcate -def load_pc_sampling_data(workload, dir, file_prefix): +def load_pc_sampling_data(workload, dir, file_prefix, sorting_type): """ Load PC sampling raw data, filter and sort it by specified conditions, then return df. @@ -1179,39 +1267,52 @@ def load_pc_sampling_data(workload, dir, file_prefix): if file_prefix.lower() == "none": return pd.DataFrame() - # No kernel filter, return grouped and sorted csv directly - if not workload.filter_kernel_ids: - # NB: the default file name is subject to changes from rocprofv3/rocprofiler_sdk + pc_sampling_method = None + + # NB: + # - The default file name is subject to changes from rocprofv3 + # - Prioritize stochastic + # - Alternatively, we could check pc_sampling_method in json + csv_file_path = Path.joinpath(Path(dir), file_prefix + "_pc_sampling_stochastic.csv") + if csv_file_path.exists(): + pc_sampling_method = "stochastic" + else: csv_file_path = Path.joinpath( Path(dir), file_prefix + "_pc_sampling_host_trap.csv" ) - if not csv_file_path.exists(): - console_error("PC sampling: can not read %s " % csv_file_path) - return pd.DataFrame() - else: - df = pd.read_csv(csv_file_path) - # Group by 'Instruction_Comment' and count occurrences - grouped_counts = ( - df.groupby("Instruction_Comment") - .agg( - count=("Instruction_Comment", "count"), - instruction=("Instruction", "first"), - ) - .reset_index() - .rename(columns={"Instruction_Comment": "source_line"}) + if csv_file_path.exists(): + pc_sampling_method = "host_trap" + + if pc_sampling_method == None: + console_error("PC sampling: can not find %s " % csv_file_path) + return pd.DataFrame() + + # No kernel filter, return grouped and sorted csv directly + if not workload.filter_kernel_ids: + + df = pd.read_csv(csv_file_path) + # Group by 'Instruction_Comment' and count occurrences + grouped_counts = ( + df.groupby("Instruction_Comment") + .agg( + count=("Instruction_Comment", "count"), + instruction=("Instruction", "first"), ) + .reset_index() + .rename(columns={"Instruction_Comment": "source_line"}) + ) - grouped_counts = grouped_counts[["source_line", "instruction", "count"]] + grouped_counts = grouped_counts[["source_line", "instruction", "count"]] - grouped_counts["source_line"] = grouped_counts["source_line"].apply( - lambda x: (".../" + Path(x).name) - ) + grouped_counts["source_line"] = grouped_counts["source_line"].apply( + lambda x: (".../" + Path(x).name) + ) - # Sort by the count of occurrences - sorted_counts = grouped_counts.sort_values(by="count", ascending=False) - # print(sorted_counts.info) + # Sort by the count of occurrences + sorted_counts = grouped_counts.sort_values(by="count", ascending=False) + # print(sorted_counts.info) - return sorted_counts + return sorted_counts elif len(workload.filter_kernel_ids) > 1: console_error( @@ -1234,14 +1335,16 @@ def load_pc_sampling_data(workload, dir, file_prefix): kernel_name = pd.read_csv(file).loc[ workload.filter_kernel_ids[0], "Kernel_Name" ] - return load_pc_sampling_data_per_kernel(json_file_path, kernel_name) + return load_pc_sampling_data_per_kernel( + pc_sampling_method, json_file_path, kernel_name, sorting_type + ) else: console_warning("PC sampling: No data") return pd.DataFrame() @demarcate -def load_kernel_top(workload, dir): +def load_kernel_top(workload, dir, args): # NB: # - Do pmc_kernel_top.csv loading before eval_metric because we need the kernel names. # - There might be a better way/timing to load raw_csv_table. @@ -1284,28 +1387,33 @@ def load_kernel_top(workload, dir): f"Couldn't load {file.name}. This may result in missing analysis data." ) elif "from_pc_sampling" in df.columns: - tmp[id] = load_pc_sampling_data(workload, dir, df.loc[0, "from_pc_sampling"]) + tmp[id] = load_pc_sampling_data( + workload, + dir, + df.loc[0, "from_pc_sampling"], + args.pc_sampling_sorting_type, + ) # print("table id", id, "filter_kernel_ids", workload.filter_kernel_ids) workload.dfs.update(tmp) @demarcate -def load_table_data(workload, dir, is_gui, debug, verbose, skipKernelTop=False): +def load_table_data(workload, dir, is_gui, args, skipKernelTop=False): """ - Load data for all "raw_csv_table" - Load dat for "pc_sampling_table" - Calculate mertric value for all "metric_table" """ if not skipKernelTop: - load_kernel_top(workload, dir) + load_kernel_top(workload, dir, args) eval_metric( workload.dfs, workload.dfs_type, workload.sys_info.iloc[0], - apply_filters(workload, dir, is_gui, debug), - debug, + apply_filters(workload, dir, is_gui, args.debug), + args.debug, ) diff --git a/src/utils/utils.py b/src/utils/utils.py index aef61183e3..74eea13dc9 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -949,12 +949,17 @@ def run_prof( df.to_csv(workload_dir + "/" + fbase + ".csv", index=False) -def pc_sampling_prof(interval, workload_dir, appcmd, rocprofiler_sdk_library_path): +def pc_sampling_prof( + method, interval, workload_dir, appcmd, rocprofiler_sdk_library_path +): """ Run rocprof with pc sampling. Current support v3 only. """ # Todo: # - precheck with rocprofv3 –-list-avail + + unit = "time" if method == "host_trap" else "cycles" + if rocprof_cmd == "rocprofiler-sdk": rocm_libdir = str(pathlib.Path(rocprofiler_sdk_library_path).parent) rocprofiler_sdk_tool_path = str( @@ -975,7 +980,7 @@ def pc_sampling_prof(interval, workload_dir, appcmd, rocprofiler_sdk_library_pat "ROCPROF_OUTPUT_PATH": workload_dir, "ROCPROF_OUTPUT_FILE_NAME": "ps_file", "ROCPROFILER_PC_SAMPLING_BETA_ENABLED": "1", - "ROCPROF_PC_SAMPLING_UNIT": "time", + "ROCPROF_PC_SAMPLING_UNIT": unit, "ROCPROF_PC_SAMPLING_INTERVAL": str(interval), "ROCPROF_PC_SAMPLING_METHOD": "host_trap", } @@ -993,7 +998,7 @@ def pc_sampling_prof(interval, workload_dir, appcmd, rocprofiler_sdk_library_pat "--pc-sampling-method", "host_trap", "--pc-sampling-unit", - "time", + unit, "--output-format", "csv", "json",