From 4244ddb07924f9ef84aa80931c331a6f1428a798 Mon Sep 17 00:00:00 2001 From: David Galiffi Date: Mon, 18 Nov 2024 15:40:59 -0500 Subject: [PATCH] ROCm 6.3 rebrand of Omniperf to ROCm Compute Profiler (#475) * Rename Omniperf to ROCm Compute Profiler (#428) - Update filenames. - Update executable to `rocprof-compute` - Update update package to `rocprofiler-compute` - Update name in application output and logs - Update name in README files - Update testing and workflows --------- Signed-off-by: Xuan Chen * Give executable permission to rocprof-compute (#456) Signed-off-by: coleramos425 * Update VERSION to 3.0.0 (#457) * Update VERSION and README to 3.0.0 * Update version mismatch of profiling data to a warning. Signed-off-by: David Galiffi * Fix changelog heading Signed-off-by: Peter Park * External CI: rename pipeline to rocprofiler-compute (#463) Signed-off-by: Daniel Su * Update branding in documentation (#442) * find/replace Omniperf to ROCm Compute Profiler Signed-off-by: Peter Park * update name in Sphinx conf Signed-off-by: Peter Park * mv what-is-omniperf.rst -> what-is-rocprof-compute.rst Signed-off-by: Peter Park * update Tutorials section Signed-off-by: Peter Park * add Omniperf as keyword to Conceptual section for internal search Signed-off-by: Peter Park * update Reference section Signed-off-by: Peter Park * black fmt conf.py Signed-off-by: Peter Park * update profile mode and basic usage subsections Signed-off-by: Peter Park * update how to use analyze mode subsection Signed-off-by: Peter Park * update install section Signed-off-by: Peter Park * fix sphinx warnings Signed-off-by: Peter Park * fix cmd line examples in profile/mode.rst Signed-off-by: Peter Park * update install decision tree image Signed-off-by: Peter Park * fix TOC and index Signed-off-by: Peter Park fix weird wording * fix cli text: deriving rocprofiler-compute metrics... Signed-off-by: Peter Park * update standalone-gui.rst Signed-off-by: Peter Park * restore removed doc updates from #428 Signed-off-by: Peter Park * update ref to Omniperf in index.rst Signed-off-by: Peter Park * fix grafana connection name to match image Signed-off-by: Peter Park * update cmds in tutorials Signed-off-by: Peter Park --------- Signed-off-by: Peter Park * Update webui branding (#459) * Update name and icon for browser tab to rocprofiler-compute. Signed-off-by: xuchen-amd * Update name and icon for browser tab to rocprofiler-compute. Signed-off-by: xuchen-amd --------- Signed-off-by: xuchen-amd * Rename grafana files to RocProfCompute * Rebranding update Missed references mostly in comments --------- Signed-off-by: Xuan Chen Signed-off-by: coleramos425 Signed-off-by: David Galiffi Signed-off-by: Peter Park Signed-off-by: Daniel Su Signed-off-by: xuchen-amd Co-authored-by: xuchen-amd Co-authored-by: Cole Ramos Co-authored-by: Peter Park Co-authored-by: Daniel Su --- .azuredevops/rocm-ci.yml | 2 +- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/workflows/mi-rhel9.yml | 8 +- .github/workflows/packaging.yml | 14 +- .github/workflows/rhel-8.yml | 2 +- .github/workflows/tarball.yml | 46 +- .github/workflows/ubuntu-jammy.yml | 2 +- AUTHORS | 2 +- CHANGELOG.md | 42 +- CMakeLists.txt | 74 +- CONTRIBUTING.md | 16 +- MAINTAINERS.md | 10 +- README.md | 24 +- VERSION | 2 +- cmake/Dockerfile | 6 +- cmake/VERSION.sha.in | 2 +- ...{omniperf.lua.in => rocprofcompute.lua.in} | 16 +- docker/build-docker-ci.sh | 4 +- docker/build-docker.sh | 2 +- docs/archive/docs-1.x/analysis.md | 6 +- docs/archive/docs-2.x/analysis.md | 4 +- docs/conceptual/command-processor.rst | 4 +- docs/conceptual/compute-unit.rst | 6 +- docs/conceptual/definitions.rst | 6 +- .../includes/normalization-units.rst | 2 +- docs/conceptual/l2-cache.rst | 10 +- docs/conceptual/local-data-share.rst | 4 +- docs/conceptual/performance-model.rst | 10 +- docs/conceptual/pipeline-descriptions.rst | 10 +- docs/conceptual/pipeline-metrics.rst | 10 +- docs/conceptual/references.rst | 4 +- docs/conceptual/shader-engine.rst | 8 +- docs/conceptual/system-speed-of-light.rst | 6 +- docs/conceptual/vector-l1-cache.rst | 12 +- docs/conf.py | 9 +- docs/data/install/install-decision-tree.png | Bin 44865 -> 360324 bytes docs/data/unused/install-decision-tree.png | Bin 0 -> 44865 bytes docs/how-to/analyze/cli.rst | 78 +- docs/how-to/analyze/grafana-gui.rst | 161 +-- docs/how-to/analyze/mode.rst | 16 +- docs/how-to/analyze/standalone-gui.rst | 32 +- docs/how-to/profile/mode.rst | 146 +-- docs/how-to/use.rst | 50 +- docs/index.rst | 30 +- docs/install/core-install.rst | 114 +- docs/install/grafana-setup.rst | 49 +- docs/license.rst | 4 +- docs/reference/compatible-accelerators.rst | 30 +- docs/reference/faq.rst | 10 +- docs/sphinx/_toc.yml.in | 5 +- .../includes/infinity-fabric-transactions.rst | 36 +- ...nstructions-per-cycle-and-utilizations.rst | 24 +- docs/tutorial/includes/lds-examples.rst | 22 +- .../includes/occupancy-limiters-example.rst | 18 +- .../valu-arithmetic-instruction-mix.rst | 8 +- .../vector-memory-operation-counting.rst | 40 +- docs/tutorial/learning-resources.rst | 18 +- docs/tutorial/profiling-by-example.rst | 8 +- ...niperf.rst => what-is-rocprof-compute.rst} | 57 +- grafana/Dockerfile | 6 +- ...ub.json => RocProfCompute_v1.0.3_pub.json} | 288 ++--- ...ub.json => RocProfCompute_v1.0.5_pub.json} | 2 +- ...ub.json => RocProfCompute_v1.0.7_pub.json} | 6 +- ...ub.json => RocProfCompute_v1.0.8_pub.json} | 10 +- ...ub.json => RocProfCompute_v2.0.0_pub.json} | 12 +- grafana/docker-compose.yml | 8 +- grafana/docker-entrypoint.sh | 2 +- grafana/grafana.ini | 2 +- grafana/plugins/omniperf_plugin/README.md | 4 +- grafana/plugins/omniperf_plugin/package.json | 4 +- .../omniperf_plugin/server/mongo-proxy.js | 2 +- ...cle.png => rocprofiler-compute_circle.png} | Bin .../plugins/omniperf_plugin/src/plugin.json | 10 +- pyproject.toml | 6 +- src/README.md | 8 +- src/argparser.py | 64 +- src/config.py | 4 +- src/{omniperf => rocprof-compute} | 24 +- .../analysis_base.py | 2 +- .../analysis_cli.py | 2 +- .../analysis_webui.py | 9 +- .../assets/default.css | 0 .../assets/favicon.ico | Bin 0 -> 1150 bytes .../assets/font-awesome/css/font-awesome.css | 0 .../font-awesome/css/font-awesome.min.css | 0 .../assets/font-awesome/fonts/FontAwesome.otf | Bin .../fonts/fontawesome-webfont.eot | Bin .../fonts/fontawesome-webfont.svg | 0 .../fonts/fontawesome-webfont.ttf | Bin .../fonts/fontawesome-webfont.woff | Bin .../font-awesome/less/bordered-pulled.less | 0 .../assets/font-awesome/less/core.less | 0 .../assets/font-awesome/less/fixed-width.less | 0 .../font-awesome/less/font-awesome.less | 0 .../assets/font-awesome/less/icons.less | 0 .../assets/font-awesome/less/larger.less | 0 .../assets/font-awesome/less/list.less | 0 .../assets/font-awesome/less/mixins.less | 0 .../assets/font-awesome/less/path.less | 0 .../font-awesome/less/rotated-flipped.less | 0 .../assets/font-awesome/less/spinning.less | 0 .../assets/font-awesome/less/stacked.less | 0 .../assets/font-awesome/less/variables.less | 0 .../font-awesome/scss/_bordered-pulled.scss | 0 .../assets/font-awesome/scss/_core.scss | 0 .../font-awesome/scss/_fixed-width.scss | 0 .../assets/font-awesome/scss/_icons.scss | 0 .../assets/font-awesome/scss/_larger.scss | 0 .../assets/font-awesome/scss/_list.scss | 0 .../assets/font-awesome/scss/_mixins.scss | 0 .../assets/font-awesome/scss/_path.scss | 0 .../font-awesome/scss/_rotated-flipped.scss | 0 .../assets/font-awesome/scss/_spinning.scss | 0 .../assets/font-awesome/scss/_stacked.scss | 0 .../assets/font-awesome/scss/_variables.scss | 0 .../font-awesome/scss/font-awesome.scss | 0 .../assets/fontello/css/animation.css | 0 .../assets/fontello/css/fontello-codes.css | 0 .../assets/fontello/css/fontello-embedded.css | 0 .../fontello/css/fontello-ie7-codes.css | 0 .../assets/fontello/css/fontello-ie7.css | 0 .../assets/fontello/css/fontello.css | 0 .../assets/fontello/font/fontello.eot | Bin .../assets/fontello/font/fontello.svg | 0 .../assets/fontello/font/fontello.ttf | Bin .../assets/fontello/font/fontello.woff | Bin .../assets/fonts.css | 0 .../librebaskerville-bold-webfont.eot | Bin .../librebaskerville-bold-webfont.svg | 0 .../librebaskerville-bold-webfont.ttf | Bin .../librebaskerville-bold-webfont.woff | Bin .../librebaskerville-italic-webfont.eot | Bin .../librebaskerville-italic-webfont.svg | 0 .../librebaskerville-italic-webfont.ttf | Bin .../librebaskerville-italic-webfont.woff | Bin .../librebaskerville-regular-webfont.eot | Bin .../librebaskerville-regular-webfont.svg | 0 .../librebaskerville-regular-webfont.ttf | Bin .../librebaskerville-regular-webfont.woff | Bin .../fonts/opensans/OpenSans-Bold-webfont.eot | Bin .../fonts/opensans/OpenSans-Bold-webfont.svg | 0 .../fonts/opensans/OpenSans-Bold-webfont.ttf | Bin .../fonts/opensans/OpenSans-Bold-webfont.woff | Bin .../opensans/OpenSans-BoldItalic-webfont.eot | Bin .../opensans/OpenSans-BoldItalic-webfont.svg | 0 .../opensans/OpenSans-BoldItalic-webfont.ttf | Bin .../opensans/OpenSans-BoldItalic-webfont.woff | Bin .../opensans/OpenSans-ExtraBold-webfont.eot | Bin .../opensans/OpenSans-ExtraBold-webfont.svg | 0 .../opensans/OpenSans-ExtraBold-webfont.ttf | Bin .../opensans/OpenSans-ExtraBold-webfont.woff | Bin .../OpenSans-ExtraBoldItalic-webfont.eot | Bin .../OpenSans-ExtraBoldItalic-webfont.svg | 0 .../OpenSans-ExtraBoldItalic-webfont.ttf | Bin .../OpenSans-ExtraBoldItalic-webfont.woff | Bin .../opensans/OpenSans-Italic-webfont.eot | Bin .../opensans/OpenSans-Italic-webfont.svg | 0 .../opensans/OpenSans-Italic-webfont.ttf | Bin .../opensans/OpenSans-Italic-webfont.woff | Bin .../fonts/opensans/OpenSans-Light-webfont.eot | Bin .../fonts/opensans/OpenSans-Light-webfont.svg | 0 .../fonts/opensans/OpenSans-Light-webfont.ttf | Bin .../opensans/OpenSans-Light-webfont.woff | Bin .../opensans/OpenSans-LightItalic-webfont.eot | Bin .../opensans/OpenSans-LightItalic-webfont.svg | 0 .../opensans/OpenSans-LightItalic-webfont.ttf | Bin .../OpenSans-LightItalic-webfont.woff | Bin .../opensans/OpenSans-Regular-webfont.eot | Bin .../opensans/OpenSans-Regular-webfont.svg | 0 .../opensans/OpenSans-Regular-webfont.ttf | Bin .../opensans/OpenSans-Regular-webfont.woff | Bin .../opensans/OpenSans-Semibold-webfont.eot | Bin .../opensans/OpenSans-Semibold-webfont.svg | 0 .../opensans/OpenSans-Semibold-webfont.ttf | Bin .../opensans/OpenSans-Semibold-webfont.woff | Bin .../OpenSans-SemiboldItalic-webfont.eot | Bin .../OpenSans-SemiboldItalic-webfont.svg | 0 .../OpenSans-SemiboldItalic-webfont.ttf | Bin .../OpenSans-SemiboldItalic-webfont.woff | Bin .../assets/layout.css | 0 .../assets/magnific-popup.css | 0 .../assets/media-queries.css | 0 ...niperf_base.py => rocprof_compute_base.py} | 48 +- .../profiler_base.py | 11 +- .../profiler_rocprof_v1.py | 4 +- .../profiler_rocprof_v2.py | 4 +- .../profiler_rocscope.py | 7 +- .../gfx906/0000_top_stats.yaml | 0 .../gfx906/0100_system_info.yaml | 0 .../gfx906/0200_system-speed-of-light.yaml | 0 .../gfx906/0300_mem_chart.yaml | 0 .../gfx906/0500_command-processor.yaml | 0 .../gfx906/0600_shader-processor-input.yaml | 0 .../gfx906/0700_wavefront-launch.yaml | 0 .../1000_compute-unit-instruction-mix.yaml | 0 .../1100_compute-unit-compute-pipeline.yaml | 0 .../analysis_configs/gfx906/1200_lds.yaml | 0 .../gfx906/1300_instruction-cache.yaml | 0 .../gfx906/1400_constant-cache.yaml | 0 .../gfx906/1500_TA_and_TD.yaml | 0 .../gfx906/1600_L1_cache.yaml | 0 .../gfx906/1700_L2_cache.yaml | 0 .../gfx906/1800_L2_cache_per_channel.yaml | 0 .../gfx908/0000_top_stats.yaml | 0 .../gfx908/0100_system_info.yaml | 0 .../gfx908/0200_system-speed-of-light.yaml | 0 .../gfx908/0300_mem_chart.yaml | 0 .../gfx908/0500_command-processor.yaml | 0 .../gfx908/0600_shader-processor-input.yaml | 0 .../gfx908/0700_wavefront-launch.yaml | 0 .../1000_compute-unit-instruction-mix.yaml | 0 .../1100_compute-unit-compute-pipeline.yaml | 0 .../analysis_configs/gfx908/1200_lds.yaml | 0 .../gfx908/1300_instruction-cache.yaml | 0 .../gfx908/1400_constant-cache.yaml | 0 .../gfx908/1500_TA_and_TD.yaml | 0 .../gfx908/1600_L1_cache.yaml | 0 .../gfx908/1700_L2_cache.yaml | 0 .../gfx908/1800_L2_cache_per_channel.yaml | 0 .../gfx90a/0000_top_stats.yaml | 0 .../gfx90a/0100_system_info.yaml | 0 .../gfx90a/0200_system-speed-of-light.yaml | 0 .../gfx90a/0300_mem_chart.yaml | 0 .../gfx90a/0400_roofline_chart.yaml | 0 .../gfx90a/0500_command-processor.yaml | 0 .../gfx90a/0600_shader-processor-input.yaml | 0 .../gfx90a/0700_wavefront-launch.yaml | 0 .../1000_compute-unit-instruction-mix.yaml | 0 .../1100_compute-unit-compute-pipeline.yaml | 0 .../analysis_configs/gfx90a/1200_lds.yaml | 0 .../gfx90a/1300_instruction-cache.yaml | 0 .../gfx90a/1400_constant-cache.yaml | 0 .../gfx90a/1500_TA_and_TD.yaml | 0 .../gfx90a/1600_L1_cache.yaml | 0 .../gfx90a/1700_L2_cache.yaml | 0 .../gfx90a/1800_L2_cache_per_channel.yaml | 0 .../gfx940/0000_top_stats.yaml | 0 .../gfx940/0100_system_info.yaml | 0 .../gfx940/0200_system-speed-of-light.yaml | 0 .../gfx940/0300_mem_chart.yaml | 0 .../gfx940/0500_command-processor.yaml | 0 .../gfx940/0600_shader-processor-input.yaml | 0 .../gfx940/0700_wavefront-launch.yaml | 0 .../1000_compute-unit-instruction-mix.yaml | 0 .../1100_compute-unit-compute-pipeline.yaml | 0 .../analysis_configs/gfx940/1200_lds.yaml | 0 .../gfx940/1300_instruction-cache.yaml | 0 .../gfx940/1400_constant-cache.yaml | 0 .../gfx940/1500_TA_and_TD.yaml | 0 .../gfx940/1600_L1_cache.yaml | 0 .../gfx940/1700_L2_cache.yaml | 0 .../gfx940/1800_L2_cache_per_channel.yaml | 0 .../gfx941/0000_top_stats.yaml | 0 .../gfx941/0100_system_info.yaml | 0 .../gfx941/0200_system-speed-of-light.yaml | 0 .../gfx941/0300_mem_chart.yaml | 0 .../gfx941/0500_command-processor.yaml | 0 .../gfx941/0600_shader-processor-input.yaml | 0 .../gfx941/0700_wavefront-launch.yaml | 0 .../1000_compute-unit-instruction-mix.yaml | 0 .../1100_compute-unit-compute-pipeline.yaml | 0 .../analysis_configs/gfx941/1200_lds.yaml | 0 .../gfx941/1300_instruction-cache.yaml | 0 .../gfx941/1400_constant-cache.yaml | 0 .../gfx941/1500_TA_and_TD.yaml | 0 .../gfx941/1600_L1_cache.yaml | 0 .../gfx941/1700_L2_cache.yaml | 0 .../gfx941/1800_L2_cache_per_channel.yaml | 0 .../gfx942/0000_top_stats.yaml | 0 .../gfx942/0100_system_info.yaml | 0 .../gfx942/0200_system-speed-of-light.yaml | 0 .../gfx942/0300_mem_chart.yaml | 0 .../gfx942/0500_command-processor.yaml | 0 .../gfx942/0600_shader-processor-input.yaml | 0 .../gfx942/0700_wavefront-launch.yaml | 0 .../1000_compute-unit-instruction-mix.yaml | 0 .../1100_compute-unit-compute-pipeline.yaml | 0 .../analysis_configs/gfx942/1200_lds.yaml | 0 .../gfx942/1300_instruction-cache.yaml | 0 .../gfx942/1400_constant-cache.yaml | 0 .../gfx942/1500_TA_and_TD.yaml | 0 .../gfx942/1600_L1_cache.yaml | 0 .../gfx942/1700_L2_cache.yaml | 0 .../gfx942/1800_L2_cache_per_channel.yaml | 0 .../panel_config_template.yaml | 0 .../profile_configs/gfx900/pmc_cpc_perf.txt | 0 .../profile_configs/gfx900/pmc_cpf_perf.txt | 0 .../profile_configs/gfx900/pmc_spi_perf.txt | 0 .../profile_configs/gfx900/pmc_sq_perf1.txt | 0 .../profile_configs/gfx900/pmc_sq_perf2.txt | 0 .../profile_configs/gfx900/pmc_sq_perf3.txt | 0 .../profile_configs/gfx900/pmc_sq_perf4.txt | 0 .../profile_configs/gfx900/pmc_sq_perf6.txt | 0 .../profile_configs/gfx900/pmc_sq_perf8.txt | 0 .../profile_configs/gfx900/pmc_sqc_perf1.txt | 0 .../profile_configs/gfx900/pmc_ta_perf.txt | 0 .../profile_configs/gfx900/pmc_tcc2_perf.txt | 0 .../profile_configs/gfx900/pmc_tcc_perf.txt | 0 .../profile_configs/gfx900/pmc_tcp_perf.txt | 0 .../profile_configs/gfx900/pmc_td_perf.txt | 0 .../profile_configs/gfx906/pmc_cpc_perf.txt | 0 .../profile_configs/gfx906/pmc_cpf_perf.txt | 0 .../profile_configs/gfx906/pmc_spi_perf.txt | 0 .../profile_configs/gfx906/pmc_sq_perf1.txt | 0 .../profile_configs/gfx906/pmc_sq_perf2.txt | 0 .../profile_configs/gfx906/pmc_sq_perf3.txt | 0 .../profile_configs/gfx906/pmc_sq_perf4.txt | 0 .../profile_configs/gfx906/pmc_sq_perf6.txt | 0 .../profile_configs/gfx906/pmc_sq_perf8.txt | 0 .../profile_configs/gfx906/pmc_sqc_perf1.txt | 0 .../profile_configs/gfx906/pmc_ta_perf.txt | 0 .../profile_configs/gfx906/pmc_tcc2_perf.txt | 0 .../profile_configs/gfx906/pmc_tcc_perf.txt | 0 .../profile_configs/gfx906/pmc_tcp_perf.txt | 0 .../profile_configs/gfx906/pmc_td_perf.txt | 0 .../profile_configs/gfx908/pmc_cpc_perf.txt | 0 .../profile_configs/gfx908/pmc_cpf_perf.txt | 0 .../profile_configs/gfx908/pmc_spi_perf.txt | 0 .../profile_configs/gfx908/pmc_sq_perf1.txt | 0 .../profile_configs/gfx908/pmc_sq_perf2.txt | 0 .../profile_configs/gfx908/pmc_sq_perf3.txt | 0 .../profile_configs/gfx908/pmc_sq_perf4.txt | 0 .../profile_configs/gfx908/pmc_sq_perf6.txt | 0 .../profile_configs/gfx908/pmc_sq_perf8.txt | 0 .../profile_configs/gfx908/pmc_sqc_perf1.txt | 0 .../profile_configs/gfx908/pmc_ta_perf.txt | 0 .../profile_configs/gfx908/pmc_tcc2_perf.txt | 0 .../profile_configs/gfx908/pmc_tcc_perf.txt | 0 .../profile_configs/gfx908/pmc_tcp_perf.txt | 0 .../profile_configs/gfx908/pmc_td_perf.txt | 0 .../profile_configs/gfx908_metrics.xml | 0 .../profile_configs/gfx90a/pmc_cpc_perf.txt | 0 .../profile_configs/gfx90a/pmc_cpf_perf.txt | 0 .../profile_configs/gfx90a/pmc_spi_perf.txt | 0 .../profile_configs/gfx90a/pmc_sq_perf1.txt | 0 .../profile_configs/gfx90a/pmc_sq_perf2.txt | 0 .../profile_configs/gfx90a/pmc_sq_perf3.txt | 0 .../profile_configs/gfx90a/pmc_sq_perf4.txt | 0 .../profile_configs/gfx90a/pmc_sq_perf6.txt | 0 .../profile_configs/gfx90a/pmc_sq_perf8.txt | 0 .../profile_configs/gfx90a/pmc_sqc_perf1.txt | 0 .../profile_configs/gfx90a/pmc_ta_perf.txt | 0 .../profile_configs/gfx90a/pmc_tcc2_perf.txt | 0 .../profile_configs/gfx90a/pmc_tcc_perf.txt | 0 .../profile_configs/gfx90a/pmc_tcp_perf.txt | 0 .../profile_configs/gfx90a/pmc_td_perf.txt | 0 .../gfx90a/roofline/pmc_roof_perf.txt | 0 .../profile_configs/gfx940/pmc_cpc_perf.txt | 0 .../profile_configs/gfx940/pmc_cpf_perf.txt | 0 .../profile_configs/gfx940/pmc_spi_perf.txt | 0 .../profile_configs/gfx940/pmc_sq_perf1.txt | 0 .../profile_configs/gfx940/pmc_sq_perf2.txt | 0 .../profile_configs/gfx940/pmc_sq_perf3.txt | 0 .../profile_configs/gfx940/pmc_sq_perf4.txt | 0 .../profile_configs/gfx940/pmc_sq_perf6.txt | 0 .../profile_configs/gfx940/pmc_sq_perf8.txt | 0 .../profile_configs/gfx940/pmc_sqc_perf1.txt | 0 .../profile_configs/gfx940/pmc_ta_perf.txt | 0 .../profile_configs/gfx940/pmc_tcc2_perf.txt | 0 .../profile_configs/gfx940/pmc_tcc_perf.txt | 0 .../profile_configs/gfx940/pmc_tcp_perf.txt | 0 .../profile_configs/gfx940/pmc_td_perf.txt | 0 .../gfx940/roofline/pmc_roof_perf.txt | 0 .../profile_configs/metrics.xml | 0 .../soc_base.py | 4 +- .../soc_gfx906.py | 6 +- .../soc_gfx908.py | 6 +- .../soc_gfx90a.py | 10 +- .../soc_gfx940.py | 11 +- .../soc_gfx941.py | 11 +- .../soc_gfx942.py | 11 +- src/roofline.py | 4 +- src/utils/db_connector.py | 9 +- src/utils/gui_components/header.py | 2 +- src/utils/logger.py | 12 +- src/utils/mem_chart.py | 4 +- src/utils/resources.py | 2 +- src/utils/specs.py | 15 +- src/utils/utils.py | 20 +- tests/4gpus.json | 35 +- tests/generate_test_analyze_workloads.py | 4 +- tests/generate_workloads.sh | 4 +- tests/test_analyze_commands.py | 226 ++-- tests/test_analyze_workloads.py | 1069 +++++++++++++---- tests/test_import_workloads.py | 826 ++++++------- tests/test_profile_general.py | 100 +- tests/test_utils.py | 10 +- utils/build.sh | 18 +- 388 files changed, 2468 insertions(+), 1843 deletions(-) rename cmake/{omniperf.lua.in => rocprofcompute.lua.in} (59%) create mode 100644 docs/data/unused/install-decision-tree.png rename docs/{what-is-omniperf.rst => what-is-rocprof-compute.rst} (70%) rename grafana/dashboards/{Omniperf_v1.0.3_pub.json => RocProfCompute_v1.0.3_pub.json} (99%) rename grafana/dashboards/{Omniperf_v1.0.5_pub.json => RocProfCompute_v1.0.5_pub.json} (99%) rename grafana/dashboards/{Omniperf_v1.0.7_pub.json => RocProfCompute_v1.0.7_pub.json} (99%) rename grafana/dashboards/{Omniperf_v1.0.8_pub.json => RocProfCompute_v1.0.8_pub.json} (99%) rename grafana/dashboards/{Omniperf_v2.0.0_pub.json => RocProfCompute_v2.0.0_pub.json} (99%) rename grafana/plugins/omniperf_plugin/src/img/{omniperf_circle.png => rocprofiler-compute_circle.png} (100%) rename src/{omniperf => rocprof-compute} (89%) rename src/{omniperf_analyze => rocprof_compute_analyze}/analysis_base.py (99%) rename src/{omniperf_analyze => rocprof_compute_analyze}/analysis_cli.py (98%) rename src/{omniperf_analyze => rocprof_compute_analyze}/analysis_webui.py (98%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/default.css (100%) create mode 100644 src/rocprof_compute_analyze/assets/favicon.ico rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/css/font-awesome.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/css/font-awesome.min.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/fonts/FontAwesome.otf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/fonts/fontawesome-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/fonts/fontawesome-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/fonts/fontawesome-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/fonts/fontawesome-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/bordered-pulled.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/core.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/fixed-width.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/font-awesome.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/icons.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/larger.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/list.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/mixins.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/path.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/rotated-flipped.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/spinning.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/stacked.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/less/variables.less (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_bordered-pulled.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_core.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_fixed-width.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_icons.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_larger.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_list.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_mixins.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_path.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_rotated-flipped.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_spinning.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_stacked.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/_variables.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/font-awesome/scss/font-awesome.scss (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/css/animation.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/css/fontello-codes.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/css/fontello-embedded.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/css/fontello-ie7-codes.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/css/fontello-ie7.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/css/fontello.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/font/fontello.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/font/fontello.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/font/fontello.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fontello/font/fontello.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-bold-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-bold-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-bold-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-bold-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-italic-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-italic-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-italic-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-italic-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-regular-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-regular-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-regular-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/librebaskerville/librebaskerville-regular-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Bold-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Bold-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Bold-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Bold-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-BoldItalic-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-BoldItalic-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-BoldItalic-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-BoldItalic-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-ExtraBold-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-ExtraBold-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-ExtraBold-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-ExtraBold-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-ExtraBoldItalic-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-ExtraBoldItalic-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-ExtraBoldItalic-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-ExtraBoldItalic-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Italic-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Italic-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Italic-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Italic-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Light-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Light-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Light-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Light-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-LightItalic-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-LightItalic-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-LightItalic-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-LightItalic-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Regular-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Regular-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Regular-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Regular-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Semibold-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Semibold-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Semibold-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-Semibold-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-SemiboldItalic-webfont.eot (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-SemiboldItalic-webfont.svg (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-SemiboldItalic-webfont.ttf (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/fonts/opensans/OpenSans-SemiboldItalic-webfont.woff (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/layout.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/magnific-popup.css (100%) rename src/{omniperf_analyze => rocprof_compute_analyze}/assets/media-queries.css (100%) rename src/{omniperf_base.py => rocprof_compute_base.py} (84%) rename src/{omniperf_profile => rocprof_compute_profile}/profiler_base.py (97%) rename src/{omniperf_profile => rocprof_compute_profile}/profiler_rocprof_v1.py (96%) rename src/{omniperf_profile => rocprof_compute_profile}/profiler_rocprof_v2.py (96%) rename src/{omniperf_profile => rocprof_compute_profile}/profiler_rocscope.py (91%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/0000_top_stats.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/0100_system_info.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/0200_system-speed-of-light.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/0300_mem_chart.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/0500_command-processor.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/0600_shader-processor-input.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/0700_wavefront-launch.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1000_compute-unit-instruction-mix.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1100_compute-unit-compute-pipeline.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1200_lds.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1300_instruction-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1400_constant-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1500_TA_and_TD.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1600_L1_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1700_L2_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx906/1800_L2_cache_per_channel.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/0000_top_stats.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/0100_system_info.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/0200_system-speed-of-light.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/0300_mem_chart.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/0500_command-processor.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/0600_shader-processor-input.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/0700_wavefront-launch.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1000_compute-unit-instruction-mix.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1100_compute-unit-compute-pipeline.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1200_lds.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1300_instruction-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1400_constant-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1500_TA_and_TD.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1600_L1_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1700_L2_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx908/1800_L2_cache_per_channel.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/0000_top_stats.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/0100_system_info.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/0200_system-speed-of-light.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/0300_mem_chart.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/0400_roofline_chart.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/0500_command-processor.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/0600_shader-processor-input.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/0700_wavefront-launch.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1000_compute-unit-instruction-mix.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1100_compute-unit-compute-pipeline.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1200_lds.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1300_instruction-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1400_constant-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1500_TA_and_TD.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1600_L1_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1700_L2_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx90a/1800_L2_cache_per_channel.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/0000_top_stats.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/0100_system_info.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/0200_system-speed-of-light.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/0300_mem_chart.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/0500_command-processor.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/0600_shader-processor-input.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/0700_wavefront-launch.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1000_compute-unit-instruction-mix.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1100_compute-unit-compute-pipeline.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1200_lds.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1300_instruction-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1400_constant-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1500_TA_and_TD.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1600_L1_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1700_L2_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx940/1800_L2_cache_per_channel.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/0000_top_stats.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/0100_system_info.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/0200_system-speed-of-light.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/0300_mem_chart.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/0500_command-processor.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/0600_shader-processor-input.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/0700_wavefront-launch.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1000_compute-unit-instruction-mix.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1100_compute-unit-compute-pipeline.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1200_lds.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1300_instruction-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1400_constant-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1500_TA_and_TD.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1600_L1_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1700_L2_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx941/1800_L2_cache_per_channel.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/0000_top_stats.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/0100_system_info.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/0200_system-speed-of-light.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/0300_mem_chart.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/0500_command-processor.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/0600_shader-processor-input.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/0700_wavefront-launch.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1000_compute-unit-instruction-mix.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1100_compute-unit-compute-pipeline.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1200_lds.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1300_instruction-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1400_constant-cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1500_TA_and_TD.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1600_L1_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1700_L2_cache.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/gfx942/1800_L2_cache_per_channel.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/analysis_configs/panel_config_template.yaml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_cpc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_cpf_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_spi_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_sq_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_sq_perf2.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_sq_perf3.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_sq_perf4.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_sq_perf6.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_sq_perf8.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_sqc_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_ta_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_tcc2_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_tcc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_tcp_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx900/pmc_td_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_cpc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_cpf_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_spi_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_sq_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_sq_perf2.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_sq_perf3.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_sq_perf4.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_sq_perf6.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_sq_perf8.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_sqc_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_ta_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_tcc2_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_tcc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_tcp_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx906/pmc_td_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_cpc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_cpf_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_spi_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_sq_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_sq_perf2.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_sq_perf3.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_sq_perf4.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_sq_perf6.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_sq_perf8.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_sqc_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_ta_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_tcc2_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_tcc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_tcp_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908/pmc_td_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx908_metrics.xml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_cpc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_cpf_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_spi_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_sq_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_sq_perf2.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_sq_perf3.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_sq_perf4.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_sq_perf6.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_sq_perf8.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_sqc_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_ta_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_tcc2_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_tcc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_tcp_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/pmc_td_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx90a/roofline/pmc_roof_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_cpc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_cpf_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_spi_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_sq_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_sq_perf2.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_sq_perf3.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_sq_perf4.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_sq_perf6.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_sq_perf8.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_sqc_perf1.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_ta_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_tcc2_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_tcc_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_tcp_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/pmc_td_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/gfx940/roofline/pmc_roof_perf.txt (100%) rename src/{omniperf_soc => rocprof_compute_soc}/profile_configs/metrics.xml (100%) rename src/{omniperf_soc => rocprof_compute_soc}/soc_base.py (99%) rename src/{omniperf_soc => rocprof_compute_soc}/soc_gfx906.py (95%) rename src/{omniperf_soc => rocprof_compute_soc}/soc_gfx908.py (95%) rename src/{omniperf_soc => rocprof_compute_soc}/soc_gfx90a.py (94%) rename src/{omniperf_soc => rocprof_compute_soc}/soc_gfx940.py (92%) rename src/{omniperf_soc => rocprof_compute_soc}/soc_gfx941.py (92%) rename src/{omniperf_soc => rocprof_compute_soc}/soc_gfx942.py (93%) diff --git a/.azuredevops/rocm-ci.yml b/.azuredevops/rocm-ci.yml index dad6d8592..51dddb9cc 100644 --- a/.azuredevops/rocm-ci.yml +++ b/.azuredevops/rocm-ci.yml @@ -43,4 +43,4 @@ pr: drafts: false jobs: - - template: ${{ variables.CI_COMPONENT_PATH }}/omniperf.yml@pipelines_repo + - template: ${{ variables.CI_COMPONENT_PATH }}/rocprofiler-compute.yml@pipelines_repo diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 4dec4e1b1..feff459fd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,7 +12,7 @@ A clear and concise description of what the bug is. **Development Environment:** - Linux Distribution: [e.g. Ubuntu20.04, RHEL8] - - Omniperf Version: [e.g. try `omniperf --version`] + - ROCm Compute Profiler Version: [e.g. try `rocprof-compute --version`] - GPU: [e.g. Mi100, Mi200] - Custer (if applicable): [e.g. Crusher, ] diff --git a/.github/workflows/mi-rhel9.yml b/.github/workflows/mi-rhel9.yml index 4cc54454f..6f594aa00 100644 --- a/.github/workflows/mi-rhel9.yml +++ b/.github/workflows/mi-rhel9.yml @@ -30,7 +30,7 @@ jobs: runs-on: [mi100, rhel9] env: - PYTHONPATH: /home1/ciuser/omniperf_deps + PYTHONPATH: /home1/ciuser/rocprofiler_compute_deps CI_VISIBLE_DEVICES: 1 name: ROCm v${{ matrix.version }} / ${{ matrix.hardware }} / ${{ matrix.profiler }} steps: @@ -85,17 +85,17 @@ jobs: run: | cd build make - srun -N 1 -J omniperf -p $CI_QUEUE -t 00:20:00 ctest -j 4 --resource-spec-file ../tests/4gpus.json --verbose -L profile + srun -N 1 -J rocprof-compute -p $CI_QUEUE -t 00:20:00 ctest -j 4 --resource-spec-file ../tests/4gpus.json --verbose -L profile - name: Run [analyze workloads] mode if: '!cancelled()' run: | cd build - srun -N 1 -J omniperf -p $CI_QUEUE -t 00:10:00 ctest --verbose -R test_analyze_workloads + srun -N 1 -J rocprof-compute -p $CI_QUEUE -t 00:10:00 ctest --verbose -R test_analyze_workloads - name: Run [analyze commands] mode if: '!cancelled()' run: | cd build - srun -N 1 -J omniperf -p $CI_QUEUE -t 00:10:00 ctest --verbose -R test_analyze_commands + srun -N 1 -J rocprof-compute -p $CI_QUEUE -t 00:10:00 ctest --verbose -R test_analyze_commands - name: Publish Test Results uses: EnricoMi/publish-unit-test-result-action/linux@v2 if: always() diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml index 2b64bbd5d..766ae957f 100644 --- a/.github/workflows/packaging.yml +++ b/.github/workflows/packaging.yml @@ -37,25 +37,25 @@ jobs: cd build make package_source - name: Rename tarball - run: mv build/omniperf-*.tar.gz build/omniperf-${{github.ref_name}}.tar.gz + run: mv build/rocprofiler-compute-*.tar.gz build/rocprofiler-compute-${{github.ref_name}}.tar.gz - name: Archive tarball uses: actions/upload-artifact@v4 with: - name: omniperf-${{github.ref_name}}.tar.gz - path: build/omniperf-${{github.ref_name}}.tar.gz + name: rocprofiler-compute-${{github.ref_name}}.tar.gz + path: build/rocprofiler-compute-${{github.ref_name}}.tar.gz - name: Set version run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV - name: Determine release name run: | if [[ ${{github.ref_name}} == rocm-* ]]; then - echo "RELEASE_NAME=Omniperf ${{ env.VERSION }} for ${{github.ref_name}}" + echo "RELEASE_NAME=rocprofiler-compute ${{ env.VERSION }} for ${{github.ref_name}}" else - echo "RELEASE_NAME=Omniperf ${{ env.VERSION }}" + echo "RELEASE_NAME=rocprofiler-compute ${{ env.VERSION }}" fi >> $GITHUB_ENV - name: Upload tarball Release Asset uses: softprops/action-gh-release@v2 - if: startsWith(github.ref, 'refs/tags/') && github.repository == 'ROCm/omniperf' + if: startsWith(github.ref, 'refs/tags/') && github.repository == 'ROCm/rocprofiler-compute' with: fail_on_unmatched: True files: | - build/omniperf-${{github.ref_name}}.tar.gz + build/rocprofiler-compute-${{github.ref_name}}.tar.gz diff --git a/.github/workflows/rhel-8.yml b/.github/workflows/rhel-8.yml index 01dfad591..16ecc35e2 100644 --- a/.github/workflows/rhel-8.yml +++ b/.github/workflows/rhel-8.yml @@ -42,7 +42,7 @@ jobs: run: | mkdir build cd build - cmake -DCMAKE_INSTALL_PREFIX=/opt/omniperf -DPYTEST_NUMPROCS=4 .. + cmake -DCMAKE_INSTALL_PREFIX=/opt/rocprofiler-compute -DPYTEST_NUMPROCS=4 .. make install - name: CTest- Analyze Commands run: | diff --git a/.github/workflows/tarball.yml b/.github/workflows/tarball.yml index b112cfb7f..9b5218835 100644 --- a/.github/workflows/tarball.yml +++ b/.github/workflows/tarball.yml @@ -8,7 +8,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true - + jobs: distbuild: runs-on: ubuntu-latest @@ -47,7 +47,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: tarball-testing - path: build/omniperf-*.tar.gz + path: build/rocprofiler-compute-*.tar.gz retention-days: 3 disttest: runs-on: ubuntu-latest @@ -61,48 +61,48 @@ jobs: with: name: tarball-testing - name: Expand - run: tar xfz omniperf-*.tar.gz; rm omniperf-*.tar.gz + run: tar xfz rocprofiler-compute-*.tar.gz; rm rocprofiler-compute-*.tar.gz - name: Python dependency installs run: | - cd omniperf-* + cd rocprofiler-compute-* python3 -m pip install -t${INSTALL_DIR}/python-libs -r requirements.txt - name: Configure run: | - cd omniperf-* + cd rocprofiler-compute-* mkdir build cd build - cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}/omniperf \ + cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}/rocprofiler-compute \ -DPYTHON_DEPS=${INSTALL_DIR}/python-libs .. - name: Install run: | - cd omniperf-* + cd rocprofiler-compute-* cd build make install - name: Verify expected paths run: | # find $INSTALL_DIR - test -d $INSTALL_DIR/omniperf - test -x $INSTALL_DIR/omniperf/bin/omniperf - test -s $INSTALL_DIR/omniperf/libexec/omniperf/VERSION - test -s $INSTALL_DIR/omniperf/libexec/omniperf/VERSION.sha - test -d $INSTALL_DIR/omniperf/libexec/omniperf/omniperf_analyze - test -d $INSTALL_DIR/omniperf/libexec/omniperf/omniperf_profile - test -d $INSTALL_DIR/omniperf/libexec/omniperf/omniperf_soc - test -d $INSTALL_DIR/omniperf/libexec/omniperf/utils - test -s $INSTALL_DIR/omniperf/share/omniperf/sample/vcopy.cpp - test -d $INSTALL_DIR/omniperf/share/omniperf/modulefiles - test -s $INSTALL_DIR/omniperf/share/doc/omniperf/LICENSE + test -d $INSTALL_DIR/rocprofiler-compute + test -x $INSTALL_DIR/rocprofiler-compute/bin/rocprof-compute + test -s $INSTALL_DIR/rocprofiler-compute/libexec/rocprofiler-compute/VERSION + test -s $INSTALL_DIR/rocprofiler-compute/libexec/rocprofiler-compute/VERSION.sha + test -d $INSTALL_DIR/rocprofiler-compute/libexec/rocprofiler-compute/rocprof_compute_analyze + test -d $INSTALL_DIR/rocprofiler-compute/libexec/rocprofiler-compute/rocprof_compute_profile + test -d $INSTALL_DIR/rocprofiler-compute/libexec/rocprofiler-compute/rocprof_compute_soc + test -d $INSTALL_DIR/rocprofiler-compute/libexec/rocprofiler-compute/utils + test -s $INSTALL_DIR/rocprofiler-compute/share/rocprofiler-compute/sample/vcopy.cpp + test -d $INSTALL_DIR/rocprofiler-compute/share/rocprofiler-compute/modulefiles + test -s $INSTALL_DIR/rocprofiler-compute/share/doc/rocprofiler-compute/LICENSE - name: Query version (setting PYTHONPATH by hand) run: | export PYTHONPATH=${INSTALL_DIR}/python-libs:$PYTHONPATH - $INSTALL_DIR/omniperf/bin/omniperf --version + $INSTALL_DIR/rocprofiler-compute/bin/rocprof-compute --version - name: Install Lmod run: sudo apt-get install -y lmod - - name: Access omniperf using modulefile + - name: Access rocprofiler-compute using modulefile run: | . /etc/profile.d/lmod.sh - module use $INSTALL_DIR/omniperf/share/omniperf/modulefiles - module load omniperf + module use $INSTALL_DIR/rocprofiler-compute/share/rocprofiler-compute/modulefiles + module load rocprofiler-compute module list - omniperf --version + rocprof-compute --version diff --git a/.github/workflows/ubuntu-jammy.yml b/.github/workflows/ubuntu-jammy.yml index 1dbf06b59..9233f55c6 100644 --- a/.github/workflows/ubuntu-jammy.yml +++ b/.github/workflows/ubuntu-jammy.yml @@ -41,7 +41,7 @@ jobs: run: | mkdir build cd build - cmake -DCMAKE_INSTALL_PREFIX=/opt/omniperf -DPYTEST_NUMPROCS=4 .. + cmake -DCMAKE_INSTALL_PREFIX=/opt/rocprofiler-compute -DPYTEST_NUMPROCS=4 .. make install - name: CTest- Analyze Commands run: | diff --git a/AUTHORS b/AUTHORS index ee4978b2b..48bc2a9ec 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -# This is the list of Omniperf's significant contributors. +# This is the list of ROCm Compute Profiler's significant contributors. # # This does not necessarily list everyone who has contributed code, # especially since many employees of one corporation may be contributing. diff --git a/CHANGELOG.md b/CHANGELOG.md index 2721d3749..7200a39a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,38 +1,38 @@ -# Changelog for Omniperf +# Changelog for ROCm Compute Profiler -Full documentation for Omniperf is available at [https://rocm.docs.amd.com/projects/omniperf/en/latest/](https://rocm.docs.amd.com/projects/omniperf/en/latest/). +Full documentation for ROCm Compute Profiler is available at [https://rocm.docs.amd.com/projects/rocprofiler-compute/en/latest/](https://rocm.docs.amd.com/projects/rocprofiler-compute/en/latest/). -## Omniperf 2.1.0 for ROCm 6.2.2 +## Omniperf 2.0.1 for ROCm 6.2.1 -### Changes +### Changed - * enable rocprofv1 for MI300 hardware (#391) - * refactoring and updating documemtation (#362, #394, #398, #414, #420) - * branch renaming and workflow updates (#389, #404, #409) - * bug fix for analysis output - * add dependency checks on application launch (#393) - * patch for profiling multi-process/multi-GPU applications (#376, #396) - * packaging updates (#386) - * rename CHANGES to CHANGELOG.md (#410) - * rollback Grafana version in Dockerfile for Angular plugin compatibility (#416) - * enable CI triggers for Azure CI (#426) - * add GPU model distinction for MI300 systems (#423) - * new MAINTAINERS.md guide for omniperf publishing procedures (#402) +* enable rocprofv1 for MI300 hardware (#391) +* refactoring and updating documemtation (#362, #394, #398, #414, #420) +* branch renaming and workflow updates (#389, #404, #409) +* bug fix for analysis output +* add dependency checks on application launch (#393) +* patch for profiling multi-process/multi-GPU applications (#376, #396) +* packaging updates (#386) +* rename CHANGES to CHANGELOG.md (#410) +* rollback Grafana version in Dockerfile for Angular plugin compatibility (#416) +* enable CI triggers for Azure CI (#426) +* add GPU model distinction for MI300 systems (#423) +* new MAINTAINERS.md guide for omniperf publishing procedures (#402) -### Optimizations +### Optimized - * reduced running time of Omniperf when profiling (#384) - * console logging improvements +* reduced running time of Omniperf when profiling (#384) +* console logging improvements ## Omniperf 2.0.1 for ROCm 6.2.0 -### Changes +### Added * new option to force hardware target via `OMNIPERF_ARCH_OVERRIDE` global (#370) * CI/CD support for MI300 hardware (#373) * support for MI308X hardware (#375) -### Optimizations +### Optimized * cmake build improvements (#374) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02ba8e534..b312b6db5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,20 +16,27 @@ message(STATUS "Hostname: ${LOCALHOST}") # Versioning info derived from file file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" FULL_VERSION_STRING LIMIT_COUNT 1) string(REGEX REPLACE "(\n|\r)" "" FULL_VERSION_STRING "${FULL_VERSION_STRING}") -set(OMNIPERF_FULL_VERSION "${FULL_VERSION_STRING}") -string(REGEX REPLACE "([0-9]+)\.([0-9]+)\.([0-9]+)(.*)" "\\1.\\2.\\3" OMNIPERF_VERSION - "${FULL_VERSION_STRING}") +set(ROCPROFCOMPUTE_FULL_VERSION "${FULL_VERSION_STRING}") +string(REGEX REPLACE "([0-9]+)\.([0-9]+)\.([0-9]+)(.*)" "\\1.\\2.\\3" + ROCPROFCOMPUTE_VERSION "${FULL_VERSION_STRING}") -# string(REGEX REPLACE "(${OMNIPERF_VERSION})(.*)" "\\2" OMNIPERF_VERSION_TWEAK +# string(REGEX REPLACE "(${ROCPROFCOMPUTE_VERSION})(.*)" "\\2" +# ROCPROFCOMPUTE_VERSION_TWEAK # "${FULL_VERSION_STRING}") -# string(REGEX REPLACE "^\\." "" OMNIPERF_VERSION_TWEAK "${OMNIPERF_VERSION_TWEAK}") +# string(REGEX REPLACE "^\\." "" ROCPROFCOMPUTE_VERSION_TWEAK +# "${ROCPROFCOMPUTE_VERSION_TWEAK}") project( - omniperf - VERSION ${OMNIPERF_VERSION} + rocprofiler-compute + VERSION ${ROCPROFCOMPUTE_VERSION} LANGUAGES C - DESCRIPTION "OmniPerf" - HOMEPAGE_URL "https://github.com/ROCm/omniperf") + DESCRIPTION + "A kernel-level profiling tool for machine learning/HPC workloads running on AMD MI GPUs" + HOMEPAGE_URL "https://github.com/ROCm/rocprofiler-compute") + +set(PACKAGE_NAME "rocprofiler-compute") +set(PACKAGE_NAME_UNDERSCORE "rocprofiler_compute") +set(EXECUTABLE_NAME "rocprof-compute") include(ExternalProject) include(GNUInstallDirs) @@ -39,9 +46,9 @@ find_package(Git) if(Git_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") execute_process( COMMAND git log --pretty=format:%h -n 1 - OUTPUT_VARIABLE OMNIPERF_GIT_REV + OUTPUT_VARIABLE ROCPROFCOMPUTE_GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE) - message(STATUS "Git revision: ${OMNIPERF_GIT_REV}") + message(STATUS "Git revision: ${ROCPROFCOMPUTE_GIT_REV}") set(GIT_CLONE TRUE) else() set(GIT_CLONE FALSER) @@ -133,18 +140,19 @@ set(MOD_INSTALL_PATH CACHE STRING "Install path for modulefile") message(STATUS "Modulefile install path: ${MOD_INSTALL_PATH}") -set(moduleFileTemplate "omniperf.lua.in") +set(moduleFileTemplate "rocprofcompute.lua.in") configure_file( ${PROJECT_SOURCE_DIR}/cmake/${moduleFileTemplate} - ${PROJECT_BINARY_DIR}/${MOD_INSTALL_PATH}/${OMNIPERF_FULL_VERSION}.lua @ONLY) + ${PROJECT_BINARY_DIR}/${MOD_INSTALL_PATH}/${ROCPROFCOMPUTE_FULL_VERSION}.lua @ONLY) # Thera mods if(LOCALHOST MATCHES "TheraS01|.*\.thera\.amd\.com|thera-hn") list(APPEND CMAKE_MESSAGE_INDENT " ") message(STATUS "Using thera-specific modulefile modification") file(READ ${PROJECT_SOURCE_DIR}/cmake/modfile.thera.mod mod_additions) - file(APPEND ${PROJECT_BINARY_DIR}/${MOD_INSTALL_PATH}/${OMNIPERF_FULL_VERSION}.lua + file(APPEND + ${PROJECT_BINARY_DIR}/${MOD_INSTALL_PATH}/${ROCPROFCOMPUTE_FULL_VERSION}.lua ${mod_additions}) list(POP_BACK CMAKE_MESSAGE_INDENT) endif() @@ -274,9 +282,9 @@ add_test( # Install # --------- -# top-level omniperf utility +# top-level rocprofiler-compute utility install( - PROGRAMS src/omniperf + PROGRAMS src/${EXECUTABLE_NAME} DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/${PROJECT_NAME} COMPONENT main) # python dependency requirements @@ -286,16 +294,16 @@ install( COMPONENT main) # support files and version info install( - FILES src/argparser.py src/config.py src/omniperf_base.py src/roofline.py VERSION - VERSION.sha + FILES src/argparser.py src/config.py src/rocprof_compute_base.py src/roofline.py + VERSION VERSION.sha DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/${PROJECT_NAME} COMPONENT main) -# src/omniperf_analyze +# src/rocprof_compute_analyze install( - DIRECTORY src/omniperf_analyze + DIRECTORY src/rocprof_compute_analyze DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/${PROJECT_NAME} COMPONENT main - PATTERN src/omniperf_analyze/tests EXCLUDE + PATTERN src/rocprof_compute_analyze/tests EXCLUDE PATTERN "__pycache__" EXCLUDE) # src/utils install( @@ -310,15 +318,15 @@ install( PROGRAMS ${rooflinebins} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT main) -# src/omniperf_soc +# src/rocprof_compute_soc install( - DIRECTORY src/omniperf_soc + DIRECTORY src/rocprof_compute_soc DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/${PROJECT_NAME} COMPONENT main PATTERN "__pycache__" EXCLUDE) -# src/omniperf_profile +# src/rocprof_compute_profile install( - DIRECTORY src/omniperf_profile + DIRECTORY src/rocprof_compute_profile DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/${PROJECT_NAME} COMPONENT main PATTERN "__pycache__" EXCLUDE) @@ -339,16 +347,16 @@ install( PATTERN "workloads" EXCLUDE) # modulefile install( - FILES ${PROJECT_BINARY_DIR}/${MOD_INSTALL_PATH}/${OMNIPERF_FULL_VERSION}.lua + FILES ${PROJECT_BINARY_DIR}/${MOD_INSTALL_PATH}/${ROCPROFCOMPUTE_FULL_VERSION}.lua DESTINATION ${MOD_INSTALL_PATH} COMPONENT main) -# top-level symlink for bin/omniperf +# top-level symlink for bin/rocprof-compute install( CODE "execute_process( COMMAND bash -c \"set -e cd \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX} - ln -sf ../${CMAKE_INSTALL_LIBEXECDIR}/${PROJECT_NAME}/omniperf ${CMAKE_INSTALL_BINDIR}/omniperf + ln -sf ../${CMAKE_INSTALL_LIBEXECDIR}/${PROJECT_NAME}/${EXECUTABLE_NAME} ${CMAKE_INSTALL_BINDIR}/${EXECUTABLE_NAME} \")" COMPONENT main) @@ -361,7 +369,7 @@ add_custom_target( COMMAND ${PROJECT_SOURCE_DIR}/utils/update_license.py --source ${PROJECT_SOURCE_DIR} --license ${PROJECT_SOURCE_DIR}/LICENSE --file - "src/omniperf,cmake/Dockerfile,cmake/rocm_install.sh,docker/docker-entrypoint.sh,src/omniperf_analyze/convertor/mongodb/convert" + "src/${PACKAGE_NAME},cmake/Dockerfile,cmake/rocm_install.sh,docker/docker-entrypoint.sh,src/rocprof_compute_analyze/convertor/mongodb/convert" ) install( @@ -401,9 +409,11 @@ set(CPACK_GENERATOR set(CPACK_PACKAGE_NAME "${PROJECT_NAME}" CACHE STRING "") -set(CPACK_PACKAGE_CONTACT "https://github.com/ROCm/omniperf") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Omniperf: tool for GPU performance profiling") -set(CPACK_RPM_PACKAGE_DESCRIPTION "Omniperf is a performance analysis tool for profiling +set(CPACK_PACKAGE_CONTACT "https://github.com/ROCm/rocprofiler-compute") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "ROCm Compute Profiler: tool for GPU performance profiling") +set(CPACK_RPM_PACKAGE_DESCRIPTION + "ROCm Compute Profiler is a performance analysis tool for profiling machine learning/HPC workloads running on AMD GPUs.") set(CPACK_PACKAGE_VENDOR "Advanced Micro Devices, Inc.") diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f18ea2ca2..640305b89 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,11 @@ ## How to fork from us -To keep our development fast and conflict free, we recommend you to [fork](https://github.com/ROCm/omniperf/fork) our repository and start your work from our `amd-staging` branch in your private repository. +To keep our development fast and conflict free, we recommend you to [fork](https://github.com/ROCm/rocprofiler-compute/fork) our repository and start your work from our `amd-staging` branch in your private repository. Afterwards, git clone your repository to your local machine. But that is not it! To keep track of the original develop repository, add it as another remote. ``` -git remote add mainline https://github.com/ROCm/omniperf.git +git remote add mainline https://github.com/ROCm/rocprofiler-compute.git git checkout amd-staging ``` @@ -17,23 +17,23 @@ git checkout -b topic- and apply your changes there. -## How to contribute to Omniperf +## How to contribute to ROCm Compute Profiler ### Did you find a bug? -- Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/ROCm/omniperf/issues). +- Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/ROCm/rocprofiler-compute/issues). -- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/ROCm/omniperf/issues/new). +- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/ROCm/rocprofiler-compute/issues/new). ### Did you write a patch that fixes a bug? -- Open a new GitHub [pull request](https://github.com/ROCm/omniperf/compare) with the patch. +- Open a new GitHub [pull request](https://github.com/ROCm/rocprofiler-compute/compare) with the patch. - Ensure the PR description clearly describes the problem and solution. If there is an existing GitHub issue open describing this bug, please include it in the description so we can close it. -- Ensure the PR is based on the `amd-staging` branch of the Omniperf GitHub repository. +- Ensure the PR is based on the `amd-staging` branch of the ROCm Compute Profiler GitHub repository. -- Omniperf requires new commits to include a "Signed-off-by" token in the commit message (typically enabled via the `git commit -s` option), indicating your agreement to the projects's [Developer's Certificate of Origin](https://developercertificate.org/) and compatability with the project [LICENSE](LICENSE): +- ROCm Compute Profiler requires new commits to include a "Signed-off-by" token in the commit message (typically enabled via the `git commit -s` option), indicating your agreement to the projects's [Developer's Certificate of Origin](https://developercertificate.org/) and compatability with the project [LICENSE](LICENSE): > (a) The contribution was created in whole or in part by me and I diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 0ee7f23da..dbf64db3e 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,11 +1,11 @@ -# Maintainers Guide to Omniperf +# Maintainers Guide to ROCm Compute Profiler ## Publishing a release -Before publishing a new Omniperf release, please review this checklist to ensure all prerequisites are met: +Before publishing a new ROCm Compute Profiler release, please review this checklist to ensure all prerequisites are met: 1) **Ensure [VERSION](VERSION) file is updated** to reflect your desired release version. -2) **Sync `amd-mainline` with `amd-staging`**. A rebase may be required to pull all the desired patches from the development branch to our stable mainline. Click [here](https://github.com/ROCm/omniperf/compare/amd-mainline...amd-staging) to begin that process. +2) **Sync `amd-mainline` with `amd-staging`**. A rebase may be required to pull all the desired patches from the development branch to our stable mainline. Click [here](https://github.com/ROCm/rocprofiler-compute/compare/amd-mainline...amd-staging) to begin that process. 3) **Update [CHANGES](CHANGES)** to reflect all major modifications to the codebase since the last release. When modifying [CHANGES](CHANGES) please ensure formatting is consistent with the rest of the ROCm software stack. See [this template](https://github.com/ROCm/hipTensor/blob/develop/CHANGELOG.md) for reference. 4) **Confirm all CI tests are passing**. You can easily confirm this by peeking the passing status of all GitHub continuous integration tests. 5) **Create a tag from `amd-mainline`**. More information on tagging can be found at [Git Docs - Tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging). @@ -13,7 +13,7 @@ Before publishing a new Omniperf release, please review this checklist to ensure > [!NOTE] Note: A successful tag should trigger the [packaging action](.github/workflows/packaging.yml) which will produce a tarball artifact. **This artifact needs to be included as an asset in your release**. Please find that the [packaging action](.github/workflows/packaging.yml) will automatically create a draft release with your tarball attached. -Once you've completed the above checklist, you are ready to publish your release. Please ensure you follow formatting from [past Omniperf releases](https://github.com/ROCm/omniperf/releases) for consistency. Some important aspects of our release formatting include: +Once you've completed the above checklist, you are ready to publish your release. Please ensure you follow formatting from [past ROCm Compute Profiler releases](https://github.com/ROCm/rocprofiler-compute/releases) for consistency. Some important aspects of our release formatting include: - Date of release is included in "Release Title". - Updates are called out in "Release Description". Updates should mirror those listed in [CHANGES](CHANGES). @@ -24,6 +24,6 @@ Once you've completed the above checklist, you are ready to publish your release If you are preparing for a new ROCm release, note that the [rocm-ci](https://github.com/rocm-ci) bot managed by DevOps will be triggering a tag automatically. This tag will follow the format `rocm-X.X.X`. -Traditionally, we will bump the Omniperf [VERSION](VERSION) with a new ROCm release. When we bump the version and reach the prerequisite step (5) above, try tagging with `vX.X.X` to validate the release tarball generated by the [packaging action](.github/workflows/packaging.yml). +Traditionally, we will bump the ROCm Compute Profiler [VERSION](VERSION) with a new ROCm release. When we bump the version and reach the prerequisite step (5) above, try tagging with `vX.X.X` to validate the release tarball generated by the [packaging action](.github/workflows/packaging.yml). In addition to the prerequisites mentioned above, please make sure that all changes have been merged from `amd-staging` -> `release/rocm-rel-X.X.X` to ensure that the "rocm-ci" bot will capture all your changes. It is easiest to file a single pull request ahead of the ROCm release. diff --git a/README.md b/README.md index c2b696b27..36d4d7f5d 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,22 @@ -[![Ubuntu 22.04](https://github.com/ROCm/omniperf/actions/workflows/ubuntu-jammy.yml/badge.svg)](https://github.com/ROCm/omniperf/actions/workflows/ubuntu-jammy.yml) -[![RHEL 8](https://github.com/ROCm/omniperf/actions/workflows/rhel-8.yml/badge.svg)](https://github.com/ROCm/omniperf/actions/workflows/rhel-8.yml) -[![Instinct](https://github.com/ROCm/omniperf/actions/workflows/mi-rhel9.yml/badge.svg)](https://github.com/ROCm/omniperf/actions/workflows/mi-rhel9.yml) -[![Docs](https://github.com/ROCm/omniperf/actions/workflows/docs.yml/badge.svg)](https://rocm.github.io/omniperf/) +[![Ubuntu 22.04](https://github.com/ROCm/rocprofiler-compute/actions/workflows/ubuntu-jammy.yml/badge.svg)](https://github.com/ROCm/rocprofiler-compute/actions/workflows/ubuntu-jammy.yml) +[![RHEL 8](https://github.com/ROCm/rocprofiler-compute/actions/workflows/rhel-8.yml/badge.svg)](https://github.com/ROCm/rocprofiler-compute/actions/workflows/rhel-8.yml) +[![Instinct](https://github.com/ROCm/rocprofiler-compute/actions/workflows/mi-rhel9.yml/badge.svg)](https://github.com/ROCm/rocprofiler-compute/actions/workflows/mi-rhel9.yml) +[![Docs](https://github.com/ROCm/rocprofiler-compute/actions/workflows/docs.yml/badge.svg)](https://rocm.github.io/rocprofiler-compute/) [![DOI](https://zenodo.org/badge/561919887.svg)](https://zenodo.org/badge/latestdoi/561919887) -# Omniperf +# ROCm Compute Profiler ## General -Omniperf is a system performance profiling tool for machine +ROCm Compute Profiler is a system performance profiling tool for machine learning/HPC workloads running on AMD MI GPUs. The tool presently targets usage on MI100, MI200, and MI300 accelerators. * For more information on available features, installation steps, and workload profiling and analysis, please refer to the online -[documentation](https://rocm.docs.amd.com/projects/omniperf/en/latest/). +[documentation](https://rocm.docs.amd.com/projects/rocprofiler-compute/en/latest/). -* Omniperf is an AMD open source research project and is not supported +* ROCm Compute Profiler is an AMD open source research project and is not supported as part of the ROCm software stack. We welcome contributions and feedback from the community. Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for additional details on our @@ -26,7 +26,7 @@ contribution process. ## Development -Omniperf follows a +ROCm Compute Profiler follows a [main-dev](https://nvie.com/posts/a-successful-git-branching-model/) branching model. As a result, our latest stable release is shipped from the `amd-mainline` branch, while new features are developed in our @@ -50,11 +50,11 @@ style reference is provided below for convenience: Keith Lowery and Nicholas Curtis and Cristian Di Pietrantonio}, - title = {AMDResearch/omniperf: v2.1.0 (27 Sept 2024)}, - month = sept, + title = {ROCm/rocprofiler-compute: v3.0.0 (01 November 2024)}, + month = November, year = 2024, publisher = {Zenodo}, - version = {v2.1.0}, + version = {v3.0.0}, doi = {10.5281/zenodo.7314631}, url = {https://doi.org/10.5281/zenodo.7314631} } diff --git a/VERSION b/VERSION index 7ec1d6db4..4a36342fc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0 +3.0.0 diff --git a/cmake/Dockerfile b/cmake/Dockerfile index 346e64aa7..b38dd735b 100644 --- a/cmake/Dockerfile +++ b/cmake/Dockerfile @@ -26,16 +26,16 @@ FROM ubuntu:20.04 USER root -COPY rocm_install.sh /omniperf/rocm_install.sh +COPY rocm_install.sh /rocprofiler-compute/rocm_install.sh -ENV PATH="/omniperf:${PATH}" +ENV PATH="/rocprofiler-compute:${PATH}" ENV TZ="US/Chicago" ENV DEBIAN_FRONTEND noninteractive #pyenv dependencies RUN apt update && \ apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl -ENV HOME="/omniperf" +ENV HOME="/rocprofiler-compute" WORKDIR $HOME ENV PYENV_ROOT="$HOME/.pyenv" ENV PATH="$PYENV_ROOT/bin:$PATH" diff --git a/cmake/VERSION.sha.in b/cmake/VERSION.sha.in index 5b3d30150..def9f7893 100644 --- a/cmake/VERSION.sha.in +++ b/cmake/VERSION.sha.in @@ -1 +1 @@ -@OMNIPERF_GIT_REV@ +@ROCPROFCOMPUTE_GIT_REV@ diff --git a/cmake/omniperf.lua.in b/cmake/rocprofcompute.lua.in similarity index 59% rename from cmake/omniperf.lua.in rename to cmake/rocprofcompute.lua.in index ca55ab6f6..846be16e0 100644 --- a/cmake/omniperf.lua.in +++ b/cmake/rocprofcompute.lua.in @@ -1,18 +1,18 @@ local help_message = [[ -Omniperf is an open-source performance analysis tool for profiling +ROCm Compute Profiler is an open-source performance analysis tool for profiling machine learning/HPC workloads running on AMD MI GPUs. -Version @OMNIPERF_FULL_VERSION@ +Version @ROCPROFCOMPUTE_FULL_VERSION@ ]] help(help_message,"\n") -whatis("Name: omniperf") -whatis("Version: @OMNIPERF_FULL_VERSION@") +whatis("Name: @PROJECT_NAME@") +whatis("Version: @ROCPROFCOMPUTE_FULL_VERSION@") whatis("Keywords: Profiling, Performance, GPU") whatis("Description: tool for GPU performance profiling") -whatis("URL: https://github.com/ROCm/omniperf") +whatis("URL: https://github.com/ROCm/rocprofiler-compute") -- Export environmental variables local topDir="@CMAKE_INSTALL_PREFIX@" @@ -20,9 +20,9 @@ local binDir="@CMAKE_INSTALL_FULL_BINDIR@" local shareDir="@CMAKE_INSTALL_FULL_DATADIR@" local pythonDeps="@PYTHON_DEPS@" -setenv("OMNIPERF_DIR",topDir) -setenv("OMNIPERF_BIN",binDir) -setenv("OMNIPERF_SHARE",shareDir) +setenv("ROCPROFCOMPUTE_DIR",topDir) +setenv("ROCPROFCOMPUTE_BIN",binDir) +setenv("ROCPROFCOMPUTE_SHARE",shareDir) -- Update relevant PATH variables prepend_path("PATH",binDir) diff --git a/docker/build-docker-ci.sh b/docker/build-docker-ci.sh index 8c7029e89..b3dba28a4 100755 --- a/docker/build-docker-ci.sh +++ b/docker/build-docker-ci.sh @@ -137,7 +137,7 @@ do verbose-run docker build . \ ${PULL} \ -f ${DOCKER_FILE} \ - --tag ${USER}/omniperf:ci-base-${DISTRO}-${VERSION} \ + --tag ${USER}/rocprofiler-compute:ci-base-${DISTRO}-${VERSION} \ --build-arg DISTRO=${DISTRO_IMAGE} \ --build-arg VERSION=${VERSION} \ --build-arg PYTHON_VERSIONS=\"${PYTHON_VERSIONS}\" @@ -149,6 +149,6 @@ done if [ "${PUSH}" -gt 0 ]; then for VERSION in ${VERSIONS} do - verbose-run docker push ${USER}/omniperf:ci-base-${DISTRO}-${VERSION} + verbose-run docker push ${USER}/rocprofiler-compute:ci-base-${DISTRO}-${VERSION} done fi \ No newline at end of file diff --git a/docker/build-docker.sh b/docker/build-docker.sh index 5d6f2d181..4da9161fb 100755 --- a/docker/build-docker.sh +++ b/docker/build-docker.sh @@ -159,7 +159,7 @@ do VERSION_PATCH=$(echo ${VERSION} | sed 's/\./ /g' | awk '{print $3}') for ROCM_VERSION in ${ROCM_VERSIONS} do - CONTAINER=${USER}/omniperf:release-base-${DISTRO}-${VERSION}-rocm-${ROCM_VERSION} + CONTAINER=${USER}/rocprofiler-compute:release-base-${DISTRO}-${VERSION}-rocm-${ROCM_VERSION} ROCM_MAJOR=$(echo ${ROCM_VERSION} | sed 's/\./ /g' | awk '{print $1}') ROCM_MINOR=$(echo ${ROCM_VERSION} | sed 's/\./ /g' | awk '{print $2}') ROCM_PATCH=$(echo ${ROCM_VERSION} | sed 's/\./ /g' | awk '{print $3}') diff --git a/docs/archive/docs-1.x/analysis.md b/docs/archive/docs-1.x/analysis.md index 126364dbd..19851c59d 100644 --- a/docs/archive/docs-1.x/analysis.md +++ b/docs/archive/docs-1.x/analysis.md @@ -171,7 +171,7 @@ $ omniperf analyze -p workloads/vcopy/mi200/ --list-metrics gfx90a ├─────────┼─────────────────────────────┤ ... ``` - 2. Choose your own customized subset of metrics with `-b` (a.k.a. `--metric`), or build your own config following [config_template](https://github.com/ROCm/omniperf/blob/amd-mainline/src/omniperf_analyze/configs/panel_config_template.yaml). Below shows how to generate a report containing only metric 2 (a.k.a. System Speed-of-Light). + 2. Choose your own customized subset of metrics with `-b` (a.k.a. `--metric`), or build your own config following [config_template](https://github.com/ROCm/omniperf/blob/amd-mainline/src/rocprof_compute_analyze/configs/panel_config_template.yaml). Below shows how to generate a report containing only metric 2 (a.k.a. System Speed-of-Light). ```shell-session $ omniperf analyze -p workloads/vcopy/mi200/ -b 2 -------- @@ -381,7 +381,7 @@ Analyze Dash is running on http://0.0.0.0:8050/ - * Serving Flask app 'omniperf_analyze.omniperf_analyze' (lazy loading) + * Serving Flask app 'rocprof_compute_analyze.rocprof_compute_analyze' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. @@ -767,4 +767,4 @@ Most panels are designed around a specific IP block to thoroughly understand its ###### L2-EA Write Stalls ![L2-EA Write Stalls](images/L2_ea_write_stalls_per_channel.png) ###### L2-EA Write Starvation -![L2-EA Write Starvation](images/L2_ea_write_starvation_per_channel.png) \ No newline at end of file +![L2-EA Write Starvation](images/L2_ea_write_starvation_per_channel.png) diff --git a/docs/archive/docs-2.x/analysis.md b/docs/archive/docs-2.x/analysis.md index 22fa72e39..a44e4b63f 100644 --- a/docs/archive/docs-2.x/analysis.md +++ b/docs/archive/docs-2.x/analysis.md @@ -181,7 +181,7 @@ Analysis mode = cli 2.1.30 -> L1I Fetch Latency ... ``` -3. Choose your own customized subset of metrics with `-b` (a.k.a. `--block`), or build your own config following [config_template](https://github.com/ROCm/omniperf/blob/amd-mainline/src/omniperf_analyze/configs/panel_config_template.yaml). Below shows how to generate a report containing only metric 2 (a.k.a. System Speed-of-Light). +3. Choose your own customized subset of metrics with `-b` (a.k.a. `--block`), or build your own config following [config_template](https://github.com/ROCm/omniperf/blob/amd-mainline/src/rocprof_compute_analyze/configs/panel_config_template.yaml). Below shows how to generate a report containing only metric 2 (a.k.a. System Speed-of-Light). ```shell-session $ omniperf analyze -p workloads/vcopy/MI200/ -b 2 -------- @@ -407,7 +407,7 @@ Analysis mode = web_ui [analysis] deriving Omniperf metrics... Dash is running on http://0.0.0.0:8050/ - * Serving Flask app 'omniperf_analyze.analysis_webui' (lazy loading) + * Serving Flask app 'rocprof_compute_analyze.analysis_webui' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. diff --git a/docs/conceptual/command-processor.rst b/docs/conceptual/command-processor.rst index a055768a1..567f7ceec 100644 --- a/docs/conceptual/command-processor.rst +++ b/docs/conceptual/command-processor.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf performance model: Command processor (CP) - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, command, processor, fetcher, packet processor, CPF, CPC + :description: ROCm Compute Profiler performance model: Command processor (CP) + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, command, processor, fetcher, packet processor, CPF, CPC ********************** Command processor (CP) diff --git a/docs/conceptual/compute-unit.rst b/docs/conceptual/compute-unit.rst index e7061c814..3b265d26b 100644 --- a/docs/conceptual/compute-unit.rst +++ b/docs/conceptual/compute-unit.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf performance model: Compute unit (CU) - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, GCN, compute, unit, pipeline, workgroup, wavefront, + :description: ROCm Compute Profiler performance model: Compute unit (CU) + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, GCN, compute, unit, pipeline, workgroup, wavefront, CDNA ***************** @@ -19,7 +19,7 @@ CDNA™-based accelerators. All :ref:`wavefronts ` of a The CU consists of several independent execution pipelines and functional units. The :doc:`/conceptual/pipeline-descriptions` section details the various execution pipelines -- VALU, SALU, LDS, scheduler, and so forth. The metrics -presented by Omniperf for these pipelines are described in +presented by ROCm Compute Profiler for these pipelines are described in :doc:`pipeline-metrics`. The :doc:`vL1D ` cache and :doc:`LDS ` are described in their own sections. diff --git a/docs/conceptual/definitions.rst b/docs/conceptual/definitions.rst index 8ad483094..f0d1e9e0e 100644 --- a/docs/conceptual/definitions.rst +++ b/docs/conceptual/definitions.rst @@ -1,13 +1,13 @@ .. meta:: - :description: Omniperf terminology and definitions - :keywords: Omniperf, ROCm, glossary, definitions, terms, profiler, tool, + :description: ROCm Compute Profiler terminology and definitions + :keywords: Omniperf, ROCm Compute Profiler, ROCm, glossary, definitions, terms, profiler, tool, Instinct, accelerator, AMD *********** Definitions *********** -The following table briefly defines some terminology used in Omniperf interfaces +The following table briefly defines some terminology used in ROCm Compute Profiler interfaces and in this documentation. .. include:: ./includes/terms.rst diff --git a/docs/conceptual/includes/normalization-units.rst b/docs/conceptual/includes/normalization-units.rst index 34961f7e0..365c30c0e 100644 --- a/docs/conceptual/includes/normalization-units.rst +++ b/docs/conceptual/includes/normalization-units.rst @@ -34,7 +34,7 @@ include: that is, the total runtime of the kernel in seconds, as measured by the :doc:`command processor `. -By default, Omniperf uses the ``per_wave`` normalization. +By default, ROCm Compute Profiler uses the ``per_wave`` normalization. .. tip:: diff --git a/docs/conceptual/l2-cache.rst b/docs/conceptual/l2-cache.rst index 2c4b44514..6d0f26c09 100644 --- a/docs/conceptual/l2-cache.rst +++ b/docs/conceptual/l2-cache.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf performance model: L2 cache (TCC) - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, L2, cache, infinity fabric, metrics + :description: ROCm Compute Profiler performance model: L2 cache (TCC) + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, L2, cache, infinity fabric, metrics ************** L2 cache (TCC) @@ -21,7 +21,7 @@ across the L2 channels. Requests that miss in the L2 cache are passed out to :ref:`Infinity Fabric™ ` to be routed to the appropriate memory location. -The L2 cache metrics reported by Omniperf are broken down into four +The L2 cache metrics reported by ROCm Compute Profiler are broken down into four categories: * :ref:`L2 Speed-of-Light ` @@ -299,7 +299,7 @@ accelerator’s memory, or even in the CPU’s memory. Infinity Fabric is responsible for routing these memory requests/data to the correct location and returning any fetched data to the L2 cache. The :ref:`l2-request-flow` describes the flow of these requests through -Infinity Fabric in more detail, as described by Omniperf metrics, +Infinity Fabric in more detail, as described by ROCm Compute Profiler metrics, while :ref:`l2-request-metrics` give detailed definitions of individual metrics. @@ -309,7 +309,7 @@ Request flow ------------ The following is a diagram that illustrates how L2↔Fabric requests are reported -by Omniperf: +by ROCm Compute Profiler: .. figure:: ../data/performance-model/fabric.png :align: center diff --git a/docs/conceptual/local-data-share.rst b/docs/conceptual/local-data-share.rst index c596844dc..8035def62 100644 --- a/docs/conceptual/local-data-share.rst +++ b/docs/conceptual/local-data-share.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf performance model: Local data share (LDS) - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, local, data, share, LDS + :description: ROCm Compute Profiler performance model: Local data share (LDS) + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, local, data, share, LDS ********************** Local data share (LDS) diff --git a/docs/conceptual/performance-model.rst b/docs/conceptual/performance-model.rst index 1a94b3ed6..191a3ca3f 100644 --- a/docs/conceptual/performance-model.rst +++ b/docs/conceptual/performance-model.rst @@ -1,13 +1,13 @@ .. meta:: - :description: Omniperf performance model - :keywords: Omniperf, ROCm, performance, model, profiler, tool, Instinct, + :description: ROCm Compute Profiler performance model + :keywords: Omniperf, ROCm Compute Profiler, ROCm, performance, model, profiler, tool, Instinct, accelerator, AMD ***************** Performance model ***************** -Omniperf makes available an extensive list of metrics to better understand +ROCm Compute Profiler makes available an extensive list of metrics to better understand achieved application performance on AMD Instinct™ MI-series accelerators including Graphics Core Next™ (GCN) GPUs like the AMD Instinct MI50, CDNA™ accelerators like the MI100, and CDNA2 accelerators such as the MI250X, MI250, @@ -18,7 +18,7 @@ hardware blocks of AMD Instinct accelerators. This section describes each hardware block on the accelerator as interacted with by a software developer to give a deeper understanding of the metrics reported by profiling data. Refer to :doc:`/tutorial/profiling-by-example` for more practical examples and details on how -to use Omniperf to optimize your code. +to use ROCm Compute Profiler to optimize your code. .. _mixxx-note: @@ -34,7 +34,7 @@ to use Omniperf to optimize your code. :prod-page:`MI250 `, and :prod-page:`MI210 ` product pages. -In this chapter, the AMD Instinct performance model used by Omniperf is divided into a handful of +In this chapter, the AMD Instinct performance model used by ROCm Compute Profiler is divided into a handful of key hardware blocks, each detailed in the following sections: * :doc:`compute-unit` diff --git a/docs/conceptual/pipeline-descriptions.rst b/docs/conceptual/pipeline-descriptions.rst index 9261421eb..c842747aa 100644 --- a/docs/conceptual/pipeline-descriptions.rst +++ b/docs/conceptual/pipeline-descriptions.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf performance model: Shader engine (SE) - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, pipeline, VALU, SALU, VMEM, SMEM, LDS, branch, + :description: ROCm Compute Profiler performance model: Shader engine (SE) + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, pipeline, VALU, SALU, VMEM, SMEM, LDS, branch, scheduler, MFMA, AGPRs ********************* @@ -101,7 +101,7 @@ coordinate between wavefronts in a workgroup. Performance model of the local data share (LDS) on AMD Instinct MI-series accelerators. -Above is Omniperf's performance model of the LDS on CDNA accelerators (adapted +Above is ROCm Compute Profiler's performance model of the LDS on CDNA accelerators (adapted from :mantor-gcn-pdf:`20`). The SIMDs in the :ref:`VALU ` are connected to the LDS in pairs (see above). Only one SIMD per pair may issue an LDS instruction at a time, but both pairs may issue concurrently. @@ -186,7 +186,7 @@ shadow (see the :ref:`MFMA ` section for more detail). .. note:: - The IPC model used by Omniperf omits the following two complications for + The IPC model used by ROCm Compute Profiler omits the following two complications for clarity. First, CDNA accelerators contain other execution units on the CU that are unused for compute applications. Second, so-called "internal" instructions (see :gcn-crash-course:`29`) are not issued to a functional @@ -237,7 +237,7 @@ various AMD accelerators (including the CDNA line), we recommend the GPRs required for D: 4 GPR alignment requirement: 8 bytes -For the purposes of Omniperf, the MFMA unit is typically treated as a separate +For the purposes of ROCm Compute Profiler, the MFMA unit is typically treated as a separate pipeline from the :ref:`VALU `, as other VALU instructions (along with other execution pipelines such as the :ref:`SALU `) typically can be issued during a portion of the total duration of an MFMA operation. diff --git a/docs/conceptual/pipeline-metrics.rst b/docs/conceptual/pipeline-metrics.rst index f7bb4bcda..5caaa3733 100644 --- a/docs/conceptual/pipeline-metrics.rst +++ b/docs/conceptual/pipeline-metrics.rst @@ -1,13 +1,13 @@ .. meta:: - :description: Omniperf performance model: Pipeline metrics - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, pipeline, wavefront, metrics, launch, runtime + :description: ROCm Compute Profiler performance model: Pipeline metrics + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, pipeline, wavefront, metrics, launch, runtime VALU, MFMA, instruction mix, FLOPs, arithmetic, operations **************** Pipeline metrics **************** -In this section, we describe the metrics available in Omniperf to analyze the +In this section, we describe the metrics available in ROCm Compute Profiler to analyze the pipelines discussed in the :doc:`pipeline-descriptions`. .. _wavefront: @@ -233,7 +233,7 @@ Instruction mix The instruction mix panel shows a breakdown of the various types of instructions executed by the user’s kernel, and which pipelines on the -:doc:`CU ` they were executed on. In addition, Omniperf reports +:doc:`CU ` they were executed on. In addition, ROCm Compute Profiler reports further information about the breakdown of operation types for the :ref:`VALU `, vector-memory, and :ref:`MFMA ` instructions. @@ -555,7 +555,7 @@ Compute pipeline FLOP counting conventions ------------------------- -Omniperf’s conventions for VALU FLOP counting are as follows: +ROCm Compute Profiler’s conventions for VALU FLOP counting are as follows: * Addition or multiplication: 1 operation diff --git a/docs/conceptual/references.rst b/docs/conceptual/references.rst index 9f3d32cd8..4ed88dd86 100644 --- a/docs/conceptual/references.rst +++ b/docs/conceptual/references.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf performance model: References - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, HIP, GCN, LLVM, docs, documentation, training + :description: ROCm Compute Profiler performance model: References + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, HIP, GCN, LLVM, docs, documentation, training ********** References diff --git a/docs/conceptual/shader-engine.rst b/docs/conceptual/shader-engine.rst index 8295c4516..75952ad00 100644 --- a/docs/conceptual/shader-engine.rst +++ b/docs/conceptual/shader-engine.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf performance model: Shader engine (SE) - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, shader, engine, sL1D, L1I, workgroup manager, SPI + :description: ROCm Compute Profiler performance model: Shader engine (SE) + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, shader, engine, sL1D, L1I, workgroup manager, SPI ****************** Shader engine (SE) @@ -21,7 +21,7 @@ The number of CUs on a SE varies from chip to chip -- see for example :hip-training-pdf:`20`. In addition, newer accelerators such as the AMD Instinct™ MI 250X have 8 SEs per accelerator. -For the purposes of Omniperf, we consider resources that are shared between +For the purposes of ROCm Compute Profiler, we consider resources that are shared between multiple CUs on a single SE as part of the SE's metrics. These include: @@ -487,7 +487,7 @@ issuing concurrently). .. note:: - Current versions of the profiling libraries underlying Omniperf attempt to + Current versions of the profiling libraries underlying ROCm Compute Profiler attempt to serialize concurrent kernels running on the accelerator, as the performance counters on the device are global (that is, shared between concurrent kernels). This means that these scheduler-pipe utilization metrics are diff --git a/docs/conceptual/system-speed-of-light.rst b/docs/conceptual/system-speed-of-light.rst index f01be4b67..3de2120b3 100644 --- a/docs/conceptual/system-speed-of-light.rst +++ b/docs/conceptual/system-speed-of-light.rst @@ -1,13 +1,13 @@ .. meta:: - :description: Omniperf performance model: System Speed-of-Light - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, system, speed of light + :description: ROCm Compute Profiler performance model: System Speed-of-Light + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, AMD, system, speed of light ********************* System Speed-of-Light ********************* System Speed-of-Light summarizes some of the key metrics from various sections -of Omniperf’s profiling report. +of ROCm Compute Profiler’s profiling report. .. warning:: diff --git a/docs/conceptual/vector-l1-cache.rst b/docs/conceptual/vector-l1-cache.rst index 086c195be..3eb5f9f89 100644 --- a/docs/conceptual/vector-l1-cache.rst +++ b/docs/conceptual/vector-l1-cache.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf performance model: Vector L1 cache (vL1D) - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, vector, l1, cache, vl1d + :description: ROCm Compute Profiler performance model: Vector L1 cache (vL1D) + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, AMD, vector, l1, cache, vl1d ********************** Vector L1 cache (vL1D) @@ -124,7 +124,7 @@ passes information about the commands (coalescing state, destination SIMD, etc.) to the :ref:`data processing unit ` for use after the requested data has been retrieved. -Omniperf reports several metrics to indicate performance bottlenecks in +ROCm Compute Profiler reports several metrics to indicate performance bottlenecks in the address processing unit, which are broken down into a few categories: @@ -378,7 +378,7 @@ Translation Cache (UTCL1). This cache contains a L1 Translation Lookaside Buffer (TLB) which stores recently translated addresses to reduce the cost of subsequent re-translations. -Omniperf reports the following L1 TLB metrics: +ROCm Compute Profiler reports the following L1 TLB metrics: .. list-table:: :header-rows: 1 @@ -656,7 +656,7 @@ latencies of read/write memory operations to the :doc:`L2 cache `. :ref:`Cache access metrics ` section when evaluating the vL1D hit rate. -.. [#vl1d-activity] Omniperf considers the vL1D to be active when any part of +.. [#vl1d-activity] ROCm Compute Profiler considers the vL1D to be active when any part of the vL1D (excluding the :ref:`address processor ` and :ref:`data return ` units) are active, for example, when performing a translation, waiting for data, accessing the Tag or Cache RAMs, etc. @@ -685,7 +685,7 @@ from the :ref:`VALU `. When data is returned from the :ref:`vL1D cache RAM `, it is matched to this previously stored request data, and returned to the appropriate SIMD. -Omniperf reports the following vL1D data-return path metrics: +ROCm Compute Profiler reports the following vL1D data-return path metrics: .. list-table:: :header-rows: 1 diff --git a/docs/conf.py b/docs/conf.py index f74f95ecd..95c0012cd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,7 +35,7 @@ version_number = match[1] # project info -project = "Omniperf" +project = "ROCm Compute Profiler" author = "Advanced Micro Devices, Inc." copyright = "Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved." version = version_number @@ -51,11 +51,14 @@ html_css_files = ["o_custom.css"] external_toc_path = "./sphinx/_toc.yml" -external_projects_current_project = "omniperf" +external_projects_current_project = "rocprofiler-compute" # frequently used external resources extlinks = { - "dev-sample": ("https://github.com/ROCm/omniperf/blob/amd-mainline/sample/%s", "%s"), + "dev-sample": ( + "https://github.com/ROCm/rocprofiler-compute/blob/amd-mainline/sample/%s", + "%s", + ), "prod-page": ( "https://www.amd.com/en/products/accelerators/instinct/%s.html", "%s", diff --git a/docs/data/install/install-decision-tree.png b/docs/data/install/install-decision-tree.png index 1c62fba87bea83808fcc3596b062c77ea720de60..6fe99b01b9b9878d66dbb15541ca675f7951b0d5 100644 GIT binary patch literal 360324 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
  • BkQl|8Od7KR>kMP&0|3EB82&0L?!l`ya3r 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 Zwx&fdNWs#869N1u^;AwQPej-I{{alF*GT{X literal 44865 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 aaeyk9$v;7tYOWC8#tn0uYlN#liT?wp{ZL{6 diff --git a/docs/data/unused/install-decision-tree.png b/docs/data/unused/install-decision-tree.png new file mode 100644 index 0000000000000000000000000000000000000000..1c62fba87bea83808fcc3596b062c77ea720de60 GIT binary patch literal 44865 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 aaeyk9$v;7tYOWC8#tn0uYlN#liT?wp{ZL{6 literal 0 HcmV?d00001 diff --git a/docs/how-to/analyze/cli.rst b/docs/how-to/analyze/cli.rst index 82185cd41..f73333f37 100644 --- a/docs/how-to/analyze/cli.rst +++ b/docs/how-to/analyze/cli.rst @@ -1,14 +1,14 @@ .. meta:: - :description: Omniperf analysis: CLI analysis - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, command line, analyze, filtering, metrics, baseline, comparison + :description: ROCm Compute Profiler analysis: CLI analysis + :keywords: ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, command line, analyze, filtering, metrics, baseline, comparison ************ CLI analysis ************ -This section provides an overview of Omniperf's CLI analysis features. +This section provides an overview of ROCm Compute Profiler's CLI analysis features. -* :ref:`Derived metrics `: All of Omniperf's built-in metrics. +* :ref:`Derived metrics `: All of ROCm Compute Profiler's built-in metrics. * :ref:`Baseline comparison `: Compare multiple runs in a side-by-side manner. @@ -19,28 +19,28 @@ This section provides an overview of Omniperf's CLI analysis features. * :ref:`Filtering `: Hone in on a particular kernel, GPU ID, or dispatch ID via post-process filtering. -Run ``omniperf analyze -h`` for more details. +Run ``rocprof-compute analyze -h`` for more details. .. _cli-walkthrough: Walkthrough =========== -1. To begin, generate a high-level analysis report using Omniperf's ``-b`` (or ``--block``) flag. +1. To begin, generate a high-level analysis report using ROCm Compute Profiler's ``-b`` (or ``--block``) flag. - .. code-block:: shell + .. code-block:: shell-session - $ omniperf analyze -p workloads/vcopy/MI200/ -b 2 + $ rocprof-compute analyze -p workloads/vcopy/MI200/ -b 2 - ___ _ __ - / _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _| - | | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_ - | |_| | | | | | | | | | | |_) | __/ | | _| - \___/|_| |_| |_|_| |_|_| .__/ \___|_| |_| - |_| + __ _ + _ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___ + | '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \ + | | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/ + |_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___| + |_| |_| Analysis mode = cli - [analysis] deriving Omniperf metrics... + [analysis] deriving rocprofiler-compute metrics... -------------------------------------------------------------------------------- 0. Top Stats @@ -134,19 +134,19 @@ Walkthrough 2. Use ``--list-metrics`` to generate a list of available metrics for inspection. - .. code-block:: shell + .. code-block:: shell-session - $ omniperf analyze -p workloads/vcopy/MI200/ --list-metrics gfx90a + $ rocprof-compute analyze -p workloads/vcopy/MI200/ --list-metrics gfx90a - ___ _ __ - / _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _| - | | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_ - | |_| | | | | | | | | | | |_) | __/ | | _| - \___/|_| |_| |_|_| |_|_| .__/ \___|_| |_| - |_| + __ _ + _ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___ + | '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \ + | | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/ + |_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___| + |_| |_| Analysis mode = cli - [analysis] deriving Omniperf metrics... + [analysis] deriving rocprofiler-compute metrics... 0 -> Top Stats 1 -> System Info 2 -> System Speed-of-Light @@ -186,13 +186,13 @@ Walkthrough 3. Choose your own customized subset of metrics with the ``-b`` (or ``--block``) option. Or, build your own configuration following - `config_template `_. + `config_template `_. The following snippet shows how to generate a report containing only metric 2 (:doc:`System Speed-of-Light `). - .. code-block:: shell + .. code-block:: shell-session - $ omniperf analyze -p workloads/vcopy/MI200/ -b 2 + $ rocprof-compute analyze -p workloads/vcopy/MI200/ -b 2 -------- Analyze @@ -280,7 +280,7 @@ Walkthrough 4. Optimize the application, iterate, and re-profile to inspect performance changes. -5. Redo a comprehensive analysis with Omniperf CLI at any optimization +5. Redo a comprehensive analysis with ROCm Compute Profiler CLI at any optimization milestone. .. _cli-analysis-options: @@ -291,22 +291,22 @@ More analysis options Single run .. code-block:: shell - $ omniperf analyze -p workloads/vcopy/MI200/ + $ rocprof-compute analyze -p workloads/vcopy/MI200/ List top kernels and dispatches .. code-block:: shell - $ omniperf analyze -p workloads/vcopy/MI200/ --list-stats + $ rocprof-compute analyze -p workloads/vcopy/MI200/ --list-stats List metrics .. code-block:: shell - $ omniperf analyze -p workloads/vcopy/MI200/ --list-metrics gfx90a + $ rocprof-compute analyze -p workloads/vcopy/MI200/ --list-metrics gfx90a Show System Speed-of-Light and CS_Busy blocks only .. code-block:: shell - $ omniperf analyze -p workloads/vcopy/MI200/ -b 2 5.1.0 + $ rocprof-compute analyze -p workloads/vcopy/MI200/ -b 2 5.1.0 .. note:: @@ -319,10 +319,10 @@ Filter kernels .. code-block:: - $ omniperf analyze -p workloads/vcopy/MI200/ --list-stats + $ rocprof-compute analyze -p workloads/vcopy/MI200/ --list-stats Analysis mode = cli - [analysis] deriving Omniperf metrics... + [analysis] deriving rocprofiler-compute metrics... -------------------------------------------------------------------------------- Detected Kernels (sorted descending by duration) @@ -344,12 +344,12 @@ Filter kernels ``vecCopy(double*, double*, double*, int, int) [clone .kd]`` at index ``0``. Then, use this index to apply the filter via ``-k`` or ``--kernels``. - .. code-block:: shell + .. code-block:: shell-session - $ omniperf analyze -p workloads/vcopy/MI200/ -k 0 + $ rocprof-compute analyze -p workloads/vcopy/MI200/ -k 0 Analysis mode = cli - [analysis] deriving Omniperf metrics... + [analysis] deriving rocprofiler-compute metrics... -------------------------------------------------------------------------------- 0. Top Stats @@ -369,10 +369,10 @@ Filter kernels Baseline comparison .. code-block:: shell - omniperf analyze -p workload1/path/ -p workload2/path/ + rocprof-compute analyze -p workload1/path/ -p workload2/path/ OR .. code-block:: shell - omniperf analyze -p workload1/path/ -k 0 -p workload2/path/ -k 1 + rocprof-compute analyze -p workload1/path/ -k 0 -p workload2/path/ -k 1 diff --git a/docs/how-to/analyze/grafana-gui.rst b/docs/how-to/analyze/grafana-gui.rst index d5474aefb..110347911 100644 --- a/docs/how-to/analyze/grafana-gui.rst +++ b/docs/how-to/analyze/grafana-gui.rst @@ -1,6 +1,7 @@ .. meta:: - :description: Omniperf analysis: Grafana GUI - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, Grafana, panels, GUI, import + :description: ROCm Compute Profiler analysis: Grafana GUI + :keywords: Omniperf, ROCm Compute Profiler, ROCm, profiler, tool, + Instinct, accelerator, Grafana, panels, GUI, import ******************** Grafana GUI analysis @@ -8,7 +9,7 @@ Grafana GUI analysis Find setup instructions in :doc:`../../install/grafana-setup`. -The Omniperf Grafana analysis dashboard GUI supports the following features to +The ROCm Compute Profiler Grafana analysis dashboard GUI supports the following features to facilitate MI accelerator performance profiling and analysis: * System and hardware component (hardware block) @@ -40,7 +41,7 @@ facilitate MI accelerator performance profiling and analysis: * L2 Cache (TCC) (both aggregated and per-channel perf info) -See the full list of :ref:`Omniperf's analysis panels `. +See the full list of :ref:`ROCm Compute Profiler's analysis panels `. .. _analysis-sol: @@ -70,14 +71,14 @@ normalizations are available. * ``per_second`` -See :ref:`normalization-units` to learn more about Omniperf normalizations. +See :ref:`normalization-units` to learn more about ROCm Compute Profiler normalizations. .. _analysis-baseline-comparison: Baseline comparison ------------------- -Omniperf enables baseline comparison to allow checking A/B effect. Currently +ROCm Compute Profiler enables baseline comparison to allow checking A/B effect. Currently baseline comparison is limited to the same :ref:`SoC `. Cross comparison between SoCs is in development. @@ -92,14 +93,14 @@ setup the following filters to allow fine grained comparisons: * Dispatch ID filtering (regex filtering) -* Omniperf Panels (multi-selection) +* ROCm Compute Profiler Panels (multi-selection) .. _analysis-regex-dispatch-id: Regex-based dispatch ID filtering --------------------------------- -Omniperf allows filtering via Regular Expressions (regex), a standard Linux +ROCm Compute Profiler allows filtering via Regular Expressions (regex), a standard Linux string matching syntax, based dispatch ID filtering to flexibly choose the kernel invocations. @@ -116,7 +117,7 @@ corresponding regex is : ``(1[7-9]|[23]\d|4[0-8])``. Incremental profiling --------------------- -Omniperf supports incremental profiling to speed up performance analysis. +ROCm Compute Profiler supports incremental profiling to speed up performance analysis. Refer to the :ref:`profiling-hw-component-filtering` section for this command. @@ -145,7 +146,7 @@ Global variables and configurations .. image:: ../../data/analyze/global_variables.png :align: center - :alt: Omniperf global variables and configurations + :alt: ROCm Compute Profiler global variables and configurations :width: 800 .. _grafana-gui-import: @@ -153,7 +154,7 @@ Global variables and configurations Grafana GUI import ------------------ -The Omniperf database ``--import`` option imports the raw profiling data to +The ROCm Compute Profiler database ``--import`` option imports the raw profiling data to Grafana's backend MongoDB database. This step is only required for Grafana GUI-based performance analysis. @@ -169,13 +170,13 @@ convention: .. code-block:: shell - omniperf___ + rocprofiler-compute___ For example: .. code-block:: shell - omniperf_asw_vcopy_mi200 + rocprofiler-compute_asw_vcopy_mi200 When using :ref:`database mode `, be sure to tailor the connection options to the machine hosting your @@ -187,10 +188,10 @@ called ``dummybox``. .. code-block:: shell-session - $ omniperf database --help + $ rocprof-compute database --help usage: - omniperf database [connection options] + rocprof-compute database [connection options] @@ -198,9 +199,9 @@ called ``dummybox``. Examples: - omniperf database --import -H pavii1 -u temp -t asw -w workloads/vcopy/mi200/ + rocprof-compute database --import -H pavii1 -u temp -t asw -w workloads/vcopy/mi200/ - omniperf database --remove -H pavii1 -u temp -w omniperf_asw_sample_mi200 + rocprof-compute database --remove -H pavii1 -u temp -w rocprofiler-compute_asw_sample_mi200 ------------------------------------------------------------------------------- @@ -215,8 +216,8 @@ called ``dummybox``. -s, --specs Print system specs. Interaction Type: - -i, --import Import workload to Omniperf DB - -r, --remove Remove a workload from Omniperf DB + -i, --import Import workload to ROCm Compute Profiler DB + -r, --remove Remove a workload from ROCm Compute Profiler DB Connection Options: -H , --host Name or IP address of the server host. @@ -228,22 +229,22 @@ called ``dummybox``. --kernel-verbose Specify Kernel Name verbose level 1-5. Lower the level, shorter the kernel name. (DEFAULT: 5) (DISABLE: 5) -Omniperf import for vcopy: -^^^^^^^^^^^^^^^^^^^^^^^^^^ +ROCm Compute Profiler import for vcopy: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. code-block:: shell +.. code-block:: shell-session - $ omniperf database --import -H dummybox -u temp -t asw -w workloads/vcopy/mi200/ + $ rocprof-compute database --import -H dummybox -u temp -t asw -w workloads/vcopy/mi200/ - ___ _ __ - / _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _| - | | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_ - | |_| | | | | | | | | | | |_) | __/ | | _| - \___/|_| |_| |_|_| |_|_| .__/ \___|_| |_| - |_| + __ _ + _ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___ + | '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \ + | | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/ + |_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___| + |_| |_| - Pulling data from /home/auser/repos/omniperf/sample/workloads/vcopy/MI200 + Pulling data from /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200 The directory exists Found sysinfo file KernelName shortening enabled @@ -251,15 +252,15 @@ Omniperf import for vcopy: Password: Password received -- Conversion & Upload in Progress -- - 0%| | 0/11 [00:00 @@ -871,7 +872,7 @@ Texture Addresser .. figure:: ../../data/analyze/grafana/ta_panel.png :align: center - :alt: Texture Addresser in Omniperf Grafana + :alt: Texture Addresser in ROCm Compute Profiler Grafana :width: 800 Metric specific to texture addresser (TA) which receives commands (e.g., @@ -889,7 +890,7 @@ Texture Data .. figure:: ../../data/analyze/grafana/td_panel.png :align: center - :alt: Texture Data panel in Omniperf Grafana + :alt: Texture Data panel in ROCm Compute Profiler Grafana :width: 800 Metrics specific to texture data (TD) which routes data back to the @@ -909,7 +910,7 @@ Speed-of-Light .. figure:: ../../data/analyze/grafana/vl1d-sol_panel.png :align: center - :alt: Speed-of-Light (VL1D) panel in Omniperf Grafana + :alt: Speed-of-Light (VL1D) panel in ROCm Compute Profiler Grafana :width: 800 Key metrics of the vector L1 data (vL1D) cache as a comparison with the peak @@ -924,7 +925,7 @@ L1D Cache Stalls .. figure:: ../../data/analyze/grafana/vl1d-cache-stalls_panel.png :align: center - :alt: L1D Cache Stalls panel in Omniperf Grafana + :alt: L1D Cache Stalls panel in ROCm Compute Profiler Grafana :width: 800 More detail on where vector L1 data (vL1D) cache is stalled in the pipeline, @@ -955,7 +956,7 @@ L1D - L2 Transactions .. figure:: ../../data/analyze/grafana/vl1d-l2-transactions_panel.png :align: center - :alt: L1D - L2 Transactions in Omniperf Grafana + :alt: L1D - L2 Transactions in ROCm Compute Profiler Grafana :width: 800 A more granular look at the types of requests made to the L2 cache. @@ -969,7 +970,7 @@ L1D Addr Translation .. figure:: ../../data/analyze/grafana/vl1d-addr-translation_panel.png :align: center - :alt: L1D Addr Translation panel in Omniperf Grafana + :alt: L1D Addr Translation panel in ROCm Compute Profiler Grafana :width: 800 After a vector memory instruction has been processed/coalesced by the address @@ -995,7 +996,7 @@ Speed-of-Light .. figure:: ../../data/analyze/grafana/l2-sol_panel.png :align: center - :alt: Speed-of-Light (L2 cache) panel in Omniperf Grafana + :alt: Speed-of-Light (L2 cache) panel in ROCm Compute Profiler Grafana :width: 800 Key metrics about the performance of the L2 cache, aggregated over all the @@ -1011,7 +1012,7 @@ L2 Cache Accesses .. figure:: ../../data/analyze/grafana/l2-accesses_panel.png :align: center - :alt: L2 Cache Accesses panel in Omniperf Grafana + :alt: L2 Cache Accesses panel in ROCm Compute Profiler Grafana :width: 800 Incoming requests to the L2 cache from the vector L1 data (vL1D) cache and @@ -1026,7 +1027,7 @@ L2 - Fabric Transactions .. figure:: ../../data/analyze/grafana/l2-fabric-transactions_panel.png :align: center - :alt: L2 - Fabric Transactions panel in Omniperf Grafana + :alt: L2 - Fabric Transactions panel in ROCm Compute Profiler Grafana :width: 800 More detail on the flow of requests through Infinity Fabric™. @@ -1040,7 +1041,7 @@ L2 - Fabric Interface Stalls .. figure:: ../../data/analyze/grafana/l2-fabric-interface-stalls_panel.png :align: center - :alt: L2 - Fabric Interface Stalls panel in Omniperf Grafana + :alt: L2 - Fabric Interface Stalls panel in ROCm Compute Profiler Grafana :width: 800 A breakdown of what types of requests in a kernel caused a stall @@ -1065,7 +1066,7 @@ Aggregate Stats .. figure:: ../../data/analyze/grafana/l2-per-channel-agg-stats_panel.png :align: center - :alt: Aggregate Stats (L2 cache per channel) panel in Omniperf Grafana + :alt: Aggregate Stats (L2 cache per channel) panel in ROCm Compute Profiler Grafana :width: 800 L2 Cache per channel performance at a glance. Metrics are aggregated over all available channels. diff --git a/docs/how-to/analyze/mode.rst b/docs/how-to/analyze/mode.rst index b34e1214c..d9f802cdb 100644 --- a/docs/how-to/analyze/mode.rst +++ b/docs/how-to/analyze/mode.rst @@ -1,22 +1,22 @@ .. meta:: - :description: How to use Omniperf's analyze mode - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, + :description: How to use ROCm Compute Profiler's analyze mode + :keywords: ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, AMD, Grafana, analysis, analyze mode ************ Analyze mode ************ -Omniperf offers several ways to interact with the metrics it generates from +ROCm Compute Profiler offers several ways to interact with the metrics it generates from profiling. Your level of familiarity with the profiled application, computing -environment, and experience with Omniperf should inform the analysis method you +environment, and experience with ROCm Compute Profiler should inform the analysis method you choose. -While analyzing with the CLI offers quick and straightforward access to Omniperf +While analyzing with the CLI offers quick and straightforward access to ROCm Compute Profiler metrics from the terminal, Grafana's dashboard GUI adds an extra layer of readability and interactivity you might prefer. -See the following sections to explore Omniperf's analysis and visualization +See the following sections to explore ROCm Compute Profiler's analysis and visualization options. * :doc:`cli` @@ -32,5 +32,5 @@ options. Unless otherwise noted, the performance analysis is done on the :ref:`MI200 platform `. -Learn about profiling with Omniperf in :doc:`../profile/mode`. For an overview of -Omniperf's other modes, see :ref:`modes`. +Learn about profiling with ROCm Compute Profiler in :doc:`../profile/mode`. For an overview of +ROCm Compute Profiler's other modes, see :ref:`modes`. diff --git a/docs/how-to/analyze/standalone-gui.rst b/docs/how-to/analyze/standalone-gui.rst index a6a3e26f3..f138c1124 100644 --- a/docs/how-to/analyze/standalone-gui.rst +++ b/docs/how-to/analyze/standalone-gui.rst @@ -1,15 +1,15 @@ .. meta:: - :description: Omniperf analysis: Standalone GUI + :description: ROCm Compute Profiler analysis: Standalone GUI :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, GUI, standalone, filter *********************** Standalone GUI analysis *********************** -Omniperf's standalone analysis GUI is a lightweight web page that you can +ROCm Compute Profiler's standalone analysis GUI is a lightweight web page that you can generate straight from the command line. The standalone analysis GUI is an alternative to the CLI if you want to explore profiling results visually, but -without the additional setup requirements or server-side overhead of Omniperf's +without the additional setup requirements or server-side overhead of ROCm Compute Profiler's detailed :doc:`Grafana interface ` option. This analysis option is implemented as a simple `Flask `_ application that lets you view results from your preferred web browser. @@ -29,25 +29,25 @@ application that lets you view results from your preferred web browser. Launch the standalone GUI analyzer ---------------------------------- -To launch the Omniperf GUI analyzer, include the ``--gui`` flag with your +To launch the ROCm Compute Profiler GUI analyzer, include the ``--gui`` flag with your desired analysis command. For example: -.. code-block:: shell +.. code-block:: shell-session - $ omniperf analyze -p workloads/vcopy/MI200/ --gui + $ rocprof-compute analyze -p workloads/vcopy/MI200/ --gui - ___ _ __ - / _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _| - | | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_ - | |_| | | | | | | | | | | |_) | __/ | | _| - \___/|_| |_| |_|_| |_|_| .__/ \___|_| |_| - |_| + __ _ + _ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___ + | '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \ + | | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/ + |_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___| + |_| |_| Analysis mode = web_ui - [analysis] deriving Omniperf metrics... + [analysis] deriving rocprofiler-compute metrics... Dash is running on http://0.0.0.0:8050/ - * Serving Flask app 'omniperf_analyze.analysis_webui' (lazy loading) + * Serving Flask app 'rocprof_compute_analyze.analysis_webui' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. @@ -62,7 +62,7 @@ At this point, you can launch your web browser of choice and navigate to .. image:: ../../data/analyze/standalone_gui.png :align: center - :alt: Omniperf standalone GUI home screen + :alt: ROCm Compute Profiler standalone GUI home screen :width: 800 .. tip:: @@ -85,5 +85,5 @@ metrics specific to your selected filters. Once a filter is applied, you'll see several additional sections become available with detailed metrics specific to that area of AMD hardware. These -detailed sections mirror the data displayed in Omniperf's +detailed sections mirror the data displayed in ROCm Compute Profiler's :doc:`Grafana interface `. diff --git a/docs/how-to/profile/mode.rst b/docs/how-to/profile/mode.rst index 5bc0ad6a7..1a5472399 100644 --- a/docs/how-to/profile/mode.rst +++ b/docs/how-to/profile/mode.rst @@ -1,27 +1,27 @@ .. meta:: - :description: How to use Omniperf's profile mode - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, + :description: How to use ROCm Compute Profiler's profile mode + :keywords: ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, AMD, profiling, profile mode ************ Profile mode ************ -The following chapter walks you through Omniperf's core profiling features by +The following chapter walks you through ROCm Compute Profiler's core profiling features by example. -Learn about analysis with Omniperf in :doc:`../analyze/mode`. For an overview of -Omniperf's other modes, see :ref:`modes`. +Learn about analysis with ROCm Compute Profiler in :doc:`../analyze/mode`. For an overview of +ROCm Compute Profiler's other modes, see :ref:`modes`. Profiling ========= -Use the ``omniperf`` executable to acquire all necessary performance monitoring +Use the ``rocprof-compute`` executable to acquire all necessary performance monitoring data through analysis of compute workloads. -Profiling with Omniperf yields the following benefits. +Profiling with ROCm Compute Profiler yields the following benefits. -* :ref:`Automate counter collection `: Omniperf handles all +* :ref:`Automate counter collection `: ROCm Compute Profiler handles all of your profiling via pre-configured input files. * :ref:`Filtering `: Apply runtime filters to speed up the profiling @@ -30,7 +30,7 @@ Profiling with Omniperf yields the following benefits. * :ref:`Standalone roofline `: Isolate a subset of built-in metrics or build your own profiling configuration. -Run ``omniperf profile -h`` for more details. See +Run ``rocprof-compute profile -h`` for more details. See :ref:`Basic usage `. .. _profile-example: @@ -38,14 +38,14 @@ Run ``omniperf profile -h`` for more details. See Profiling example ----------------- -The ``__ repository +The ``__ repository includes source code for a sample GPU compute workload, ``vcopy.cpp``. A copy of this file is available in the ``share/sample`` subdirectory after a normal -Omniperf installation, or via the ``$OMNIPERF_SHARE/sample`` directory when +ROCm Compute Profiler installation, or via the ``$ROCPROFCOMPUTE_SHARE/sample`` directory when using the supplied modulefile. The examples in this section use a compiled version of the ``vcopy`` workload to -demonstrate the use of Omniperf in MI accelerator performance analysis. Unless +demonstrate the use of ROCm Compute Profiler in MI accelerator performance analysis. Unless otherwise noted, the performance analysis is done on the :ref:`MI200 platform `. @@ -54,7 +54,7 @@ Workload compilation The following example demonstrates compilation of ``vcopy``. -.. code-block:: shell +.. code-block:: shell-session $ hipcc vcopy.cpp -o vcopy $ ls @@ -74,20 +74,20 @@ The following example demonstrates compilation of ``vcopy``. The following sample command profiles the ``vcopy`` workload. -.. code-block:: shell +.. code-block:: shell-session - $ omniperf profile --name vcopy -- ./vcopy -n 1048576 -b 256 + $ rocprof-compute profile --name vcopy -- ./vcopy -n 1048576 -b 256 - ___ _ __ - / _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _| - | | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_ - | |_| | | | | | | | | | | |_) | __/ | | _| - \___/|_| |_| |_|_| |_|_| .__/ \___|_| |_| - |_| + __ _ + _ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___ + | '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \ + | | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/ + |_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___| + |_| |_| - Omniperf version: 2.0.0 + rocprofiler-compute version: 2.0.0 Profiler choice: rocprofv1 - Path: /home/auser/repos/omniperf/sample/workloads/vcopy/MI200 + Path: /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200 Target: MI200 Command: ./vcopy -n 1048576 -b 256 Kernel Selection: None @@ -98,10 +98,10 @@ The following sample command profiles the ``vcopy`` workload. Collecting Performance Counters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - [profiling] Current input file: /home/auser/repos/omniperf/sample/workloads/vcopy/MI200/perfmon/SQ_IFETCH_LEVEL.txt - |-> [rocprof] RPL: on '240312_174329' from '/opt/rocm-5.2.1' in '/home/auser/repos/omniperf/src/omniperf' + [profiling] Current input file: /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200/perfmon/SQ_IFETCH_LEVEL.txt + |-> [rocprof] RPL: on '240312_174329' from '/opt/rocm-5.2.1' in '/home/auser/repos/rocprofiler-compute/src/rocprof-compute' |-> [rocprof] RPL: profiling '""./vcopy -n 1048576 -b 256""' - |-> [rocprof] RPL: input file '/home/auser/repos/omniperf/sample/workloads/vcopy/MI200/perfmon/SQ_IFETCH_LEVEL.txt' + |-> [rocprof] RPL: input file '/home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200/perfmon/SQ_IFETCH_LEVEL.txt' |-> [rocprof] RPL: output dir '/tmp/rpl_data_240312_174329_692890' |-> [rocprof] RPL: result dir '/tmp/rpl_data_240312_174329_692890/input0_results_240312_174329' |-> [rocprof] ROCProfiler: input from "/tmp/rpl_data_240312_174329_692890/input0.xml" @@ -123,13 +123,13 @@ The following sample command profiles the ``vcopy`` workload. |-> [rocprof] Releasing CPU memory |-> [rocprof] |-> [rocprof] ROCPRofiler: 1 contexts collected, output directory /tmp/rpl_data_240312_174329_692890/input0_results_240312_174329 - |-> [rocprof] File '/home/auser/repos/omniperf/sample/workloads/vcopy/MI200/SQ_IFETCH_LEVEL.csv' is generating + |-> [rocprof] File '/home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200/SQ_IFETCH_LEVEL.csv' is generating |-> [rocprof] - [profiling] Current input file: /home/auser/repos/omniperf/sample/workloads/vcopy/MI200/perfmon/SQ_INST_LEVEL_LDS.txt + [profiling] Current input file: /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200/perfmon/SQ_INST_LEVEL_LDS.txt ... - [roofline] Checking for roofline.csv in /home/auser/repos/omniperf/sample/workloads/vcopy/MI200 + [roofline] Checking for roofline.csv in /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200 [roofline] No roofline data found. Generating... Empirical Roofline Calculation Copyright © 2022 Advanced Micro Devices, Inc. All rights reserved. @@ -171,9 +171,9 @@ The following sample command profiles the ``vcopy`` workload. .. _profiling-routine: -Notice the two main stages in Omniperf's *default* profiling routine. +Notice the two main stages in ROCm Compute Profiler's *default* profiling routine. -1. The first stage collects all the counters needed for Omniperf analysis +1. The first stage collects all the counters needed for ROCm Compute Profiler analysis (omitting any filters you have provided). 2. The second stage collects data for the roofline analysis (this stage can be @@ -187,7 +187,7 @@ example: * "MI200" for the AMD Instinct MI200 family of accelerators * "MI100" for the AMD Instinct MI100 family of accelerators -The SoC names are generated as a part of Omniperf, and do not *always* +The SoC names are generated as a part of ROCm Compute Profiler, and do not *always* distinguish between different accelerators in the same family; for instance, an Instinct MI210 vs an Instinct MI250. @@ -198,7 +198,7 @@ an Instinct MI210 vs an Instinct MI250. profiling output is stored in ``log.txt``. Roofline-specific benchmark results are stored in ``roofline.csv``. -.. code-block:: shell +.. code-block:: shell-session $ ls workloads/vcopy/MI200/ total 112 @@ -222,8 +222,8 @@ Filtering To reduce profiling time and the counters collected, you should use profiling filters. Profiling filters and their functionality depend on the underlying -profiler being used. While Omniperf is profiler-agnostic, this following is a -detailed description of profiling filters available when using Omniperf with +profiler being used. While ROCm Compute Profiler is profiler-agnostic, this following is a +detailed description of profiling filters available when using ROCm Compute Profiler with :doc:`ROCProfiler `. Filtering options @@ -255,7 +255,7 @@ Hardware component filtering ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can profile specific hardware components to speed up the profiling process. -In Omniperf, the term hardware block to refers to a hardware component or a +In ROCm Compute Profiler, the term hardware block to refers to a hardware component or a group of hardware components. All profiling results are accumulated in the same target directory without overwriting those for other hardware components. This enables incremental profiling and analysis. @@ -263,16 +263,16 @@ enables incremental profiling and analysis. The following example only gathers hardware counters for the shader sequencer (SQ) and L2 cache (TCC) components, skipping all other hardware components. -.. code-block:: shell +.. code-block:: shell-session - $ omniperf profile --name vcopy -b SQ TCC -- ./vcopy -n 1048576 -b 256 + $ rocprof-compute profile --name vcopy -b SQ TCC -- ./vcopy -n 1048576 -b 256 - ___ _ __ - / _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _| - | | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_ - | |_| | | | | | | | | | | |_) | __/ | | _| - \___/|_| |_| |_|_| |_|_| .__/ \___|_| |_| - |_| + __ _ + _ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___ + | '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \ + | | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/ + |_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___| + |_| |_| fname: pmc_cpc_perf: Skipped fname: pmc_spi_perf: Skipped @@ -289,9 +289,9 @@ The following example only gathers hardware counters for the shader sequencer fname: pmc_sqc_perf1: Skipped fname: pmc_sq_perf6: Added fname: pmc_sq_perf2: Added - Omniperf version: 2.0.0 + rocprofiler-compute version: 2.0.0 Profiler choice: rocprofv1 - Path: /home/auser/repos/omniperf/sample/workloads/vcopy/MI200 + Path: /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200 Target: MI200 Command: ./vcopy -n 1048576 -b 256 Kernel Selection: None @@ -314,20 +314,20 @@ kernel name substring list to isolate desired kernels. The following example demonstrates profiling isolating the kernel matching substring ``vecCopy``. -.. code-block:: shell +.. code-block:: shell-session - $ omniperf profile --name vcopy -k vecCopy -- ./vcopy -n 1048576 -b 256 + $ rocprof-compute profile --name vcopy -k vecCopy -- ./vcopy -n 1048576 -b 256 - ___ _ __ - / _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _| - | | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_ - | |_| | | | | | | | | | | |_) | __/ | | _| - \___/|_| |_| |_|_| |_|_| .__/ \___|_| |_| - |_| + __ _ + _ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___ + | '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \ + | | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/ + |_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___| + |_| |_| - Omniperf version: 2.0.0 + rocprofiler-compute version: 2.0.0 Profiler choice: rocprofv1 - Path: /home/auser/repos/omniperf/sample/workloads/vcopy/MI200 + Path: /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200 Target: MI200 Command: ./vcopy -n 1048576 -b 256 Kernel Selection: ['vecCopy'] @@ -349,20 +349,20 @@ Dispatch filtering is based on the *global* dispatch index of kernels in a run. The following example profiles only the first kernel dispatch in the execution of the application (note zero-based indexing). -.. code-block:: shell +.. code-block:: shell-session - $ omniperf profile --name vcopy -d 0 -- ./vcopy -n 1048576 -b 256 + $ rocprof-compute profile --name vcopy -d 0 -- ./vcopy -n 1048576 -b 256 - ___ _ __ - / _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _| - | | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_ - | |_| | | | | | | | | | | |_) | __/ | | _| - \___/|_| |_| |_|_| |_|_| .__/ \___|_| |_| - |_| + __ _ + _ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___ + | '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \ + | | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/ + |_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___| + |_| |_| - Omniperf version: 2.0.0 + rocprofiler-compute version: 2.0.0 Profiler choice: rocprofv1 - Path: /home/auser/repos/omniperf/sample/workloads/vcopy/MI200 + Path: /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200 Target: MI200 Command: ./vcopy -n 1048576 -b 256 Kernel Selection: None @@ -408,14 +408,14 @@ Roofline only The following example demonstrates profiling roofline data only: -.. code-block:: shell +.. code-block:: shell-session - $ omniperf profile --name vcopy --roof-only -- ./vcopy -n 1048576 -b 256 + $ rocprof-compute profile --name vcopy --roof-only -- ./vcopy -n 1048576 -b 256 ... - [roofline] Checking for roofline.csv in /home/auser/repos/omniperf/sample/workloads/vcopy/MI200 + [roofline] Checking for roofline.csv in /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200 [roofline] No roofline data found. Generating... - Checking for roofline.csv in /home/auser/repos/omniperf/sample/workloads/vcopy/MI200 + Checking for roofline.csv in /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200 Empirical Roofline Calculation Copyright © 2022 Advanced Micro Devices, Inc. All rights reserved. Total detected GPU devices: 4 @@ -427,7 +427,7 @@ The following example demonstrates profiling roofline data only: An inspection of our workload output folder shows ``.pdf`` plots were generated successfully. -.. code-block:: shell +.. code-block:: shell-session $ ls workloads/vcopy/MI200/ total 48 @@ -441,7 +441,7 @@ successfully. .. note:: - Omniperf generates two roofline outputs to organize results and reduce + ROCm Compute Profiler generates two roofline outputs to organize results and reduce clutter. One chart plots FP32/FP64 performance while the other plots I8/FP16 performance. @@ -450,6 +450,6 @@ plot. .. image:: ../../data/profile/sample-roof-plot.png :align: center - :alt: Sample Omniperf roofline output + :alt: Sample ROCm Compute Profiler roofline output :width: 800 diff --git a/docs/how-to/use.rst b/docs/how-to/use.rst index 7377dd9f9..c3ecc9417 100644 --- a/docs/how-to/use.rst +++ b/docs/how-to/use.rst @@ -1,13 +1,13 @@ .. meta:: - :description: Omniperf basic usage - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, + :description: ROCm Compute Profiler basic usage + :keywords: ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, AMD, basics, usage, operations *********** Basic usage *********** -The following section outlines basic Omniperf workflows, modes, options, and +The following section outlines basic ROCm Compute Profiler workflows, modes, options, and operations. Command line profiler @@ -18,7 +18,7 @@ Launch and profile the target application using the command line profiler. The command line profiler launches the target application, calls the ROCProfiler API via the ``rocprof`` binary, and collects profile results for the specified kernels, dispatches, and hardware components. If not -specified, Omniperf defaults to collecting all available counters for all +specified, ROCm Compute Profiler defaults to collecting all available counters for all kernels and dispatches launched by the your executable. To collect the default set of data for all kernels in the target @@ -26,7 +26,7 @@ application, launch, for example: .. code-block:: shell - $ omniperf profile -n vcopy_data -- ./vcopy -n 1048576 -b 256 + $ rocprof-compute profile -n vcopy_data -- ./vcopy -n 1048576 -b 256 This runs the app, launches each kernel, and generates profiling results. By default, results are written to a subdirectory with your accelerator's name; @@ -35,7 +35,7 @@ via the ``-n`` argument. .. note:: - To collect all requested profile information, Omniperf might replay kernels + To collect all requested profile information, ROCm Compute Profiler might replay kernels multiple times. .. _basic-filter-data-collection: @@ -67,7 +67,7 @@ argument: .. code-block:: shell - $ omniperf analyze --list-metrics + $ rocprof-compute analyze --list-metrics .. _basic-analyze-cli: @@ -87,7 +87,7 @@ To interact with profiling results from a different session, provide the workload path. ``-p``, ``--path`` - Enables you to analyze existing profiling data in the Omniperf CLI. + Enables you to analyze existing profiling data in the ROCm Compute Profiler CLI. See :doc:`analyze/cli` for more detailed information. @@ -97,16 +97,16 @@ Analyze in the Grafana GUI -------------------------- To conduct a more in-depth analysis of profiling results, it's suggested to use -a Grafana GUI with Omniperf. To interact with profiling results, import your -data to the MongoDB instance included in the Omniperf Dockerfile. See +a Grafana GUI with ROCm Compute Profiler. To interact with profiling results, import your +data to the MongoDB instance included in the ROCm Compute Profiler Dockerfile. See :doc:`/install/grafana-setup`. -To interact with Grafana data, stored in the Omniperf database, enter +To interact with Grafana data, stored in the ROCm Compute Profiler database, enter ``database`` :ref:`mode `; for example: .. code-block:: shell - $ omniperf database --import [CONNECTION OPTIONS] + $ rocprof-compute database --import [CONNECTION OPTIONS] See :doc:`/how-to/analyze/grafana-gui` for more detailed information. @@ -115,7 +115,7 @@ See :doc:`/how-to/analyze/grafana-gui` for more detailed information. Modes ===== -Modes change the fundamental behavior of the Omniperf command line tool. +Modes change the fundamental behavior of the ROCm Compute Profiler command line tool. Depending on which mode you choose, different command line options become available. @@ -133,10 +133,10 @@ Profile mode .. code-block:: shell - $ omniperf profile --help + $ rocprof-compute profile --help See :doc:`profile/mode` to learn about this mode in depth and to get started -profiling with Omniperf. +profiling with ROCm Compute Profiler. .. _modes-analyze: @@ -144,24 +144,24 @@ Analyze mode ------------ ``analyze`` - Loads profiling data from the ``--path`` (``-p``) directory into the Omniperf + Loads profiling data from the ``--path`` (``-p``) directory into the ROCm Compute Profiler CLI analyzer where you have immediate access to profiling results and generated metrics. It generates metrics from the entirety of your profiled - application or a subset identified through the Omniperf CLI analysis filters. + application or a subset identified through the ROCm Compute Profiler CLI analysis filters. To generate a lightweight GUI interface, you can add the ``--gui`` flag to your analysis command. - This mode is a middle ground to the highly detailed Omniperf Grafana GUI and + This mode is a middle ground to the highly detailed ROCm Compute Profiler Grafana GUI and is great if you want immediate access to a hardware component you’re already familiar with. .. code-block:: shell - $ omniperf analyze --help + $ rocprof-compute analyze --help See :doc:`analyze/mode` to learn about this mode in depth and to get started -with analysis using Omniperf. +with analysis using ROCm Compute Profiler. .. _modes-database: @@ -178,7 +178,7 @@ Database mode .. code-block:: shell - $ omniperf database --help + $ rocprof-compute database --help See :doc:`/install/grafana-setup` to learn about setting up a Grafana server and database instance to make your profiling data more digestible and shareable. @@ -188,11 +188,11 @@ database instance to make your profiling data more digestible and shareable. Global options ============== -The Omniperf command line tool has a set of *global* utility options that are +The ROCm Compute Profiler command line tool has a set of *global* utility options that are available across all modes. ``-v``, ``--version`` - Prints the Omniperf version and exits. + Prints the ROCm Compute Profiler version and exits. ``-V``, ``--verbose`` Increases output verbosity. Use multiple times for higher levels of @@ -206,7 +206,7 @@ available across all modes. .. note:: - Omniperf also recognizes the project variable, ``OMNIPERF_COLOR`` should you + ROCm Compute Profiler also recognizes the project variable, ``ROCPROFCOMPUTE_COLOR`` should you choose to disable colorful output. To disable default colorful behavior, set this variable to ``0``. @@ -215,7 +215,7 @@ available across all modes. Basic operations ================ -The following table lists Omniperf's basic operations, their +The following table lists ROCm Compute Profiler's basic operations, their :ref:`modes `, and required arguments. .. list-table:: diff --git a/docs/index.rst b/docs/index.rst index 1df329e7d..80cd512bb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,34 +1,34 @@ .. meta:: - :description: Omniperf documentation and reference + :description: ROCm Compute Profiler documentation and reference :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD -********************** -Omniperf documentation -********************** +*********************************** +ROCm Compute Profiler documentation +*********************************** -Omniperf documentation provides a comprehensive overview of Omniperf. -In addition to a full deployment guide with installation instructions, this -documentation also explains the ideas motivating the design behind the tool and -its components. +This documentation provides a comprehensive overview of the ROCm Compute +Profiler tool. In addition to a full deployment guide with installation +instructions, this documentation also explains the ideas motivating the design +behind the tool and its components. -If you're new to Omniperf, familiarize yourself with the tool by reviewing the +If you're new to ROCm Compute Profiler, familiarize yourself with the tool by reviewing the chapters that follow and gradually learn its more advanced features. To get -started, see :doc:`What is Omniperf? `. +started, see :doc:`What is ROCm Compute Profiler? `. -Omniperf is open source and hosted at ``__. +ROCm Compute Profiler is open source and hosted at ``__. .. grid:: 2 :gutter: 3 .. grid-item-card:: Install - * :doc:`install/core-install` - * :doc:`Grafana server for Omniperf ` + * :doc:`Installation and deployment ` + * :doc:`Grafana server for ROCm Compute Profiler ` .. grid-item:: -Use the following topics to learn more about the advantages of Omniperf in your -development toolkit, how it aims to model performance, and how to use Omniperf +Use the following topics to learn more about the advantages of ROCm Compute Profiler in your +development toolkit, how it aims to model performance, and how to use ROCm Compute Profiler in practice. .. grid:: 2 diff --git a/docs/install/core-install.rst b/docs/install/core-install.rst index f33b97622..12985b4e9 100644 --- a/docs/install/core-install.rst +++ b/docs/install/core-install.rst @@ -1,15 +1,15 @@ .. meta:: - :description: Omniperf installation and deployment - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, + :description: ROCm Compute Profiler installation and deployment + :keywords: Omniperf, ROCm Compute Profiler, ROCm, tool, Instinct, accelerator, AMD, install, deploy, Grafana, client, configuration, modulefiles -********************************* -Installing and deploying Omniperf -********************************* +********************************************** +Installing and deploying ROCm Compute Profiler +********************************************** -Omniperf consists of two installation components. +ROCm Compute Profiler consists of two installation components. -* :ref:`Omniperf core installation ` (client-side) +* :ref:`ROCm Compute Profiler core installation ` (client-side) * Provides the core application profiling capability. * Allows the collection of performance counters, filtering by hardware @@ -17,27 +17,27 @@ Omniperf consists of two installation components. * Provides a CLI-based analysis mode. * Provides a standalone web interface for importing analysis metrics. -* :doc:`Grafana server for Omniperf ` (server-side) (*optional*) +* :doc:`Grafana server for ROCm Compute Profiler ` (server-side) (*optional*) * Hosts the MongoDB backend and Grafana instance. * Is packaged in a Docker container for easy setup. Determine what you need to install based on how you would like to interact with -Omniperf. See the following decision tree to help determine what installation is +ROCm Compute Profiler. See the following decision tree to help determine what installation is right for you. .. image:: ../data/install/install-decision-tree.png :align: center - :alt: Decision tree for installing and deploying Omniperf + :alt: Decision tree for installing and deploying ROCm Compute Profiler :width: 800 .. _core-install: - + Core installation ================= -The core Omniperf application requires the following basic software -dependencies. As of ROCm 6.2, the core Omniperf is included with your ROCm +The core ROCm Compute Profiler application requires the following basic software +dependencies. As of ROCm 6.2, the core ROCm Compute Profiler is included with your ROCm installation. * Python ``>= 3.8`` @@ -46,16 +46,16 @@ installation. .. note:: - Omniperf will use the first version of ``Python3`` found in your system's - ``PATH``. If the default version of Python3 is older than 3.8, you may need to - update your system's ``PATH`` to point to a newer version of Python3. + ROCm Compute Profiler will use the first version of ``python3`` found in your system's + ``PATH``. If the default version of Python is older than 3.8, you may need to + update your system's ``PATH`` to point to a newer version. -Omniperf depends on a number of Python packages documented in the top-level -``requirements.txt`` file. Install these *before* configuring Omniperf. +ROCm Compute Profiler depends on a number of Python packages documented in the top-level +``requirements.txt`` file. Install these *before* configuring ROCm Compute Profiler. .. tip:: - If looking to build Omniperf as a developer, consider these additional + If looking to build ROCm Compute Profiler as a developer, consider these additional requirements. .. list-table:: @@ -64,23 +64,23 @@ Omniperf depends on a number of Python packages documented in the top-level - Python packages required to build this documentation from source. * - ``requirements-test.txt`` - - Python packages required to run Omniperf's CI suite using PyTest. + - Python packages required to run ROCm Compute Profiler's CI suite using PyTest. -The recommended procedure for Omniperf usage is to install into a shared file +The recommended procedure for ROCm Compute Profiler usage is to install into a shared file system so that multiple users can access the final installation. The following steps illustrate how to install the necessary Python dependencies -using `pip `_ and Omniperf into a +using `pip `_ and ROCm Compute Profiler into a shared location controlled by the ``INSTALL_DIR`` environment variable. .. tip:: - To always run Omniperf with a particular version of python, you can create a - bash alias. For example, to run Omniperf with Python 3.10, you can run the + To always run ROCm Compute Profiler with a particular version of Python, you can create a + bash alias. For example, to run ROCm Compute Profiler with Python 3.10, you can run the following command: .. code-block:: shell - alias omniperf-mypython="/usr/bin/python3.10 /opt/rocm/bin/omniperf" + alias rocprof-compute-mypython="/usr/bin/python3.10 /opt/rocm/bin/rocprof-compute" .. _core-install-cmake-vars: @@ -97,13 +97,13 @@ follows. - Description * - ``CMAKE_INSTALL_PREFIX`` - - Controls the install path for Omniperf files. + - Controls the install path for ROCm Compute Profiler files. * - ``PYTHON_DEPS`` - Specifies an optional path to resolve Python package dependencies. * - ``MOD_INSTALL_PATH`` - - Specifies an optional path for separate Omniperf modulefile installation. + - Specifies an optional path for separate ROCm Compute Profiler modulefile installation. .. _core-install-steps: @@ -111,20 +111,20 @@ Install from source ------------------- #. A typical install begins by downloading the latest release tarball available - from ``__. From there, untar and + from ``__. From there, untar and navigate into the top-level directory. .. - {{ config.version }} substitutes the Omniperf version in ../conf.py + {{ config.version }} substitutes the ROCm Compute Profiler version in ../conf.py .. datatemplate:nodata:: .. code-block:: shell - tar xfz omniperf-v{{ config.version }}.tar.gz - cd omniperf-v{{ config.version }} + tar xfz rocprofiler-compute-v{{ config.version }}.tar.gz + cd rocprofiler-compute-v{{ config.version }} -#. Next, install Python dependencies and complete the Omniperf configuration and +#. Next, install Python dependencies and complete the ROCm Compute Profiler configuration and install process. .. datatemplate:nodata:: @@ -137,12 +137,12 @@ Install from source # install python deps python3 -m pip install -t ${INSTALL_DIR}/python-libs -r requirements.txt - # configure Omniperf for shared install + # configure ROCm Compute Profiler for shared install mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}/{{ config.version }} \ -DPYTHON_DEPS=${INSTALL_DIR}/python-libs \ - -DMOD_INSTALL_PATH=${INSTALL_DIR}/modulefiles/omniperf .. + -DMOD_INSTALL_PATH=${INSTALL_DIR}/modulefiles/rocprofiler-compute .. # install make install @@ -169,33 +169,33 @@ Execution using modulefiles The installation process includes the creation of an environment modulefile for use with `Lmod `_. On systems that support Lmod, -you can register the Omniperf modulefile directory and setup your environment -for execution of Omniperf as follows. +you can register the ROCm Compute Profiler modulefile directory and setup your environment +for execution of ROCm Compute Profiler as follows. .. datatemplate:nodata:: .. code-block:: shell $ module use $INSTALL_DIR/modulefiles - $ module load omniperf - $ which omniperf - /opt/apps/omniperf/{{ config.version }}/bin/omniperf + $ module load rocprofiler-compute + $ which rocprof-compute + /opt/apps/rocprofiler-compute/{{ config.version }}/bin/rocprof-compute - $ omniperf --version + $ rocprof-compute --version ROC Profiler: /opt/rocm-5.1.0/bin/rocprof - omniperf (v{{ config.version }}) + rocprofiler-compute (v{{ config.version }}) .. tip:: If you're relying on an Lmod Python module locally, you may wish to customize - the resulting Omniperf modulefile post-installation to include extra + the resulting ROCm Compute Profiler modulefile post-installation to include extra module dependencies. Execution without modulefiles ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To use Omniperf without the companion modulefile, update your ``PATH`` +To use ROCm Compute Profiler without the companion modulefile, update your ``PATH`` settings to enable access to the command line binary. If you installed Python dependencies in a shared location, also update your ``PYTHONPATH`` configuration. @@ -212,7 +212,7 @@ configuration. Install via package manager --------------------------- -Once ROCm (minimum version 6.2.0) is installed, you can install Omniperf using +Once ROCm (minimum version 6.2.0) is installed, you can install ROCm Compute Profiler using your operating system's native package manager using the following commands. See :doc:`rocm-install-on-linux:index` for guidance on installing the ROCm software stack. @@ -223,38 +223,38 @@ software stack. .. code-block:: shell - $ sudo apt install omniperf - # Include omniperf in your system PATH - $ sudo update-alternatives --install /usr/bin/omniperf omniperf /opt/rocm/bin/omniperf 0 + $ sudo apt install rocprofiler-compute + # Include rocprofiler-compute in your system PATH + $ sudo update-alternatives --install /usr/bin/rocprofiler-compute rocprof-compute /opt/rocm/bin/rocprofiler-compute 0 # Install Python dependencies - $ python3 -m pip install -r /opt/rocm/libexec/omniperf/requirements.txt + $ python3 -m pip install -r /opt/rocm/libexec/rocprofiler-compute/requirements.txt .. tab-item:: Red Hat Enterprise Linux .. code-block:: shell - $ sudo dnf install omniperf - # Include omniperf in your system PATH - $ sudo update-alternatives --install /usr/bin/omniperf omniperf /opt/rocm/bin/omniperf 0 + $ sudo dnf install rocprofiler-compute + # Include rocprofiler-compute in your system PATH + $ sudo update-alternatives --install /usr/bin/rocprofiler-compute rocprof-compute /opt/rocm/bin/rocprofiler-compute 0 # Install Python dependencies - $ python3 -m pip install -r /opt/rocm/libexec/omniperf/requirements.txt + $ python3 -m pip install -r /opt/rocm/libexec/rocprofiler-compute/requirements.txt .. tab-item:: SUSE Linux Enterprise Server .. code-block:: shell - $ sudo zypper install omniperf - # Include omniperf in your system PATH - $ sudo update-alternatives --install /usr/bin/omniperf omniperf /opt/rocm/bin/omniperf 0 + $ sudo zypper install rocprofiler-compute + # Include rocprofiler-compute in your system PATH + $ sudo update-alternatives --install /usr/bin/rocprofiler-compute rocprof-compute /opt/rocm/bin/rocprofiler-compute 0 # Install Python dependencies - $ python3 -m pip install -r /opt/rocm/libexec/omniperf/requirements.txt + $ python3 -m pip install -r /opt/rocm/libexec/rocprofiler-compute/requirements.txt .. _core-install-rocprof-var: ROCProfiler ----------- -Omniperf relies on :doc:`ROCProfiler `'s ``rocprof`` binary +ROCm Compute Profiler relies on :doc:`ROCProfiler `'s ``rocprof`` binary during the profiling process. Normally, the path to this binary is detected automatically, but you can override the path by the setting the optional ``ROCPROF`` environment variable. diff --git a/docs/install/grafana-setup.rst b/docs/install/grafana-setup.rst index a7486d286..4ef28f85b 100644 --- a/docs/install/grafana-setup.rst +++ b/docs/install/grafana-setup.rst @@ -1,26 +1,26 @@ .. meta:: - :description: Omniperf Grafana server installation and deployment - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, + :description: ROCm Compute Profiler Grafana server installation and deployment + :keywords: ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, AMD, install, deploy, Grafana, server, configuration, GUI -**************************************** -Setting up a Grafana server for Omniperf -**************************************** +*************************************************** +Setting up Grafana server for ROCm Compute Profiler +*************************************************** A Grafana server is *not required* to profile or analyze performance data from the CLI. It's a supplementary mechanism to help you import performance data and examine it in a detailed `Grafana `_ dashboard GUI. -Learn about installing and configuring the main Omniperf tool in +Learn about installing and configuring the main ROCm Compute Profiler tool in :ref:`core-install`. -Setting up a Grafana instance for Omniperf requires the following basic software +Setting up a Grafana instance for ROCm Compute Profiler requires the following basic software dependencies. * `Docker Engine `_ -The recommended process for enabling the server-side of Omniperf is to use the +The recommended process for enabling the server-side of ROCm Compute Profiler is to use the provided ``Dockerfile`` to build the Grafana and MongoDB instance. .. _grafana-mongodb-setup: @@ -34,7 +34,7 @@ the following setup instructions. Install MongoDB utilities ------------------------- -Omniperf uses the +ROCm Compute Profiler uses the `mongoimport `_ utility to upload data to your Grafana instance's backend database. @@ -70,7 +70,7 @@ crash or reset. This is called *creating a persistent volume*. Build and launch the Docker container ------------------------------------- -You're now ready to build your ``Dockerfile``. Navigate to your Omniperf install +You're now ready to build your ``Dockerfile``. Navigate to your ROCm Compute Profiler install directory to begin. .. code-block:: bash @@ -79,6 +79,13 @@ directory to begin. $ sudo docker-compose build $ sudo docker-compose up -d +.. note:: + + To troubleshoot Docker container build failures related to certificate verification, try + disabling any network proxy services on the host system. These proxy services can interfere + with OpenSSL's ability to retrieve a correct certificate chain when the container accesses + external websites. + The TCP ports for Grafana (``4000``) and MongoDB (``27017``) in the Docker container are mapped to ``14000`` and ``27018``, respectively, on the host side. @@ -158,12 +165,12 @@ connection is successful. .. _grafana-import-dashboard-file: -Import the Omniperf dashboard file ----------------------------------- +Import the ROCm Compute Profiler dashboard file +----------------------------------------------- From the **Create** → **Import** page, upload the dashboard file, -``/dashboards/Omniperf_v{__VERSION__}_pub.json`` from the -:doc:`Omniperf tarball `. +``/dashboards/RocProfCompute_v{__VERSION__}_pub.json`` from the +:doc:`ROCm Compute Profiler tarball `. Edit both the dashboard **Name** and the **Unique identifier (UID)** fields to uniquely identify the dashboard. Click **Import** to complete the process. @@ -177,21 +184,21 @@ uniquely identify the dashboard. Click **Import** to complete the process. .. _grafana-select-workload: -Select and load the Omniperf workload -------------------------------------- +Select and load the ROCm Compute Profiler workload +-------------------------------------------------- Once you have imported a dashboard you're ready to begin. Start by browsing available dashboards and selecting the dashboard you have just imported. .. figure:: ../data/install/opening_dashboard.png :align: center - :alt: Opening your Omniperf dashboard in Grafana + :alt: Opening your ROCm Compute Profiler dashboard in Grafana :width: 800 - Opening your Omniperf profiling dashboard in Grafana. + Opening your ROCm Compute Profiler profiling dashboard in Grafana. Remember that you need to upload workload data to the MongoDB backend before -analyzing in your Grafana interface. See a detailed example of this in +analyzing in your Grafana interface. See a detailed example of this in :ref:`grafana-gui-import`. After a workload has been successfully uploaded, you should be able to select it @@ -199,10 +206,10 @@ from the workload dropdown located at the top of your Grafana dashboard. .. figure:: ../data/install/grafana_workload_selection.png :align: center - :alt: Omniperf workload selection in Grafana + :alt: ROCm Compute Profiler workload selection in Grafana :width: 800 - Selecting your Omniperf workload in Grafana. + Selecting your ROCm Compute Profiler workload in Grafana. For more information on how to use the Grafana interface for analysis see :doc:`/how-to/analyze/grafana-gui`. diff --git a/docs/license.rst b/docs/license.rst index c423ed34f..b64c89729 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf license - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, + :description: ROCm Compute Profiler license + :keywords: ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, AMD, license ******* diff --git a/docs/reference/compatible-accelerators.rst b/docs/reference/compatible-accelerators.rst index b93c72032..65a3f70a1 100644 --- a/docs/reference/compatible-accelerators.rst +++ b/docs/reference/compatible-accelerators.rst @@ -1,36 +1,36 @@ .. meta:: - :description: Omniperf support: compatible accelerators and GPUs - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, GPU + :description: ROCm Compute Profiler support: compatible accelerators and GPUs + :keywords: Omniperf, compatible, cdna, gcn, gfx, rdna, radeon, hardware, architecture *********************** Compatible accelerators *********************** The following table lists SoCs (System on Chip) tested for compatibility with -Omniperf. See :doc:`rocm:reference/gpu-arch-specs` for full AMD accelerator and +ROCm Compute Profiler. See :doc:`rocm:reference/gpu-arch-specs` for full AMD accelerator and GPU specifications. .. _def-soc: .. note:: - In Omniperf documentation, the term System on Chip (SoC) refers to a + In ROCm Compute Profiler documentation, the term System on Chip (SoC) refers to a particular family of AMD accelerators. .. list-table:: - :header-rows: 1 + :header-rows: 1 - * - Platform - - Status + * - Platform + - Status - * - AMD Instinct™ MI300 - - Supported ✅ + * - AMD Instinct™ MI300 + - Supported ✅ - * - AMD Instinct MI200 - - Supported ✅ + * - AMD Instinct MI200 + - Supported ✅ - * - AMD Instinct MI100 - - Supported ✅ + * - AMD Instinct MI100 + - Supported ✅ - * - AMD Instinct MI50, MI60 (Vega 20) - - No support ❌ + * - AMD Instinct MI50, MI60 (Vega 20) + - No support ❌ diff --git a/docs/reference/faq.rst b/docs/reference/faq.rst index 3cbbe778f..2ec10debf 100644 --- a/docs/reference/faq.rst +++ b/docs/reference/faq.rst @@ -1,6 +1,6 @@ .. meta:: - :description: Omniperf FAQ and troubleshooting - :keywords: Omniperf, FAQ, troubleshooting, ROCm, profiler, tool, Instinct, + :description: ROCm Compute Profiler FAQ and troubleshooting + :keywords: ROCm Compute Profiler, FAQ, troubleshooting, ROCm, profiler, tool, Instinct, accelerator, AMD, SSH, error, version, workaround, help *** @@ -9,8 +9,8 @@ FAQ Frequently asked questions and troubleshooting tips. -How do I export profiling data I have already generated using Omniperf? -======================================================================= +How do I export profiling data I have already generated using ROCm Compute Profiler? +==================================================================================== To interact with the Grafana GUI, you must sync data with the MongoDB backend. You can do this using :ref:`database ` mode. @@ -19,7 +19,7 @@ Pass in the directory of your desired workload as follows. .. code-block:: shell - $ omniperf database --import -w -H -u -t + $ rocprof-compute database --import -w -H -u -t python ast error: 'Constant' object has no attribute 'kind' =========================================================== diff --git a/docs/sphinx/_toc.yml.in b/docs/sphinx/_toc.yml.in index eb863b7a3..7df82fc8b 100644 --- a/docs/sphinx/_toc.yml.in +++ b/docs/sphinx/_toc.yml.in @@ -6,13 +6,14 @@ defaults: root: index subtrees: - entries: - - file: what-is-omniperf.rst + - file: what-is-rocprof-compute.rst - caption: Install entries: - file: install/core-install.rst + title: Installation and deployment - file: install/grafana-setup.rst - title: Grafana server for Omniperf + title: Grafana server setup - caption: How to entries: diff --git a/docs/tutorial/includes/infinity-fabric-transactions.rst b/docs/tutorial/includes/infinity-fabric-transactions.rst index fd510bd49..9e26e59bd 100644 --- a/docs/tutorial/includes/infinity-fabric-transactions.rst +++ b/docs/tutorial/includes/infinity-fabric-transactions.rst @@ -5,7 +5,7 @@ Infinity Fabric transactions For this example, consider the :dev-sample:`Infinity Fabric™ sample ` distributed as a part of - Omniperf. + ROCm Compute Profiler. This following code snippet launches a simple read-only kernel. @@ -36,7 +36,7 @@ is identically false -- and thus we expect no writes. .. note:: - The actual sample included with Omniperf also includes the ability to select + The actual sample included with ROCm Compute Profiler also includes the ability to select different operation types (such as atomics, writes). This abbreviated version is presented here for reference only. @@ -44,13 +44,13 @@ Finally, this sample code lets the user control the :ref:`granularity of an allocation `, the owner of an allocation (local HBM, CPU DRAM or remote HBM), and the size of an allocation (the default is :math:`\sim4`\ GiB) via command line arguments. In doing so, we can explore -the impact of these parameters on the L2-Fabric metrics reported by Omniperf to +the impact of these parameters on the L2-Fabric metrics reported by ROCm Compute Profiler to further understand their meaning. .. note:: All results in this section were generated an a node of Infinity - Fabric connected MI250 accelerators using ROCm version 5.6.0, and Omniperf + Fabric connected MI250 accelerators using ROCm version 5.6.0, and ROCm Compute Profiler version 2.0.0. Although results may vary with ROCm versions and accelerator connectivity, we expect the lessons learned here to be broadly applicable. @@ -64,7 +64,7 @@ In our first experiment, we consider the simplest possible case, a .. code-block:: shell-session - $ omniperf profile -n coarse_grained_local --no-roof -- ./fabric -t 1 -o 0 + $ rocprof-compute profile -n coarse_grained_local --no-roof -- ./fabric -t 1 -o 0 Using: mtype:CoarseGrained mowner:Device @@ -73,7 +73,7 @@ In our first experiment, we consider the simplest possible case, a mdata:Unsigned remoteId:-1 <...> - $ omniperf analyze -p workloads/coarse_grained_local/mi200 -b 17.2.0 17.2.1 17.2.2 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 + $ rocprof-compute analyze -p workloads/coarse_grained_local/mi200 -b 17.2.0 17.2.1 17.2.2 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 <...> 17. L2 Cache 17.2 L2 - Fabric Transactions @@ -163,7 +163,7 @@ accelerator. Our code uses the ``hipExtMallocWithFlag`` API with the .. code-block:: shell-session - $ omniperf profile -n fine_grained_local --no-roof -- ./fabric -t 0 -o 0 + $ rocprof-compute profile -n fine_grained_local --no-roof -- ./fabric -t 0 -o 0 Using: mtype:FineGrained mowner:Device @@ -172,7 +172,7 @@ accelerator. Our code uses the ``hipExtMallocWithFlag`` API with the mdata:Unsigned remoteId:-1 <...> - $ omniperf analyze -p workloads/fine_grained_local/mi200 -b 17.2.0 17.2.1 17.2.2 17.2.3 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 + $ rocprof-compute analyze -p workloads/fine_grained_local/mi200 -b 17.2.0 17.2.1 17.2.2 17.2.3 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 <...> 17. L2 Cache 17.2 L2 - Fabric Transactions @@ -245,7 +245,7 @@ substantial change in the L2-Fabric metrics: .. code-block:: shell-session - $ omniperf profile -n fine_grained_remote --no-roof -- ./fabric -t 0 -o 2 + $ rocprof-compute profile -n fine_grained_remote --no-roof -- ./fabric -t 0 -o 2 Using: mtype:FineGrained mowner:Remote @@ -254,7 +254,7 @@ substantial change in the L2-Fabric metrics: mdata:Unsigned remoteId:-1 <...> - $ omniperf analyze -p workloads/fine_grained_remote/mi200 -b 17.2.0 17.2.1 17.2.2 17.2.3 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 + $ rocprof-compute analyze -p workloads/fine_grained_remote/mi200 -b 17.2.0 17.2.1 17.2.2 17.2.3 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 <...> 17. L2 Cache 17.2 L2 - Fabric Transactions @@ -339,7 +339,7 @@ fine-grained memory using the ``hipHostMalloc`` API: .. code-block:: shell-session - $ omniperf profile -n fine_grained_host --no-roof -- ./fabric -t 0 -o 1 + $ rocprof-compute profile -n fine_grained_host --no-roof -- ./fabric -t 0 -o 1 Using: mtype:FineGrained mowner:Host @@ -348,7 +348,7 @@ fine-grained memory using the ``hipHostMalloc`` API: mdata:Unsigned remoteId:-1 <...> - $ omniperf analyze -p workloads/fine_grained_host/mi200 -b 17.2.0 17.2.1 17.2.2 17.2.3 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 + $ rocprof-compute analyze -p workloads/fine_grained_host/mi200 -b 17.2.0 17.2.1 17.2.2 17.2.3 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 <...> 17. L2 Cache 17.2 L2 - Fabric Transactions @@ -416,7 +416,7 @@ allocation as coarse-grained: .. code-block:: shell-session - $ omniperf profile -n coarse_grained_host --no-roof -- ./fabric -t 1 -o 1 + $ rocprof-compute profile -n coarse_grained_host --no-roof -- ./fabric -t 1 -o 1 Using: mtype:CoarseGrained mowner:Host @@ -425,7 +425,7 @@ allocation as coarse-grained: mdata:Unsigned remoteId:-1 <...> - $ omniperf analyze -p workloads/coarse_grained_host/mi200 -b 17.2.0 17.2.1 17.2.2 17.2.3 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 + $ rocprof-compute analyze -p workloads/coarse_grained_host/mi200 -b 17.2.0 17.2.1 17.2.2 17.2.3 17.4.0 17.4.1 17.4.2 17.5.0 17.5.1 17.5.2 17.5.3 17.5.4 -n per_kernel --dispatch 2 <...> 17. L2 Cache 17.2 L2 - Fabric Transactions @@ -484,7 +484,7 @@ operations to fine-grained memory allocated on the host: .. code-block:: shell-session - $ omniperf profile -n fine_grained_host_write --no-roof -- ./fabric -t 0 -o 1 -p 1 + $ rocprof-compute profile -n fine_grained_host_write --no-roof -- ./fabric -t 0 -o 1 -p 1 Using: mtype:FineGrained mowner:Host @@ -493,7 +493,7 @@ operations to fine-grained memory allocated on the host: mdata:Unsigned remoteId:-1 <...> - $ omniperf analyze -p workloads/fine_grained_host_writes/mi200 -b 17.2.4 17.2.5 17.2.6 17.2.7 17.2.8 17.4.3 17.4.4 17.4.5 17.4.6 17.5.5 17.5.6 17.5.7 17.5.8 17.5.9 17.5.10 -n per_kernel --dispatch 2 + $ rocprof-compute analyze -p workloads/fine_grained_host_writes/mi200 -b 17.2.4 17.2.5 17.2.6 17.2.7 17.2.8 17.4.3 17.4.4 17.4.5 17.4.6 17.5.5 17.5.6 17.5.7 17.5.8 17.5.9 17.5.10 -n per_kernel --dispatch 2 <...> 17. L2 Cache 17.2 L2 - Fabric Transactions @@ -576,7 +576,7 @@ operations to the CPU’s DRAM. .. code-block:: shell-session - $ omniperf profile -n fine_grained_host_add --no-roof -- ./fabric -t 0 -o 1 -p 2 + $ rocprof-compute profile -n fine_grained_host_add --no-roof -- ./fabric -t 0 -o 1 -p 2 Using: mtype:FineGrained mowner:Host @@ -585,7 +585,7 @@ operations to the CPU’s DRAM. mdata:Unsigned remoteId:-1 <...> - $ omniperf analyze -p workloads/fine_grained_host_add/mi200 -b 17.2.4 17.2.5 17.2.6 17.2.7 17.2.8 17.4.3 17.4.4 17.4.5 17.4.6 17.5.5 17.5.6 17.5.7 17.5.8 17.5.9 17.5.10 -n per_kernel --dispatch 2 + $ rocprof-compute analyze -p workloads/fine_grained_host_add/mi200 -b 17.2.4 17.2.5 17.2.6 17.2.7 17.2.8 17.4.3 17.4.4 17.4.5 17.4.6 17.5.5 17.5.6 17.5.7 17.5.8 17.5.9 17.5.10 -n per_kernel --dispatch 2 <...> 17. L2 Cache 17.2 L2 - Fabric Transactions diff --git a/docs/tutorial/includes/instructions-per-cycle-and-utilizations.rst b/docs/tutorial/includes/instructions-per-cycle-and-utilizations.rst index dcbf37266..c9efe8502 100644 --- a/docs/tutorial/includes/instructions-per-cycle-and-utilizations.rst +++ b/docs/tutorial/includes/instructions-per-cycle-and-utilizations.rst @@ -5,7 +5,7 @@ Instructions-per-cycle and utilizations example For this example, consider the :dev-sample:`instructions-per-cycle (IPC) example ` included with -Omniperf. +ROCm Compute Profiler. This example is compiled using ``c++17`` support: @@ -17,7 +17,7 @@ and was run on an MI250 CDNA2 accelerator: .. code-block:: shell - $ omniperf profile -n ipc --no-roof -- ./ipc + $ rocprof-compute profile -n ipc --no-roof -- ./ipc The results shown in this section are *generally* applicable to CDNA accelerators, but may vary between generations and specific products. @@ -64,11 +64,11 @@ operation, i.e., a ``v_mov_b32`` instruction, e.g.: This instruction simply copies the contents from the source register (``v1``) to the destination register (``v0``). Investigating this kernel -with Omniperf, we see: +with ROCm Compute Profiler, we see: .. code-block:: shell-session - $ omniperf analyze -p workloads/ipc/mi200/ --dispatch 7 -b 11.2 + $ rocprof-compute analyze -p workloads/ipc/mi200/ --dispatch 7 -b 11.2 <...> -------------------------------------------------------------------------------- 0. Top Stat @@ -172,7 +172,7 @@ in the IPC example: .. code-block:: shell - $ omniperf analyze -p workloads/ipc/mi200/ --dispatch 8 -b 11.2 --decimal 4 + $ rocprof-compute analyze -p workloads/ipc/mi200/ --dispatch 8 -b 11.2 --decimal 4 <...> -------------------------------------------------------------------------------- 0. Top Stat @@ -240,7 +240,7 @@ instructions executed over the total There are further complications of the Issued IPC metric (**11.2.1**) that make its use more complicated. We will be explore that in the :ref:`following section `. For these reasons, - Omniperf typically promotes use of the regular IPC metric (**11.2.0**), e.g., in + ROCm Compute Profiler typically promotes use of the regular IPC metric (**11.2.0**), e.g., in the top-level Speed-of-Light chart. .. _ipc-internal-instructions: @@ -261,11 +261,11 @@ Here we choose to use the following no-op to make our point: s_nop 0x0 -Running this kernel through Omniperf yields: +Running this kernel through ROCm Compute Profiler yields: .. code-block:: shell-session - $ omniperf analyze -p workloads/ipc/mi200/ --dispatch 9 -b 11.2 + $ rocprof-compute analyze -p workloads/ipc/mi200/ --dispatch 9 -b 11.2 <...> -------------------------------------------------------------------------------- 0. Top Stat @@ -362,11 +362,11 @@ operation, for instance: which, in analogue to our :ref:`v_mov ` example, copies the contents of the source scalar register (``s1``) to the destination -scalar register (``s0``). Running this kernel through Omniperf yields: +scalar register (``s0``). Running this kernel through ROCm Compute Profiler yields: .. code-block:: shell-session - $ omniperf analyze -p workloads/ipc/mi200/ --dispatch 10 -b 11.2 + $ rocprof-compute analyze -p workloads/ipc/mi200/ --dispatch 10 -b 11.2 <...> -------------------------------------------------------------------------------- 0. Top Stat @@ -426,11 +426,11 @@ of our :ref:`v_mov ` example: That is, we wrap our :ref:`VALU ` operation inside a conditional where only one lane in our wavefront is active. Running this kernel -through Omniperf yields: +through ROCm Compute Profiler yields: .. code-block:: shell-session - $ omniperf analyze -p workloads/ipc/mi200/ --dispatch 11 -b 11.2 + $ rocprof-compute analyze -p workloads/ipc/mi200/ --dispatch 11 -b 11.2 <...> -------------------------------------------------------------------------------- 0. Top Stat diff --git a/docs/tutorial/includes/lds-examples.rst b/docs/tutorial/includes/lds-examples.rst index f6cff7b72..8d1b7b1a9 100644 --- a/docs/tutorial/includes/lds-examples.rst +++ b/docs/tutorial/includes/lds-examples.rst @@ -4,22 +4,22 @@ LDS examples ============ For this example, consider the -:dev-sample:`LDS sample ` distributed as a part of Omniperf. This +:dev-sample:`LDS sample ` distributed as a part of ROCm Compute Profiler. This code contains two kernels to explore how both :doc:`LDS ` bandwidth and -bank conflicts are calculated in Omniperf. +bank conflicts are calculated in ROCm Compute Profiler. This example was compiled and run on an MI250 accelerator using ROCm -v5.6.0, and Omniperf v2.0.0. +v5.6.0, and ROCm Compute Profiler v2.0.0. .. code-block:: shell-session $ hipcc -O3 lds.hip -o lds -Finally, we generate our ``omniperf profile`` as: +Finally, we generate our ``rocprof-compute profile`` as: .. code-block:: shell-session - $ omniperf profile -n lds --no-roof -- ./lds + $ rocprof-compute profile -n lds --no-roof -- ./lds .. _lds-bandwidth: @@ -71,7 +71,7 @@ Next, let’s analyze the first of our bandwidth kernel dispatches: .. code-block:: shell - $ omniperf analyze -p workloads/lds/mi200/ -b 12.2.1 --dispatch 0 -n per_kernel + $ rocprof-compute analyze -p workloads/lds/mi200/ -b 12.2.1 --dispatch 0 -n per_kernel <...> 12. Local Data Share (LDS) 12.2 LDS Stats @@ -93,7 +93,7 @@ Recall our definition of this metric: Here we see that this instruction *could* have loaded up to 256 bytes of data (4 bytes for each work-item in the wavefront), and therefore this -is the expected value for this metric in Omniperf, hence why this metric +is the expected value for this metric in ROCm Compute Profiler, hence why this metric is named the “theoretical” bandwidth. To further illustrate this point we plot the relationship of the @@ -104,11 +104,11 @@ launched from 1 to 256: .. figure:: ../data/profiling-by-example/ldsbandwidth.png :align: center :alt: Comparison of effective bandwidth versus the theoretical bandwidth - metric in Omniperf for our simple example. + metric in ROCm Compute Profiler for our simple example. :width: 800 Comparison of effective bandwidth versus the theoretical bandwidth - metric in Omniperf for our simple example. + metric in ROCm Compute Profiler for our simple example. Here we see that the theoretical bandwidth metric follows a step-function. It increases only when another wavefront issues an LDS instruction for up to 256 @@ -172,7 +172,7 @@ see: .. code-block:: shell - $ omniperf analyze -p workloads/lds/mi200/ -b 12.2.4 12.2.6 --dispatch 256 -n per_kernel + $ rocprof-compute analyze -p workloads/lds/mi200/ -b 12.2.4 12.2.6 --dispatch 256 -n per_kernel <...> -------------------------------------------------------------------------------- 12. Local Data Share (LDS) @@ -196,7 +196,7 @@ Looking at the next ``conflicts`` dispatch (i.e., two work-items) yields: .. code-block:: shell - $ omniperf analyze -p workloads/lds/mi200/ -b 12.2.4 12.2.6 --dispatch 257 -n per_kernel + $ rocprof-compute analyze -p workloads/lds/mi200/ -b 12.2.4 12.2.6 --dispatch 257 -n per_kernel <...> -------------------------------------------------------------------------------- 12. Local Data Share (LDS) diff --git a/docs/tutorial/includes/occupancy-limiters-example.rst b/docs/tutorial/includes/occupancy-limiters-example.rst index bd8129d12..dcbd6a61b 100644 --- a/docs/tutorial/includes/occupancy-limiters-example.rst +++ b/docs/tutorial/includes/occupancy-limiters-example.rst @@ -4,15 +4,15 @@ Occupancy limiters example ========================== For this example, consider the -:dev-sample:`occupancy ` included with Omniperf. We will +:dev-sample:`occupancy ` included with ROCm Compute Profiler. We will investigate the use of the resource allocation panel in the :ref:`Workgroup Manager `’s metrics section to determine occupancy limiters. This code contains several kernels to explore how both various kernel resources impact achieved occupancy, and how this is reported in -Omniperf. +ROCm Compute Profiler. This example was compiled and run on a MI250 accelerator using ROCm -v5.6.0, and Omniperf v2.0.0: +v5.6.0, and ROCm Compute Profiler v2.0.0: .. code-block:: shell @@ -21,11 +21,11 @@ v5.6.0, and Omniperf v2.0.0: We have again included the ``--save-temps`` flag to get the corresponding assembly. -Finally, we generate our Omniperf profile as: +Finally, we generate our ROCm Compute Profiler profile as: .. code-block:: shell - $ omniperf profile -n occupancy --no-roof -- ./occupancy + $ rocprof-compute profile -n occupancy --no-roof -- ./occupancy .. _occupancy-experiment-design: @@ -88,7 +88,7 @@ depend on the exact ROCm/compiler version. We will use various permutations of this kernel to limit occupancy, and more importantly for the purposes of this example, demonstrate how this -is reported in Omniperf. +is reported in ROCm Compute Profiler. .. _vgpr-occupancy: @@ -101,7 +101,7 @@ the analyze step on this kernel: .. code-block:: shell - $ omniperf analyze -p workloads/occupancy/mi200/ -b 2.1.15 6.2 7.1.5 7.1.6 7.1.7 --dispatch 1 + $ rocprof-compute analyze -p workloads/occupancy/mi200/ -b 2.1.15 6.2 7.1.5 7.1.6 7.1.7 --dispatch 1 <...> -------------------------------------------------------------------------------- 0. Top Stat @@ -226,7 +226,7 @@ Analyzing this: .. code-block:: shell - $ omniperf analyze -p workloads/occupancy/mi200/ -b 2.1.15 6.2 7.1.5 7.1.6 7.1.7 7.1.8 --dispatch 3 + $ rocprof-compute analyze -p workloads/occupancy/mi200/ -b 2.1.15 6.2 7.1.5 7.1.6 7.1.7 7.1.8 --dispatch 3 <...> -------------------------------------------------------------------------------- 2. System Speed-of-Light @@ -351,7 +351,7 @@ Analyzing this workload yields: .. code-block:: shell-session - $ omniperf analyze -p workloads/occupancy/mi200/ -b 2.1.15 6.2 7.1.5 7.1.6 7.1.7 7.1.8 7.1.9 --dispatch 5 + $ rocprof-compute analyze -p workloads/occupancy/mi200/ -b 2.1.15 6.2 7.1.5 7.1.6 7.1.7 7.1.8 7.1.9 --dispatch 5 <...> -------------------------------------------------------------------------------- 0. Top Stat diff --git a/docs/tutorial/includes/valu-arithmetic-instruction-mix.rst b/docs/tutorial/includes/valu-arithmetic-instruction-mix.rst index 785fc6ecf..dcdb46ac4 100644 --- a/docs/tutorial/includes/valu-arithmetic-instruction-mix.rst +++ b/docs/tutorial/includes/valu-arithmetic-instruction-mix.rst @@ -5,7 +5,7 @@ VALU arithmetic instruction mix For this example, consider the :dev-sample:`instruction mix sample ` distributed as a part - of Omniperf. + of ROCm Compute Profiler. .. note:: @@ -55,7 +55,7 @@ Instruction mix ^^^^^^^^^^^^^^^ This example was compiled and run on a MI250 accelerator using ROCm - v5.6.0, and Omniperf v2.0.0. + v5.6.0, and ROCm Compute Profiler v2.0.0. .. code-block:: shell @@ -65,13 +65,13 @@ Generate the profile for this example using the following command. .. code-block:: shell - $ omniperf profile -n instmix --no-roof -- ./instmix + $ rocprof-compute profile -n instmix --no-roof -- ./instmix Analyze the instruction mix section. .. code-block:: shell - $ omniperf analyze -p workloads/instmix/mi200/ -b 10.2 + $ rocprof-compute analyze -p workloads/instmix/mi200/ -b 10.2 <...> 10. Compute Units - Instruction Mix 10.2 VALU Arithmetic Instr Mix diff --git a/docs/tutorial/includes/vector-memory-operation-counting.rst b/docs/tutorial/includes/vector-memory-operation-counting.rst index 2797ed8f2..4cfb875f4 100644 --- a/docs/tutorial/includes/vector-memory-operation-counting.rst +++ b/docs/tutorial/includes/vector-memory-operation-counting.rst @@ -10,7 +10,7 @@ Global / Generic (FLAT) For this example, consider the :dev-sample:`vector memory sample ` distributed as a part of -Omniperf. This code launches many different versions of a simple +ROCm Compute Profiler. This code launches many different versions of a simple read/write/atomic-only kernels targeting various address spaces. For example, below is our simple ``global_write`` kernel: @@ -24,7 +24,7 @@ below is our simple ``global_write`` kernel: .. note:: This example was compiled and run on an MI250 accelerator using ROCm - v5.6.0, and Omniperf v2.0.0. + v5.6.0, and ROCm Compute Profiler v2.0.0. .. code-block:: shell-session @@ -34,11 +34,11 @@ We have also chosen to include the ``--save-temps`` flag to save the compiler temporary files, such as the generated CDNA assembly code, for inspection. -Finally, we generate our ``omniperf profile`` as follows. +Finally, we generate our ``rocprof-compute profile`` as follows. .. code-block:: shell-session - $ omniperf profile -n vmem --no-roof -- ./vmem + $ rocprof-compute profile -n vmem --no-roof -- ./vmem .. _flat-experiment-design: @@ -94,7 +94,7 @@ First, we demonstrate our simple ``global_write`` kernel: .. code-block:: shell-session - $ omniperf analyze -p workloads/vmem/mi200/ --dispatch 1 -b 10.3 15.1.4 15.1.5 15.1.6 15.1.7 15.1.8 15.1.9 15.1.10 15.1.11 -n per_kernel + $ rocprof-compute analyze -p workloads/vmem/mi200/ --dispatch 1 -b 10.3 15.1.4 15.1.5 15.1.6 15.1.7 15.1.8 15.1.9 15.1.10 15.1.11 -n per_kernel <...> -------------------------------------------------------------------------------- 0. Top Stat @@ -208,7 +208,7 @@ Examining this kernel in the VMEM Instruction Mix table yields: .. code-block:: shell-session - $ omniperf analyze -p workloads/vmem/mi200/ --dispatch 2 -b 10.3 -n per_kernel + $ rocprof-compute analyze -p workloads/vmem/mi200/ --dispatch 2 -b 10.3 -n per_kernel <...> 0. Top Stat ╒════╤══════════════════════════════════════════╤═════════╤═══════════╤════════════╤══════════════╤════════╕ @@ -264,7 +264,7 @@ access. .. code-block:: shell-session - $ omniperf analyze -p workloads/vmem/mi200/ --dispatch 2 -b 12.2.0 -n per_kernel + $ rocprof-compute analyze -p workloads/vmem/mi200/ --dispatch 2 -b 12.2.0 -n per_kernel <...> 12. Local Data Share (LDS) 12.2 LDS Stats @@ -304,11 +304,11 @@ Here we observe a now familiar pattern: the compiler to statically eliminate, but is identically false. In this case, our ``main()`` function initializes the data in ``ptr`` to zero. -Running Omniperf on this kernel yields: +Running ROCm Compute Profiler on this kernel yields: .. code-block:: shell-session - $ omniperf analyze -p workloads/vmem/mi200/ --dispatch 3 -b 10.3 -n per_kernel + $ rocprof-compute analyze -p workloads/vmem/mi200/ --dispatch 3 -b 10.3 -n per_kernel <...> 0. Top Stat ╒════╤════════════════════════════════════╤═════════╤═══════════╤════════════╤══════════════╤════════╕ @@ -383,11 +383,11 @@ false conditional (both ``zero`` and ``filter`` are set to zero in the kernel launch). Note that this is a *different* conditional from our pointer assignment (to avoid combination of the two). -Running Omniperf on this kernel reports: +Running ROCm Compute Profiler on this kernel reports: .. code-block:: shell-session - $ omniperf analyze -p workloads/vmem/mi200/ --dispatch 4 -b 10.3 12.2.0 16.3.10 -n per_kernel + $ rocprof-compute analyze -p workloads/vmem/mi200/ --dispatch 4 -b 10.3 12.2.0 16.3.10 -n per_kernel <...> 0. Top Stat ╒════╤══════════════════════════════════════════╤═════════╤═══════════╤════════════╤══════════════╤════════╕ @@ -468,11 +468,11 @@ to a pointer. } -Running Omniperf on this kernel yields: +Running ROCm Compute Profiler on this kernel yields: .. code-block:: shell-session - $ omniperf analyze -p workloads/vmem/mi200/ --dispatch 5 -b 10.3 16.3.12 -n per_kernel + $ rocprof-compute analyze -p workloads/vmem/mi200/ --dispatch 5 -b 10.3 16.3.12 -n per_kernel <...> 0. Top Stat ╒════╤══════════════════════════════════════╤═════════╤═══════════╤════════════╤══════════════╤════════╕ @@ -537,11 +537,11 @@ operation targets both LDS and global memory: This assigns every other work-item to atomically update global memory or local memory. -Running this kernel through Omniperf shows: +Running this kernel through ROCm Compute Profiler shows: .. code-block:: shell-session - $ omniperf analyze -p workloads/vmem/mi200/ --dispatch 6 -b 10.3 12.2.0 16.3.12 -n per_kernel + $ rocprof-compute analyze -p workloads/vmem/mi200/ --dispatch 6 -b 10.3 12.2.0 16.3.12 -n per_kernel <...> 0. Top Stat ╒════╤══════════════════════════════════════════╤═════════╤═══════════╤════════════╤══════════════╤════════╕ @@ -623,7 +623,7 @@ manner. See for further reading on this instruction type. We develop a `simple -kernel `__ +kernel `__ that uses stack memory: .. code-block:: cpp @@ -647,19 +647,19 @@ Our strategy here is to: to global memory to prevent the compiler from optimizing it out. This example was compiled and run on an MI250 accelerator using ROCm v5.6.0, and -Omniperf v2.0.0. +ROCm Compute Profiler v2.0.0. .. code-block:: shell-session $ hipcc -O3 stack.hip -o stack.hip -And profiled using Omniperf: +And profiled using ROCm Compute Profiler: .. code-block:: shell-session - $ omniperf profile -n stack --no-roof -- ./stack + $ rocprof-compute profile -n stack --no-roof -- ./stack <...> - $ omniperf analyze -p workloads/stack/mi200/ -b 10.3 16.3.11 -n per_kernel + $ rocprof-compute analyze -p workloads/stack/mi200/ -b 10.3 16.3.11 -n per_kernel <...> 10. Compute Units - Instruction Mix 10.3 VMEM Instr Mix diff --git a/docs/tutorial/learning-resources.rst b/docs/tutorial/learning-resources.rst index 931f1f7f1..7766e08dd 100644 --- a/docs/tutorial/learning-resources.rst +++ b/docs/tutorial/learning-resources.rst @@ -1,20 +1,22 @@ .. meta:: - :description: Omniperf external training resources - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD, - training, examples + :description: ROCm Compute Profiler external training resources + :keywords: Omniperf, examples, tutorials, videos, lesson, lessons, how ****************** Learning resources ****************** -This section is a catalog of external resources and third-party content that -can help you learn Omniperf. Some areas of the following content might be -outdated. +This section provides a curated list of external resources and third-party +content to support learning the ROCm Compute Profiler. Some information in +these materials may be outdated. -Introduction to Omniperf +ROCm Compute Profiler was previously known as Omniperf. Some of the following +resources use the earlier name. + +Introduction to ROCm Compute Profiler :fab:`youtube` `AMD profiling workshop (Pawsey Supercomputing Research Centre) `_ -Omniperf example exercises +ROCm Compute Profiler example exercises ``__ AMD Instinct™ tuning guides diff --git a/docs/tutorial/profiling-by-example.rst b/docs/tutorial/profiling-by-example.rst index e39239b9d..faa00b5ec 100644 --- a/docs/tutorial/profiling-by-example.rst +++ b/docs/tutorial/profiling-by-example.rst @@ -1,14 +1,14 @@ .. meta:: - :description: Omniperf: Profiling by example - :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD + :description: ROCm Compute Profiler: Profiling by example + :keywords: ROCm Compute Profiler, ROCm, profiler, tool, Instinct, accelerator, AMD ******************** Profiling by example ******************** The following examples refer to sample :doc:`HIP ` code located in -:fab:`github` :dev-sample:`ROCm/omniperf/blob/amd-mainline/sample <>` and distributed -as part of Omniperf. +:fab:`github` :dev-sample:`ROCm/rocprofiler-compute/blob/amd-mainline/sample <>` +and distributed as part of ROCm Compute Profiler. .. include:: ./includes/valu-arithmetic-instruction-mix.rst diff --git a/docs/what-is-omniperf.rst b/docs/what-is-rocprof-compute.rst similarity index 70% rename from docs/what-is-omniperf.rst rename to docs/what-is-rocprof-compute.rst index 473be896f..6c660097d 100644 --- a/docs/what-is-omniperf.rst +++ b/docs/what-is-rocprof-compute.rst @@ -1,33 +1,33 @@ .. meta:: - :description: What is Omniperf? + :description: What is ROCm Compute Profiler? :keywords: Omniperf, ROCm, profiler, tool, Instinct, accelerator, AMD -***************** -What is Omniperf? -***************** +****************************** +What is ROCm Compute Profiler? +****************************** -Omniperf is a kernel-level profiling tool for machine learning and high +ROCm Compute Profiler is a kernel-level profiling tool for machine learning and high performance computing (HPC) workloads running on AMD Instinct™ accelerators. AMD Instinct MI-series accelerators are data center-class GPUs designed for -compute and have some graphics capabilities disabled or removed. Omniperf -primarily targets use with +compute and have some graphics capabilities disabled or removed. +ROCm Compute Profiler primarily targets use with :doc:`accelerators in the MI300, MI200, and MI100 families `. Development is in progress to support Radeon™ (RDNA) GPUs. -Omniperf is built on top of :doc:`ROCProfiler ` to +ROCm Compute Profiler is built on top of :doc:`ROCProfiler ` to monitor hardware performance counters. .. _high-level-design: -High-level design of Omniperf -============================= +High-level design +================= -The architecture of Omniperf consists of three major components shown in the +The architecture of ROCm Compute Profiler consists of three major components shown in the following diagram. -Core Omniperf profiler ----------------------- +Core ROCm Compute Profiler +-------------------------- Acquires raw performance counters via application replay using ``rocprof``. Counters are stored in a comma-separated-values format for further @@ -35,43 +35,43 @@ Counters are stored in a comma-separated-values format for further micro-benchmarks to acquire hierarchical roofline data. The roofline model is not available on accelerators pre-MI200. -Grafana server for Omniperf ---------------------------- +Grafana server for ROCm Compute Profiler +---------------------------------------- * **Grafana database import**: All raw performance counters are imported into a :ref:`backend MongoDB database ` to support analysis and visualization in the Grafana GUI. Compatibility with - previously generated data using older Omniperf versions is not guaranteed. + previously generated data using older ROCm Compute Profiler versions is not guaranteed. * **Grafana analysis dashboard GUI**: The :doc:`Grafana dashboard ` retrieves the raw counters information from the backend database. It displays the relevant performance metrics and visualization. -Omniperf standalone GUI analyzer --------------------------------- +ROCm Compute Profiler standalone GUI analyzer +--------------------------------------------- -Omniperf provides a :doc:`standalone GUI ` to +ROCm Compute Profiler provides a :doc:`standalone GUI ` to enable basic performance analysis without the need to import data into a database instance. Find setup instructions in :doc:`install/grafana-setup` .. image:: data/install/omniperf_server_vs_client_install.png :align: center - :alt: Architectural design of Omniperf + :alt: Architectural design of ROCm Compute Profiler :width: 800 -Omniperf features -================= +Features +======== -Omniperf offers comprehensive profiling based on all available hardware counters +ROCm Compute Profiler offers comprehensive profiling based on all available hardware counters for the target accelerator. It delivers advanced performance analysis features, such as system Speed-of-Light (SOL) and hardware block-level SOL evaluations. -Additionally, Omniperf provides in-depth memory chart analysis, roofline +Additionally, ROCm Compute Profiler provides in-depth memory chart analysis, roofline analysis, baseline comparisons, and more, ensuring a thorough understanding of system performance. -Omniperf supports analysis through both the :doc:`command line ` or a -:doc:`GUI `. The following list describes Omniperf's features at a +ROCm Compute Profiler supports analysis through both the :doc:`command line ` or a +:doc:`GUI `. The following list describes ROCm Compute Profiler's features at a high level. * :doc:`Support for AMD Instinct MI300, MI200, and MI100 accelerators ` @@ -107,8 +107,8 @@ high level. * :ref:`Scalar L1D Cache panel ` - * :ref:`L1 Address Processing Unit, or, Texture Addresser (TA) ` - and :ref:`L1 Backend Data Processing Unit, or, Texture Data (TD) ` panels + * :ref:`L1 Address Processing Unit or Texture Addresser (TA) `; + and :ref:`L1 Backend Data Processing Unit or Texture Data (TD) ` panels * :ref:`Vector L1D Cache panel ` @@ -127,3 +127,4 @@ high level. * :ref:`Baseline comparisons ` * :ref:`Multiple normalizations ` + diff --git a/grafana/Dockerfile b/grafana/Dockerfile index 2227f487f..6f7b7f049 100644 --- a/grafana/Dockerfile +++ b/grafana/Dockerfile @@ -1,6 +1,6 @@ # ----------------------------------------------------------------------- # NOTE: -# Dependencies are not included as part of Omniperf. +# Dependencies are not included as part of ROCm Compute Profiler. # It's the user's responsibility to accept any licensing implications # before building the project # ----------------------------------------------------------------------- @@ -15,7 +15,7 @@ ENV TZ "US/Chicago" ENV NVM_DIR /usr/local/nvm ENV NODE_VERSION 20.12.2 -ADD plugins/omniperf_plugin /var/lib/grafana/plugins/omniperf_plugin +ADD plugins/rocprofiler-compute_plugin /var/lib/grafana/plugins/rocprofiler-compute_plugin # Install Grafana and MongoDB Community Edition # Note: Grafana install is stubbed to 10.4.3 @@ -50,7 +50,7 @@ RUN apt-get install -y tzdata systemd apt-utils npm vim net-tools && \ /usr/sbin/grafana-cli plugins install grafana-image-renderer && \ /usr/sbin/grafana-cli plugins install aceiot-svg-panel && \ chown root:grafana /etc/grafana && \ - cd /var/lib/grafana/plugins/omniperf_plugin && \ + cd /var/lib/grafana/plugins/rocprofiler-compute_plugin && \ npm install && \ npm run build && \ apt-get autoremove -y && \ diff --git a/grafana/dashboards/Omniperf_v1.0.3_pub.json b/grafana/dashboards/RocProfCompute_v1.0.3_pub.json similarity index 99% rename from grafana/dashboards/Omniperf_v1.0.3_pub.json rename to grafana/dashboards/RocProfCompute_v1.0.3_pub.json index 5e4c480cc..270366cbe 100644 --- a/grafana/dashboards/Omniperf_v1.0.3_pub.json +++ b/grafana/dashboards/RocProfCompute_v1.0.3_pub.json @@ -32,7 +32,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -92,7 +92,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -103,7 +103,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -139,7 +139,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -151,7 +151,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -333,7 +333,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -344,7 +344,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -458,7 +458,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -543,7 +543,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "tlh8EwUnk" }, "rawQuery": true, @@ -571,7 +571,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -583,7 +583,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -641,7 +641,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "u5Z2zJhnk" }, "hide": false, @@ -1015,7 +1015,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "HV80ot2nz" }, "rawQuery": true, @@ -1437,7 +1437,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "HV80ot2nz" }, "rawQuery": true, @@ -1504,7 +1504,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -1516,7 +1516,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -1812,7 +1812,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "rawQuery": true, @@ -1822,7 +1822,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "hide": false, @@ -1833,7 +1833,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "hide": false, @@ -1844,7 +1844,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "hide": false, @@ -1855,7 +1855,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "hide": false, @@ -1890,7 +1890,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -1902,7 +1902,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -2488,7 +2488,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "rawQuery": true, @@ -2498,7 +2498,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -2509,7 +2509,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -2520,7 +2520,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -2531,7 +2531,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -2542,7 +2542,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -2553,7 +2553,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -2564,7 +2564,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -2575,7 +2575,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -2586,7 +2586,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "jYrBWHfnz" }, "hide": false, @@ -3175,7 +3175,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -3186,7 +3186,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -3197,7 +3197,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -3208,7 +3208,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -3219,7 +3219,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -3230,7 +3230,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -3241,7 +3241,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -3252,7 +3252,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "LJKvMZank" }, "hide": false, @@ -3263,7 +3263,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "jYrBWHfnz" }, "hide": false, @@ -3274,7 +3274,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "jYrBWHfnz" }, "hide": false, @@ -3292,7 +3292,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -3304,7 +3304,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -3390,7 +3390,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -3400,7 +3400,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -3595,7 +3595,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -3605,7 +3605,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -3658,7 +3658,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -3670,7 +3670,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -3829,7 +3829,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -3839,7 +3839,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4036,7 +4036,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -4046,7 +4046,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4098,7 +4098,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -4110,7 +4110,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -4306,7 +4306,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -4316,7 +4316,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4502,7 +4502,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4513,7 +4513,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4568,7 +4568,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -4580,7 +4580,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -4644,7 +4644,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -4654,7 +4654,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4735,7 +4735,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4746,7 +4746,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4825,7 +4825,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -4835,7 +4835,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4919,7 +4919,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -4929,7 +4929,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -4969,7 +4969,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -4981,7 +4981,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -5052,7 +5052,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -5062,7 +5062,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -5196,7 +5196,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "rawQuery": true, @@ -5206,7 +5206,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -5370,7 +5370,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -5380,7 +5380,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -5477,7 +5477,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "rawQuery": true, @@ -5487,7 +5487,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -5498,7 +5498,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -5509,7 +5509,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -5520,7 +5520,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -5531,7 +5531,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -5542,7 +5542,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -5553,7 +5553,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -5600,7 +5600,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -5612,7 +5612,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -5683,7 +5683,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -5693,7 +5693,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -5875,7 +5875,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -5886,7 +5886,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -5941,7 +5941,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -5953,7 +5953,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -6021,7 +6021,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -6031,7 +6031,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -6131,7 +6131,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "rawQuery": true, @@ -6141,7 +6141,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -6189,7 +6189,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -6201,7 +6201,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -6284,7 +6284,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -6295,7 +6295,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "sY628IJnz" }, "hide": false, @@ -6393,7 +6393,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -6404,7 +6404,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "bhNVuvBnk" }, "hide": false, @@ -6547,7 +6547,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -6558,7 +6558,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -6610,7 +6610,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -6622,7 +6622,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -6709,7 +6709,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -6719,7 +6719,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -6891,7 +6891,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -6901,7 +6901,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -6953,7 +6953,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -6965,7 +6965,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -7032,7 +7032,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -7042,7 +7042,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -7195,7 +7195,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -7205,7 +7205,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -7391,7 +7391,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -7402,7 +7402,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -7558,7 +7558,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "tlh8EwUnk" }, "rawQuery": true, @@ -7635,7 +7635,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -7645,7 +7645,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -7697,7 +7697,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -7709,7 +7709,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -7919,7 +7919,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -7929,7 +7929,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -8067,7 +8067,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -8077,7 +8077,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -8237,7 +8237,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -8248,7 +8248,7 @@ }, { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "hide": false, @@ -8403,7 +8403,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -8420,7 +8420,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -8432,7 +8432,7 @@ { "collapsed": true, "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "gridPos": { @@ -10245,7 +10245,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -10364,7 +10364,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "Zzw1yR27k" }, "rawQuery": true, @@ -12540,7 +12540,7 @@ "targets": [ { "datasource": { - "type": "amd-omniperf-data-plugin", + "type": "amd-rocprofiler-compute-data-plugin", "uid": "oVK0I__nk" }, "refId": "A" @@ -12737,8 +12737,8 @@ { "current": { "selected": false, - "text": "omniperf_asw_mixbench_mi200", - "value": "omniperf_asw_mixbench_mi200" + "text": "rocprofiler-compute_asw_mixbench_mi200", + "value": "rocprofiler-compute_asw_mixbench_mi200" }, "definition": "workload_names.names.aggregate([\n {\"$group\": {\n \"_id\": \"&name\"\n }}\n]);", "hide": 0, @@ -12883,8 +12883,8 @@ { "current": { "selected": false, - "text": "omniperf_asw_mixbench_mi200", - "value": "omniperf_asw_mixbench_mi200" + "text": "rocprofiler-compute_asw_mixbench_mi200", + "value": "rocprofiler-compute_asw_mixbench_mi200" }, "definition": "workload_names.names.aggregate([\n {\"$group\": {\n \"_id\": \"&name\"\n }}\n]);", "hide": 0, @@ -13318,8 +13318,8 @@ }, "timepicker": {}, "timezone": "", - "title": "Omniperf_v1.0.3_pub", - "uid": "Omniperf_v1_0_063020221", + "title": "rocprofiler-compute_v1.0.3_pub", + "uid": "rocprofiler-compute_v1_0_063020221", "version": 4, "weekStart": "" } \ No newline at end of file diff --git a/grafana/dashboards/Omniperf_v1.0.5_pub.json b/grafana/dashboards/RocProfCompute_v1.0.5_pub.json similarity index 99% rename from grafana/dashboards/Omniperf_v1.0.5_pub.json rename to grafana/dashboards/RocProfCompute_v1.0.5_pub.json index 4cbfd4a8e..d04333113 100644 --- a/grafana/dashboards/Omniperf_v1.0.5_pub.json +++ b/grafana/dashboards/RocProfCompute_v1.0.5_pub.json @@ -13324,7 +13324,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Omniperf_v1.0.5_pub", + "title": "rocprofiler-compute_v1.0.5_pub", "uid": "MIPerf_v1_0_0630202211", "version": 3, "weekStart": "" diff --git a/grafana/dashboards/Omniperf_v1.0.7_pub.json b/grafana/dashboards/RocProfCompute_v1.0.7_pub.json similarity index 99% rename from grafana/dashboards/Omniperf_v1.0.7_pub.json rename to grafana/dashboards/RocProfCompute_v1.0.7_pub.json index c4b089979..80e544f3a 100644 --- a/grafana/dashboards/Omniperf_v1.0.7_pub.json +++ b/grafana/dashboards/RocProfCompute_v1.0.7_pub.json @@ -12733,8 +12733,8 @@ { "current": { "selected": true, - "text": "omniperf_asw_mix_mi200", - "value": "omniperf_asw_mix_mi200" + "text": "rocprofiler-compute_asw_mix_mi200", + "value": "rocprofiler-compute_asw_mix_mi200" }, "definition": "workload_names.names.aggregate([\n {\"$group\": {\n \"_id\": \"&name\"\n }}\n]);", "hide": 0, @@ -13318,7 +13318,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Omniperf_v1.0.7_pub", + "title": "rocprofiler-compute_v1.0.7_pub", "uid": "MIPerf_v1_0_06302022112", "version": 2, "weekStart": "" diff --git a/grafana/dashboards/Omniperf_v1.0.8_pub.json b/grafana/dashboards/RocProfCompute_v1.0.8_pub.json similarity index 99% rename from grafana/dashboards/Omniperf_v1.0.8_pub.json rename to grafana/dashboards/RocProfCompute_v1.0.8_pub.json index 72df97ef3..570ad3110 100644 --- a/grafana/dashboards/Omniperf_v1.0.8_pub.json +++ b/grafana/dashboards/RocProfCompute_v1.0.8_pub.json @@ -12809,8 +12809,8 @@ { "current": { "selected": true, - "text": "omniperf_asw_mixbench_mi200", - "value": "omniperf_asw_mixbench_mi200" + "text": "rocprofiler-compute_asw_mixbench_mi200", + "value": "rocprofiler-compute_asw_mixbench_mi200" }, "definition": "workload_names.names.aggregate([\n {\"$group\": {\n \"_id\": \"&name\"\n }}\n]);", "hide": 0, @@ -12955,8 +12955,8 @@ { "current": { "selected": true, - "text": "omniperf_asw_mixbench_mi200", - "value": "omniperf_asw_mixbench_mi200" + "text": "rocprofiler-compute_asw_mixbench_mi200", + "value": "rocprofiler-compute_asw_mixbench_mi200" }, "definition": "workload_names.names.aggregate([\n {\"$group\": {\n \"_id\": \"&name\"\n }}\n]);", "hide": 0, @@ -13390,7 +13390,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Omniperf_v1.0.8_pub", + "title": "rocprofiler-compute_v1.0.8_pub", "uid": "MIPerf_v1_0_0630202211210", "version": 4, "weekStart": "" diff --git a/grafana/dashboards/Omniperf_v2.0.0_pub.json b/grafana/dashboards/RocProfCompute_v2.0.0_pub.json similarity index 99% rename from grafana/dashboards/Omniperf_v2.0.0_pub.json rename to grafana/dashboards/RocProfCompute_v2.0.0_pub.json index 603d52ed7..1e0cd46ee 100644 --- a/grafana/dashboards/Omniperf_v2.0.0_pub.json +++ b/grafana/dashboards/RocProfCompute_v2.0.0_pub.json @@ -12827,8 +12827,8 @@ { "current": { "selected": true, - "text": "omniperf_pymongo4_Vcopy_gfx90a", - "value": "omniperf_pymongo4_Vcopy_gfx90a" + "text": "rocprofiler-compute_pymongo4_Vcopy_gfx90a", + "value": "rocprofiler-compute_pymongo4_Vcopy_gfx90a" }, "definition": "workload_names.names.aggregate([\n {\"$group\": {\n \"_id\": \"&name\"\n }}\n]);", "hide": 0, @@ -12973,8 +12973,8 @@ { "current": { "selected": false, - "text": "omniperf_pymongo4_Vcopy_gfx908", - "value": "omniperf_pymongo4_Vcopy_gfx908" + "text": "rocprofiler-compute_pymongo4_Vcopy_gfx908", + "value": "rocprofiler-compute_pymongo4_Vcopy_gfx908" }, "definition": "workload_names.names.aggregate([\n {\"$group\": {\n \"_id\": \"&name\"\n }}\n]);", "hide": 0, @@ -13408,8 +13408,8 @@ }, "timepicker": {}, "timezone": "", - "title": "Omniperf_v2.0_pubx", - "uid": "Omniperf_v20x", + "title": "rocprofiler-compute_v2.0_pubx", + "uid": "rocprofiler-compute_v20x", "version": 2, "weekStart": "" } \ No newline at end of file diff --git a/grafana/docker-compose.yml b/grafana/docker-compose.yml index 34e03d277..38c3ebd9b 100644 --- a/grafana/docker-compose.yml +++ b/grafana/docker-compose.yml @@ -1,6 +1,6 @@ # ----------------------------------------------------------------------- # NOTE: -# Dependencies are not included as part of Omniperf. +# Dependencies are not included as part of ROCm Compute Profiler. # It's the user's responsibility to accept any licensing implications # before building the project # ----------------------------------------------------------------------- @@ -9,13 +9,13 @@ version: "3.3" services: web: - image: omniperf-grafana-v1.0 - container_name: omniperf-grafana-v1.0 + image: rocprofiler-compute-grafana-v1.0 + container_name: rocprofiler-compute-grafana-v1.0 restart: always build: . environment: - GF_PATHS_CONFIG="grafana/etc/grafana.ini" - - GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=amd-omniperf-data-plugin + - GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=amd-rocprofiler-compute-data-plugin - GF_DEFAULT_APP_MODE=development ports: - "14000:4000" diff --git a/grafana/docker-entrypoint.sh b/grafana/docker-entrypoint.sh index 57ae8fa74..be92ccf6e 100755 --- a/grafana/docker-entrypoint.sh +++ b/grafana/docker-entrypoint.sh @@ -24,7 +24,7 @@ # SOFTWARE. ##############################################################################el -pushd /var/lib/grafana/plugins/omniperf_plugin +pushd /var/lib/grafana/plugins/rocprofiler-compute_plugin npm run server & popd diff --git a/grafana/grafana.ini b/grafana/grafana.ini index fcf8b42b0..d2e07ed15 100644 --- a/grafana/grafana.ini +++ b/grafana/grafana.ini @@ -874,7 +874,7 @@ max_days = 7 ;enable_alpha = false ;app_tls_skip_verify_insecure = false # Enter a comma-separated list of plugin identifiers to identify plugins to load even if they are unsigned. Plugins with modified signatures are never loaded. -allow_loading_unsigned_plugins = amd-custom-svg, amd-omniperf-data-plugin +allow_loading_unsigned_plugins = amd-custom-svg, amd-rocprofiler-compute-data-plugin # Enable or disable installing plugins directly from within Grafana. ;plugin_admin_enabled = false ;plugin_admin_external_manage_enabled = false diff --git a/grafana/plugins/omniperf_plugin/README.md b/grafana/plugins/omniperf_plugin/README.md index 32974100e..e8f47590a 100644 --- a/grafana/plugins/omniperf_plugin/README.md +++ b/grafana/plugins/omniperf_plugin/README.md @@ -1,6 +1,6 @@ -# Omniperf Data Source Plugin +# ROCm Compute Profiler Data Source Plugin -This plugin allows users of Omniperf to connect their MongoDB database to for visualization in Grafana +This plugin allows users of ROCm Compute Profiler to connect their MongoDB database to for visualization in Grafana ## Info diff --git a/grafana/plugins/omniperf_plugin/package.json b/grafana/plugins/omniperf_plugin/package.json index 36c6c420f..e68745895 100644 --- a/grafana/plugins/omniperf_plugin/package.json +++ b/grafana/plugins/omniperf_plugin/package.json @@ -1,5 +1,5 @@ { - "name": "amd-omniperf-data-plugin", + "name": "amd-rocprofiler-compute-data-plugin", "version": "1.0.0", "description": "", "main": "server/mongo-proxy.js", @@ -39,5 +39,5 @@ "mongodb": "^4.12.1", "statman-stopwatch": "^2.7.0" }, - "_comments": "Dependencies are not included as part of Omniperf. It's the user's responsibility to accept any licensing implications before building the project." + "_comments": "Dependencies are not included as part of ROCm Compute Profiler. It's the user's responsibility to accept any licensing implications before building the project." } diff --git a/grafana/plugins/omniperf_plugin/server/mongo-proxy.js b/grafana/plugins/omniperf_plugin/server/mongo-proxy.js index 8fb4df075..04a489106 100644 --- a/grafana/plugins/omniperf_plugin/server/mongo-proxy.js +++ b/grafana/plugins/omniperf_plugin/server/mongo-proxy.js @@ -398,7 +398,7 @@ function runAggregateQuery( requestId, queryId, body, queryArgs, res, next ) results = getTimeseriesResults(docs) } - // This is where omniperf will go for most results + // This is where rocprofiler-compute will go for most results else { results = getTableResults(docs) diff --git a/grafana/plugins/omniperf_plugin/src/img/omniperf_circle.png b/grafana/plugins/omniperf_plugin/src/img/rocprofiler-compute_circle.png similarity index 100% rename from grafana/plugins/omniperf_plugin/src/img/omniperf_circle.png rename to grafana/plugins/omniperf_plugin/src/img/rocprofiler-compute_circle.png diff --git a/grafana/plugins/omniperf_plugin/src/plugin.json b/grafana/plugins/omniperf_plugin/src/plugin.json index 90647f764..204e6574b 100644 --- a/grafana/plugins/omniperf_plugin/src/plugin.json +++ b/grafana/plugins/omniperf_plugin/src/plugin.json @@ -1,6 +1,6 @@ { - "name": "Omniperf Data", - "id": "amd-omniperf-data-plugin", + "name": "ROCm Compute Profiler Data", + "id": "amd-rocprofiler-compute-data-plugin", "type": "datasource", "backend": true, "partials": { @@ -9,14 +9,14 @@ "metrics": true, "annotations": false, "info": { - "description": "An Omniperf datasource build for MongoDB", + "description": "An ROCm Compute Profiler datasource build for MongoDB", "author": { "name": "Audacious Software Group", "url": "" }, "logos": { - "small": "img/omniperf_circle.png", - "large": "img/omniperf_circle.png" + "small": "img/rocprofiler-compute_circle.png", + "large": "img/rocprofiler-compute_circle.png" }, "version": "%VERSION%", "updated": "%TODAY%" diff --git a/pyproject.toml b/pyproject.toml index d470c6367..478ea4da8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ exclude = ''' | external | .pytest_cache | build - | build-omniperf + | build-rocprof_compute )/ ) ''' @@ -29,9 +29,9 @@ addopts = [ pythonpath = [ ".", "src", - "src/omniperf_soc", + "src/rocprof_compute_soc", "src/utils", - "src/omniperf_analyze/utils", + "src/rocprof_compute_analyze/utils", "tests" ] diff --git a/src/README.md b/src/README.md index dc3b92a4c..2aacb888d 100644 --- a/src/README.md +++ b/src/README.md @@ -1,6 +1,6 @@ -This directory contains all the source code files for the Omniperf project. -The top-level `omniperf` executable is the entry point and defines the flow for subsequent execution modes. +This directory contains all the source code files for the ROCm Compute Profiler project. +The top-level `rocprof-compute` executable is the entry point and defines the flow for subsequent execution modes. -To build Omniperf as a developer (from source) please add this directory to `PATH`. -You will find utilities and logic specific to Omniperf's different execution modes in their +To build ROCm Compute Profiler as a developer (from source) please add this directory to `PATH`. +You will find utilities and logic specific to ROCm Compute Profiler's different execution modes in their respective subdirectories. \ No newline at end of file diff --git a/src/argparser.py b/src/argparser.py index 1e02a849f..7d45e6eb8 100644 --- a/src/argparser.py +++ b/src/argparser.py @@ -34,11 +34,14 @@ def print_avail_arch(avail_arch: list): return ret_str -def add_general_group(parser, omniperf_version): +def add_general_group(parser, rocprof_compute_version): general_group = parser.add_argument_group("General Options") general_group.add_argument( - "-v", "--version", action="version", version=omniperf_version["ver_pretty"] + "-v", + "--version", + action="version", + version=rocprof_compute_version["ver_pretty"], ) general_group.add_argument( "-V", @@ -57,14 +60,16 @@ def add_general_group(parser, omniperf_version): ) -def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): +def omniarg_parser( + parser, rocprof_compute_home, supported_archs, rocprof_compute_version +): # ----------------------------------------- # Parse arguments (dependent on mode) # ----------------------------------------- ## General Command Line Options ## ---------------------------- - add_general_group(parser, omniperf_version) + add_general_group(parser, rocprof_compute_version) parser._positionals.title = "Modes" parser._optionals.title = "Help" @@ -79,15 +84,15 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): help="Profile the target application", usage=""" -omniperf profile --name [profile options] [roofline options] -- +rocprof-compute profile --name [profile options] [roofline options] -- --------------------------------------------------------------------------------- Examples: -\tomniperf profile -n vcopy_all -- ./vcopy -n 1048576 -b 256 -\tomniperf profile -n vcopy_SPI_TCC -b SQ TCC -- ./vcopy -n 1048576 -b 256 -\tomniperf profile -n vcopy_kernel -k vecCopy -- ./vcopy -n 1048576 -b 256 -\tomniperf profile -n vcopy_disp -d 0 -- ./vcopy -n 1048576 -b 256 -\tomniperf profile -n vcopy_roof --roof-only -- ./vcopy -n 1048576 -b 256 +\trocprof-compute profile -n vcopy_all -- ./vcopy -n 1048576 -b 256 +\trocprof-compute profile -n vcopy_SPI_TCC -b SQ TCC -- ./vcopy -n 1048576 -b 256 +\trocprof-compute profile -n vcopy_kernel -k vecCopy -- ./vcopy -n 1048576 -b 256 +\trocprof-compute profile -n vcopy_disp -d 0 -- ./vcopy -n 1048576 -b 256 +\trocprof-compute profile -n vcopy_roof --roof-only -- ./vcopy -n 1048576 -b 256 --------------------------------------------------------------------------------- """, prog="tool", @@ -98,7 +103,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): ) profile_parser._optionals.title = "Help" - add_general_group(profile_parser, omniperf_version) + add_general_group(profile_parser, rocprof_compute_version) profile_group = profile_parser.add_argument_group("Profile Options") roofline_group = profile_parser.add_argument_group("Standalone Roofline Options") @@ -194,7 +199,10 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): "--use-rocscope", default=False, dest="use_rocscope", help=argparse.SUPPRESS ) profile_group.add_argument( - "--kernel-summaries", default=False, dest="summaries", help=argparse.SUPPRESS + "--kernel-summaries", + default=False, + dest="summaries", + help=argparse.SUPPRESS, ) profile_group.add_argument( "--join-type", @@ -272,14 +280,14 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): ## ---------------------------- db_parser = subparsers.add_parser( "database", - help="Interact with Omniperf database", + help="Interact with rocprofiler-compute database", usage=""" - \nomniperf database [connection options] + \nrocprof-compute database [connection options] \n\n------------------------------------------------------------------------------- \nExamples: - \n\tomniperf database --import -H pavii1 -u temp -t asw -w workloads/vcopy/mi200/ - \n\tomniperf database --remove -H pavii1 -u temp -w omniperf_asw_sample_mi200 + \n\trocprof-compute database --import -H pavii1 -u temp -t asw -w workloads/vcopy/mi200/ + \n\trocprof-compute database --remove -H pavii1 -u temp -w rocprofiler-compute_asw_sample_mi200 \n-------------------------------------------------------------------------------\n """, prog="tool", @@ -290,7 +298,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): ) db_parser._optionals.title = "Help" - add_general_group(db_parser, omniperf_version) + add_general_group(db_parser, rocprof_compute_version) interaction_group = db_parser.add_argument_group("Interaction Type") connection_group = db_parser.add_argument_group("Connection Options") @@ -300,7 +308,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): required=False, dest="upload", action="store_true", - help="\t\t\t\tImport workload to Omniperf DB", + help="\t\t\t\tImport workload to rocprofiler-compute DB", ) interaction_group.add_argument( "-r", @@ -308,7 +316,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): required=False, dest="remove", action="store_true", - help="\t\t\t\tRemove a workload from Omniperf DB", + help="\t\t\t\tRemove a workload from rocprofiler-compute DB", ) connection_group.add_argument( @@ -366,13 +374,13 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): "analyze", help="Analyze existing profiling results at command line", usage=""" -omniperf analyze --path [analyze options] +rocprof-compute analyze --path [analyze options] ----------------------------------------------------------------------------------- Examples: -\tomniperf analyze -p workloads/vcopy/mi200/ --list-metrics gfx90a -\tomniperf analyze -p workloads/mixbench/mi200/ --dispatch 12 34 --decimal 3 -\tomniperf analyze -p workloads/mixbench/mi200/ --gui +\trocprof-compute analyze -p workloads/vcopy/mi200/ --list-metrics gfx90a +\trocprof-compute analyze -p workloads/mixbench/mi200/ --dispatch 12 34 --decimal 3 +\trocprof-compute analyze -p workloads/mixbench/mi200/ --gui ----------------------------------------------------------------------------------- """, prog="tool", @@ -383,7 +391,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): ) analyze_parser._optionals.title = "Help" - add_general_group(analyze_parser, omniperf_version) + add_general_group(analyze_parser, rocprof_compute_version) analyze_group = analyze_parser.add_argument_group("Analyze Options") analyze_advanced_group = analyze_parser.add_argument_group("Advanced Options") @@ -454,7 +462,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): type=int, nargs="?", const=8050, - help="\t\tActivate a GUI to interate with Omniperf metrics.\n\t\tOptionally, specify port to launch application (DEFAULT: 8050)", + help="\t\tActivate a GUI to interate with rocprofiler-compute metrics.\n\t\tOptionally, specify port to launch application (DEFAULT: 8050)", ) analyze_advanced_group.add_argument( "--random-port", @@ -499,7 +507,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): dest="config_dir", metavar="", help="\t\tSpecify the directory of customized configs.", - default=omniperf_home.joinpath("omniperf_soc/analysis_configs/"), + default=rocprof_compute_home.joinpath("rocprof_compute_soc/analysis_configs/"), ) analyze_advanced_group.add_argument( "--save-dfs", @@ -519,7 +527,9 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version): "-g", dest="debug", action="store_true", help="\t\tDebug single metric." ) analyze_advanced_group.add_argument( - "--dependency", action="store_true", help="\t\tList the installation dependency." + "--dependency", + action="store_true", + help="\t\tList the installation dependency.", ) analyze_advanced_group.add_argument( "--kernel-verbose", diff --git a/src/config.py b/src/config.py index 6cd07ff1c..1caed5029 100644 --- a/src/config.py +++ b/src/config.py @@ -25,5 +25,5 @@ from pathlib import Path # NB: Creating a new module to share global vars across modules -omniperf_home = Path(__file__).resolve().parent -prog = "omniperf" +rocprof_compute_home = Path(__file__).resolve().parent +prog = "rocprofiler-compute" diff --git a/src/omniperf b/src/rocprof-compute similarity index 89% rename from src/omniperf rename to src/rocprof-compute index 1acff5f07..c8d2d0ee6 100755 --- a/src/omniperf +++ b/src/rocprof-compute @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -"""Main entry point for omniperf""" +"""Main entry point for rocprof-compute""" ##############################################################################bl # MIT License @@ -34,7 +34,7 @@ import re try: from pathlib import Path from importlib import metadata - from omniperf_base import Omniperf + from rocprof_compute_base import RocProfCompute from utils.utils import console_error except ImportError as e: # print("Failed to import required modules: " + str(e)) @@ -61,12 +61,12 @@ def verify_deps_version(localVer, desiredVer, operator): def verify_deps(): """Utility to read library dependencies from requirements.txt and endeavor to load them within current execution environment. - Used in top-level omniperf to provide error messages if necessary + Used in top-level rocprofiler-compute to provide error messages if necessary dependencies are not available.""" # Check which version of python is being used if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 8): - print("[ERROR] Python 3.8 or higher is required to run omniperf." + print("[ERROR] Python 3.8 or higher is required to run rocprofiler-compute." f" The current version is {sys.version_info[0]}.{sys.version_info[1]}.") sys.exit(1) @@ -108,7 +108,7 @@ def verify_deps(): ): print( f"[ERROR] the '{dependency}' distribution does " - "not meet version requirements to use omniperf." + "not meet version requirements to use rocprofiler-compute." ) print(" --> version installed :", localVersion) error = True @@ -119,7 +119,7 @@ def verify_deps(): "Please verify all of the python dependencies called out " "in the requirements file" ) - print("are installed locally prior to running omniperf.") + print("are installed locally prior to running rocprofiler-compute.") print("") print(f"See: {checkFile}") sys.exit(1) @@ -132,17 +132,17 @@ def main(): # verify required python dependencies verify_deps() - omniperf = Omniperf() + rocprof_compute = RocProfCompute() - mode = omniperf.get_mode() + mode = rocprof_compute.get_mode() - # major omniperf execution modes + # major rocprofiler-compute execution modes if mode == "profile": - omniperf.run_profiler() + rocprof_compute.run_profiler() elif mode == "database": - omniperf.update_db() + rocprof_compute.update_db() elif mode == "analyze": - omniperf.run_analysis() + rocprof_compute.run_analysis() else: console_error("Unsupported execution mode") diff --git a/src/omniperf_analyze/analysis_base.py b/src/rocprof_compute_analyze/analysis_base.py similarity index 99% rename from src/omniperf_analyze/analysis_base.py rename to src/rocprof_compute_analyze/analysis_base.py index c80489972..b1fad7712 100644 --- a/src/omniperf_analyze/analysis_base.py +++ b/src/rocprof_compute_analyze/analysis_base.py @@ -200,7 +200,7 @@ def sanitize(self): def pre_processing(self): """Perform initialization prior to analysis.""" console_debug("analysis", "prepping to do some analysis") - console_log("analysis", "deriving Omniperf metrics...") + console_log("analysis", "deriving rocprofiler-compute metrics...") # initalize output file self._output = ( open(self.__args.output_file, "w+") if self.__args.output_file else sys.stdout diff --git a/src/omniperf_analyze/analysis_cli.py b/src/rocprof_compute_analyze/analysis_cli.py similarity index 98% rename from src/omniperf_analyze/analysis_cli.py rename to src/rocprof_compute_analyze/analysis_cli.py index 36fbbf8c5..f3276c476 100644 --- a/src/omniperf_analyze/analysis_cli.py +++ b/src/rocprof_compute_analyze/analysis_cli.py @@ -22,7 +22,7 @@ # SOFTWARE. ##############################################################################el -from omniperf_analyze.analysis_base import OmniAnalyze_Base +from rocprof_compute_analyze.analysis_base import OmniAnalyze_Base from utils.utils import demarcate, console_error from utils import file_io, parser, tty from utils.kernel_name_shortener import kernel_name_shortener diff --git a/src/omniperf_analyze/analysis_webui.py b/src/rocprof_compute_analyze/analysis_webui.py similarity index 98% rename from src/omniperf_analyze/analysis_webui.py rename to src/rocprof_compute_analyze/analysis_webui.py index 54645cbbb..883763237 100644 --- a/src/omniperf_analyze/analysis_webui.py +++ b/src/rocprof_compute_analyze/analysis_webui.py @@ -22,7 +22,7 @@ # SOFTWARE. ##############################################################################el -from omniperf_analyze.analysis_base import OmniAnalyze_Base +from rocprof_compute_analyze.analysis_base import OmniAnalyze_Base from utils.utils import demarcate, console_debug, console_error from utils import file_io, parser from utils.gui import build_bar_chart, build_table_chart @@ -37,10 +37,15 @@ from dash.dependencies import Input, Output, State +PROJECT_NAME = "rocprofiler-compute" + + class webui_analysis(OmniAnalyze_Base): def __init__(self, args, supported_archs): super().__init__(args, supported_archs) - self.app = dash.Dash(__name__, external_stylesheets=[dbc.themes.CYBORG]) + self.app = dash.Dash( + __name__, title=PROJECT_NAME, external_stylesheets=[dbc.themes.CYBORG] + ) self.dest_dir = os.path.abspath(args.path[0][0]) self.arch = None diff --git a/src/omniperf_analyze/assets/default.css b/src/rocprof_compute_analyze/assets/default.css similarity index 100% rename from src/omniperf_analyze/assets/default.css rename to src/rocprof_compute_analyze/assets/default.css diff --git a/src/rocprof_compute_analyze/assets/favicon.ico b/src/rocprof_compute_analyze/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3f148e32b590c977e982e2017538baa9dad47a3b GIT binary patch literal 1150 zcmbu5F%E)25Jf+Ui7l12rKP1MNAL)gmL9-@&SP){k6>x(73?gv(@K0BGKP==Rv7Xa z@^}894N}6BrsBQSZYC`xtpEw7)@c%FPE}|g4`;S5tvkGy*OxKm?aPSudKvk^orCA> za6*gS%cxr!s@=)@)zMrtV%9O+&iL0K=9?K~{LPH9e#@BR-(oI0DADb|TSxj;&X?)2 s-OT$D-moK739 is required to run.\nomniperf profile -n test -- " + "An is required to run.\rrocprof-compute profile -n test -- " ) # TODO: Add an equivelent of characterize_app() to run profiling directly out of this module @@ -427,7 +427,7 @@ def profile(self): else: mibench(self.__args, self.__mspec) - # NB: Currently the post_prossesing() method is the only one being used by omniperf, + # NB: Currently the post_prossesing() method is the only one being used by rocprofiler-compute, # we include pre_processing() and profile() methods for those who wish to borrow the roofline module @abstractmethod def post_processing(self): diff --git a/src/utils/db_connector.py b/src/utils/db_connector.py index 195ff6be8..4216e01a3 100644 --- a/src/utils/db_connector.py +++ b/src/utils/db_connector.py @@ -79,7 +79,12 @@ def prep_import(self): ) self.connection_info["db"] = ( - "omniperf_" + str(self.args.team) + "_" + str(name) + "_" + str(soc) + "rocprofiler-compute_" + + str(self.args.team) + + "_" + + str(name) + + "_" + + str(soc) ) @demarcate @@ -157,7 +162,7 @@ def pre_processing(self): is_full_workload_name = self.args.workload.count("_") >= 3 if not is_full_workload_name: console_error( - "-w/--workload is not valid. Please use full workload name as seen in GUI when removing (i.e. omniperf_asw_vcopy_mi200)" + "-w/--workload is not valid. Please use full workload name as seen in GUI when removing (i.e. rocprofiler-compute_asw_vcopy_mi200)" ) if ( self.connection_info["host"] == None diff --git a/src/utils/gui_components/header.py b/src/utils/gui_components/header.py index d8255ae46..7e6a3811a 100644 --- a/src/utils/gui_components/header.py +++ b/src/utils/gui_components/header.py @@ -299,7 +299,7 @@ def get_header(raw_pmc, input_filters, kernel_names): children=[ # Report bug button html.A( - href="https://github.com/ROCm/omniperf/issues", + href="https://github.com/ROCm/rocprofiler-compute/issues", children=[ html.Button( className="report", diff --git a/src/utils/logger.py b/src/utils/logger.py index dae4a7a25..b6285ba00 100644 --- a/src/utils/logger.py +++ b/src/utils/logger.py @@ -83,8 +83,8 @@ def setup_console_handler(): setattr(logging, "trace", trace_logger) color_setting = 1 - if "OMNIPERF_COLOR" in os.environ.keys(): - color_setting = int(os.environ["OMNIPERF_COLOR"]) + if "ROCPROFCOMPUTE_COLOR" in os.environ.keys(): + color_setting = int(os.environ["ROCPROFCOMPUTE_COLOR"]) if color_setting == 0: # non-colored @@ -99,7 +99,7 @@ def setup_console_handler(): # no color or levelname for INFO, other log messages entirely in color formatter = ColoredFormatterAll() else: - print("Unsupported setting for OMNIPERF_COLOR - set to 0, 1, 2 or 3.") + print("Unsupported setting for ROCPROFCOMPUTE_COLOR - set to 0, 1, 2 or 3.") sys.exit(1) console_handler = logging.StreamHandler(sys.stdout) @@ -130,8 +130,8 @@ def setup_logging_priority(verbosity, quietmode, appmode): loglevel = levels[min(verbosity, len(levels) - 1)] # cap to last level index # optional: override of default loglevel via env variable which takes precedence - if "OMNIPERF_LOGLEVEL" in os.environ.keys(): - loglevel = os.environ["OMNIPERF_LOGLEVEL"] + if "ROCPROFCOMPUTE_LOGLEVEL" in os.environ.keys(): + loglevel = os.environ["ROCPROFCOMPUTE_LOGLEVEL"] if loglevel in {"DEBUG", "debug"}: loglevel = logging.DEBUG elif loglevel in {"TRACE", "trace"}: @@ -141,7 +141,7 @@ def setup_logging_priority(verbosity, quietmode, appmode): elif loglevel in {"ERROR", "error"}: loglevel = logging.ERROR else: - print("Ignoring unsupported OMNIPERF_LOGLEVEL setting (%s)" % loglevel) + print("Ignoring unsupported ROCPROFCOMPUTE_LOGLEVEL setting (%s)" % loglevel) sys.exit(1) # update console loglevel based on command-line args/env settings diff --git a/src/utils/mem_chart.py b/src/utils/mem_chart.py index 8a4dcf1f8..0bf922625 100644 --- a/src/utils/mem_chart.py +++ b/src/utils/mem_chart.py @@ -178,7 +178,9 @@ def draw(self, canvas): ) canvas.text(self.x_min + 4.0, self.y_max - 13.0, "LDS Alloc:") canvas.text( - self.x_min + 4.0, self.y_max - 14.0, "{val:>13.0f}".format(val=self.lds_alloc) + self.x_min + 4.0, + self.y_max - 14.0, + "{val:>13.0f}".format(val=self.lds_alloc), ) canvas.rect( diff --git a/src/utils/resources.py b/src/utils/resources.py index 198684261..634174e93 100644 --- a/src/utils/resources.py +++ b/src/utils/resources.py @@ -30,6 +30,6 @@ def get_resource_path(relative_path): rel_path = pathlib.Path(relative_path) dev_base_path = ( pathlib.Path(__file__).resolve().parent.parent.parent.parent - ) # omniperf dir (whereas equiv comd in omniperf.py returns src dir) + ) # rocprof_compute dir (whereas equiv comd in rocprof_compute.py returns src dir) base_path = getattr(sys, "_MEIPASS", dev_base_path) return dev_base_path diff --git a/src/utils/specs.py b/src/utils/specs.py index 07938bcf1..2ea0b64bb 100644 --- a/src/utils/specs.py +++ b/src/utils/specs.py @@ -58,7 +58,7 @@ def detect_arch(_rocminfo): - from omniperf_base import SUPPORTED_ARCHS + from rocprof_compute_base import SUPPORTED_ARCHS for idx1, linetext in enumerate(_rocminfo): gpu_arch = search(r"^\s*Name\s*:\s+ ([a-zA-Z0-9]+)\s*$", linetext) @@ -91,9 +91,9 @@ def generate_machine_specs(args, sysinfo: dict = None): console_error( "Detected mismatch in sysinfo versioning. You need to reprofile to update data." ) - version = get_version(config.omniperf_home)["version"] + version = get_version(config.rocprof_compute_home)["version"] if sysinfo_ver != version[: version.find(".")]: - console_error( + console_warning( "Detected mismatch in sysinfo versioning. You need to reprofile to update data." ) return MachineSpecs(**sysinfo) @@ -106,7 +106,7 @@ def generate_machine_specs(args, sysinfo: dict = None): hostname = socket.gethostname() # set specs version - vData = get_version(config.omniperf_home) + vData = get_version(config.rocprof_compute_home) version = vData["version"] # NB: Just taking major as specs version. May want to make this more specific in the future specs_version = version[ @@ -174,7 +174,7 @@ def generate_machine_specs(args, sysinfo: dict = None): ) # Load above SoC specs via module import try: - soc_module = importlib.import_module("omniperf_soc.soc_" + specs.gpu_arch) + soc_module = importlib.import_module("rocprof_compute_soc.soc_" + specs.gpu_arch) except ModuleNotFoundError as e: console_error( "Arch %s marked as supported, but couldn't find class implementation %s." @@ -253,7 +253,8 @@ class MachineSpecs: ## A. Machine Specs ########################################## hostname: str = field( - default=None, metadata={"doc": "The hostname of the machine.", "name": "Hostname"} + default=None, + metadata={"doc": "The hostname of the machine.", "name": "Hostname"}, ) cpu_model: str = field( default=None, @@ -547,7 +548,7 @@ def get_class_members(self): return pd.DataFrame(data, index=[0]) def __repr__(self): - topstr = "Machine Specifications: describing the state of the machine that Omniperf data was collected on.\n" + topstr = "Machine Specifications: describing the state of the machine that ROCm Compute Profiler data was collected on.\n" data = [] for field in fields(self): name = field.name diff --git a/src/utils/utils.py b/src/utils/utils.py index a4b1a10b3..825ec4c97 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -87,12 +87,12 @@ def trace_logger(message, *args, **kwargs): logging.log(logging.TRACE, message, *args, **kwargs) -def get_version(omniperf_home) -> dict: - """Return Omniperf versioning info""" +def get_version(rocprof_compute_home) -> dict: + """Return ROCm Compute Profiler versioning info""" # symantic version info - note that version file(s) can reside in # two locations depending on development vs formal install - searchDirs = [omniperf_home, omniperf_home.parent] + searchDirs = [rocprof_compute_home, rocprof_compute_home.parent] found = False versionDir = None @@ -110,7 +110,7 @@ def get_version(omniperf_home) -> dict: console_error("Cannot find VERSION file at {}".format(searchDirs)) # git version info - gitDir = os.path.join(omniperf_home.parent, ".git") + gitDir = os.path.join(rocprof_compute_home.parent, ".git") if (shutil.which("git") is not None) and os.path.exists(gitDir): gitQuery = subprocess.run( ["git", "log", "--pretty=format:%h", "-n", "1"], @@ -142,7 +142,7 @@ def get_version_display(version, sha, mode): """Pretty print versioning info""" buf = io.StringIO() print("-" * 40, file=buf) - print("Omniperf version: %s (%s)" % (version, mode), file=buf) + print("rocprofiler-compute version: %s (%s)" % (version, mode), file=buf) print("Git revision: %s" % sha, file=buf) print("-" * 40, file=buf) return buf.getvalue() @@ -396,7 +396,11 @@ def detect_roofline(mspec): rooflineBinary = os.environ["ROOFLINE_BIN"] if os.path.exists(rooflineBinary): console_warning("roofline", "Detected user-supplied binary") - return {"rocm_ver": "override", "distro": "override", "path": rooflineBinary} + return { + "rocm_ver": "override", + "distro": "override", + "path": rooflineBinary, + } else: msg = "user-supplied path to binary not accessible" msg += "--> ROOFLINE_BIN = %s\n" % target_binary @@ -466,8 +470,8 @@ def mibench(args, mspec): # check two potential locations for roofline binaries due to differences in # development usage vs formal install potential_paths = [ - "%s/utils/rooflines/roofline" % config.omniperf_home, - "%s/bin/roofline" % config.omniperf_home.parent.parent, + "%s/utils/rooflines/roofline" % config.rocprof_compute_home, + "%s/bin/roofline" % config.rocprof_compute_home.parent.parent, ] for dir in potential_paths: diff --git a/tests/4gpus.json b/tests/4gpus.json index e2cac33e2..6c59d23c4 100644 --- a/tests/4gpus.json +++ b/tests/4gpus.json @@ -1,24 +1,15 @@ { - "version": { - "major": 1, - "minor": 0 - }, - "local": [ - { - "gpus": [ - { - "id": "0", - }, - { - "id": "1" - }, - { - "id": "2" - }, - { - "id": "3" - } - ] - } - ] + "version": {"major": 1, "minor": 0}, + "local": [ + { + "gpus": [ + { + "id": "0", + }, + {"id": "1"}, + {"id": "2"}, + {"id": "3"}, + ] + } + ], } diff --git a/tests/generate_test_analyze_workloads.py b/tests/generate_test_analyze_workloads.py index 58e2b9f6f..03fe62e78 100644 --- a/tests/generate_test_analyze_workloads.py +++ b/tests/generate_test_analyze_workloads.py @@ -27,11 +27,11 @@ + arch + "():" + "\n\twith pytest.raises(SystemExit) as e:" - + "\n\t\twith patch('sys.argv',['omniperf', 'analyze', '--path', '" + + "\n\t\twith patch('sys.argv',['rocprof-compute', 'analyze', '--path', '" + workload + "/" + arch - + "']):\n\t\t\tomniperf.main()" + + "']):\n\t\t\trocprof_compute.main()" + "\n\tassert e.value.code == 0" ) f.write(test) diff --git a/tests/generate_workloads.sh b/tests/generate_workloads.sh index e57b06b1a..478d4b8e2 100755 --- a/tests/generate_workloads.sh +++ b/tests/generate_workloads.sh @@ -56,6 +56,6 @@ echo "starting" for key in "${!commands[@]}"; do echo profiling $key; command="${commands[$key]}" - echo "$key = ./src/omniperf profile -n $key ${dirs[@]}" - ./src/omniperf profile -n $key $command -p tests/workloads/$key/$soc -- ./tests/vcopy -n 1048576 -b 256 -i 3 ; + echo "$key = ./src/rocprof-compute profile -n $key ${dirs[@]}" + ./src/rocprof-compute profile -n $key $command -p tests/workloads/$key/$soc -- ./tests/vcopy -n 1048576 -b 256 -i 3 ; echo "done" ; done \ No newline at end of file diff --git a/tests/test_analyze_commands.py b/tests/test_analyze_commands.py index 5a0e7aec8..fde43bc50 100644 --- a/tests/test_analyze_commands.py +++ b/tests/test_analyze_commands.py @@ -7,9 +7,9 @@ import pandas as pd import test_utils -omniperf = SourceFileLoader("omniperf", "src/omniperf").load_module() +rocprof_compute = SourceFileLoader("rocprof-compute", "src/rocprof-compute").load_module() -baseline_opts = ["omniperf", "analyze"] +baseline_opts = ["rocprof-compute", "analyze"] config = {} config["cleanup"] = True if "PYTEST_XDIST_WORKER_COUNT" in os.environ else False @@ -29,9 +29,9 @@ def test_valid_path(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", workload_dir], + ["rocprof-compute", "analyze", "--path", workload_dir], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -45,14 +45,14 @@ def test_list_kernels(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, "--list-stats", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -60,8 +60,10 @@ def test_list_kernels(): @pytest.mark.list_metrics def test_list_metrics_gfx90a(): with pytest.raises(SystemExit) as e: - with patch("sys.argv", ["omniperf", "analyze", "--list-metrics", "gfx90a"]): - omniperf.main() + with patch( + "sys.argv", ["rocprof-compute", "analyze", "--list-metrics", "gfx90a"] + ): + rocprof_compute.main() assert e.value.code == 1 for dir in indirs: @@ -70,7 +72,7 @@ def test_list_metrics_gfx90a(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -78,7 +80,7 @@ def test_list_metrics_gfx90a(): "gfx90a", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -87,8 +89,10 @@ def test_list_metrics_gfx90a(): @pytest.mark.list_metrics def test_list_metrics_gfx906(): with pytest.raises(SystemExit) as e: - with patch("sys.argv", ["omniperf", "analyze", "--list-metrics", "gfx906"]): - omniperf.main() + with patch( + "sys.argv", ["rocprof-compute", "analyze", "--list-metrics", "gfx906"] + ): + rocprof_compute.main() assert e.value.code == 1 for dir in indirs: @@ -97,7 +101,7 @@ def test_list_metrics_gfx906(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -105,7 +109,7 @@ def test_list_metrics_gfx906(): "gfx906", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -114,8 +118,10 @@ def test_list_metrics_gfx906(): @pytest.mark.list_metrics def test_list_metrics_gfx908(): with pytest.raises(SystemExit) as e: - with patch("sys.argv", ["omniperf", "analyze", "--list-metrics", "gfx908"]): - omniperf.main() + with patch( + "sys.argv", ["rocprof-compute", "analyze", "--list-metrics", "gfx908"] + ): + rocprof_compute.main() assert e.value.code == 1 for dir in indirs: @@ -124,7 +130,7 @@ def test_list_metrics_gfx908(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -132,7 +138,7 @@ def test_list_metrics_gfx908(): "gfx908", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -146,7 +152,7 @@ def test_filter_block_1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -154,7 +160,7 @@ def test_filter_block_1(): "1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -168,7 +174,7 @@ def test_filter_block_2(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -176,7 +182,7 @@ def test_filter_block_2(): "5", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -190,7 +196,7 @@ def test_filter_block_3(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -198,7 +204,7 @@ def test_filter_block_3(): "5.2.2", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -212,7 +218,7 @@ def test_filter_block_4(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -220,7 +226,7 @@ def test_filter_block_4(): "6.1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -234,7 +240,7 @@ def test_filter_block_5(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -242,7 +248,7 @@ def test_filter_block_5(): "10", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -256,7 +262,7 @@ def test_filter_block_6(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -264,7 +270,7 @@ def test_filter_block_6(): "100", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -278,7 +284,7 @@ def test_filter_kernel_1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -286,7 +292,7 @@ def test_filter_kernel_1(): "0", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -300,7 +306,7 @@ def test_filter_kernel_2(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -308,7 +314,7 @@ def test_filter_kernel_2(): "1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -322,7 +328,7 @@ def test_filter_kernel_3(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -331,7 +337,7 @@ def test_filter_kernel_3(): "1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -345,7 +351,7 @@ def test_dispatch_1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -353,7 +359,7 @@ def test_dispatch_1(): "0", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -367,7 +373,7 @@ def test_dispatch_2(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -375,7 +381,7 @@ def test_dispatch_2(): "1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -389,7 +395,7 @@ def test_dispatch_3(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -397,7 +403,7 @@ def test_dispatch_3(): "2", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -411,7 +417,7 @@ def test_dispatch_4(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -420,7 +426,7 @@ def test_dispatch_4(): "4", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -434,7 +440,7 @@ def test_dispatch_5(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -443,7 +449,7 @@ def test_dispatch_5(): "6", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -457,7 +463,7 @@ def test_gpu_ids(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -465,7 +471,7 @@ def test_gpu_ids(): "2", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -479,7 +485,7 @@ def test_normal_unit_per_wave(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -487,7 +493,7 @@ def test_normal_unit_per_wave(): "per_wave", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -501,7 +507,7 @@ def test_normal_unit_per_cycle(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -509,7 +515,7 @@ def test_normal_unit_per_cycle(): "per_cycle", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -523,7 +529,7 @@ def test_normal_unit_per_second(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -531,7 +537,7 @@ def test_normal_unit_per_second(): "per_second", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -545,7 +551,7 @@ def test_normal_unit_per_kernel(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -553,7 +559,7 @@ def test_normal_unit_per_kernel(): "per_kernel", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -567,7 +573,7 @@ def test_max_stat_num_1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -575,7 +581,7 @@ def test_max_stat_num_1(): "0", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -589,7 +595,7 @@ def test_max_stat_num_2(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -597,7 +603,7 @@ def test_max_stat_num_2(): "5", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -611,7 +617,7 @@ def test_max_stat_num_3(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -619,7 +625,7 @@ def test_max_stat_num_3(): "10", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -633,7 +639,7 @@ def test_max_stat_num_4(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -641,7 +647,7 @@ def test_max_stat_num_4(): "15", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -655,7 +661,7 @@ def test_time_unit_s(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -663,7 +669,7 @@ def test_time_unit_s(): "s", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -677,7 +683,7 @@ def test_time_unit_ms(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -685,7 +691,7 @@ def test_time_unit_ms(): "ms", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -699,7 +705,7 @@ def test_time_unit_us(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -707,7 +713,7 @@ def test_time_unit_us(): "us", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -721,7 +727,7 @@ def test_time_unit_ns(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -729,7 +735,7 @@ def test_time_unit_ns(): "ns", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -743,7 +749,7 @@ def test_decimal_1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -751,7 +757,7 @@ def test_decimal_1(): "0", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -765,7 +771,7 @@ def test_decimal_2(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -773,7 +779,7 @@ def test_decimal_2(): "1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -787,7 +793,7 @@ def test_decimal_3(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -795,7 +801,7 @@ def test_decimal_3(): "4", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -810,7 +816,7 @@ def test_save_dfs(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -818,7 +824,7 @@ def test_save_dfs(): output_path, ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 files_in_workload = os.listdir(output_path) @@ -843,7 +849,7 @@ def test_save_dfs(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -851,7 +857,7 @@ def test_save_dfs(): output_path, ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 files_in_workload = os.listdir(output_path) @@ -872,7 +878,7 @@ def test_col_1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -880,7 +886,7 @@ def test_col_1(): "0", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -894,7 +900,7 @@ def test_col_2(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -902,7 +908,7 @@ def test_col_2(): "2", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -916,7 +922,7 @@ def test_col_3(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -925,7 +931,7 @@ def test_col_3(): "2", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -939,14 +945,14 @@ def test_g(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, "-g", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -960,7 +966,7 @@ def test_kernel_verbose_0(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -968,7 +974,7 @@ def test_kernel_verbose_0(): "0", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -982,7 +988,7 @@ def test_kernel_verbose_1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -990,7 +996,7 @@ def test_kernel_verbose_1(): "1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -1004,7 +1010,7 @@ def test_kernel_verbose_2(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -1012,7 +1018,7 @@ def test_kernel_verbose_2(): "2", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -1026,7 +1032,7 @@ def test_kernel_verbose_3(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -1034,7 +1040,7 @@ def test_kernel_verbose_3(): "3", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -1048,7 +1054,7 @@ def test_kernel_verbose_4(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -1056,7 +1062,7 @@ def test_kernel_verbose_4(): "4", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -1070,7 +1076,7 @@ def test_kernel_verbose_5(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -1078,7 +1084,7 @@ def test_kernel_verbose_5(): "5", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -1092,7 +1098,7 @@ def test_kernel_verbose_6(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, @@ -1100,7 +1106,7 @@ def test_kernel_verbose_6(): "6", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) @@ -1112,7 +1118,7 @@ def test_baseline(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/vcopy/MI200", @@ -1120,7 +1126,7 @@ def test_baseline(): "tests/workloads/vcopy/MI100", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 with pytest.raises(SystemExit) as e: @@ -1135,7 +1141,7 @@ def test_baseline(): "tests/workloads/vcopy/MI200", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 with pytest.raises(SystemExit) as e: @@ -1150,7 +1156,7 @@ def test_baseline(): "tests/workloads/vcopy/MI100", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -1162,13 +1168,13 @@ def test_dependency_MI100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", workload_dir, "--dependency", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 test_utils.clean_output_dir(config["cleanup"], workload_dir) diff --git a/tests/test_analyze_workloads.py b/tests/test_analyze_workloads.py index 2b3605ed7..c47e59b30 100644 --- a/tests/test_analyze_workloads.py +++ b/tests/test_analyze_workloads.py @@ -10,11 +10,10 @@ import inspect import sys import test_utils -import pytest from unittest.mock import patch from importlib.machinery import SourceFileLoader -omniperf = SourceFileLoader("omniperf", "src/omniperf").load_module() +rocprof_compute = SourceFileLoader("rocprof-compute", "src/rocprof-compute").load_module() ################################################## ## Generated tests ## @@ -24,18 +23,20 @@ def test_analyze_vcopy_MI100(): with pytest.raises(SystemExit) as e: with patch( - "sys.argv", ["omniperf", "analyze", "--path", "tests/workloads/vcopy/MI100"] + "sys.argv", + ["rocprof-compute", "analyze", "--path", "tests/workloads/vcopy/MI100"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 def test_analyze_vcopy_MI200(): with pytest.raises(SystemExit) as e: with patch( - "sys.argv", ["omniperf", "analyze", "--path", "tests/workloads/vcopy/MI200"] + "sys.argv", + ["rocprof-compute", "analyze", "--path", "tests/workloads/vcopy/MI200"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -43,9 +44,14 @@ def test_analyze_ipblocks_TCP_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TCP/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TCP/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -53,9 +59,14 @@ def test_analyze_ipblocks_TCP_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TCP/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TCP/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -63,9 +74,14 @@ def test_analyze_ipblocks_TCP_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TCP/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TCP/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -73,9 +89,14 @@ def test_analyze_ipblocks_TCP_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TCP/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TCP/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -83,9 +104,14 @@ def test_analyze_ipblocks_SQC_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQC/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQC/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -93,9 +119,14 @@ def test_analyze_ipblocks_SQC_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQC/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQC/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -103,9 +134,14 @@ def test_analyze_ipblocks_SQC_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQC/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQC/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -113,9 +149,14 @@ def test_analyze_ipblocks_SQC_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQC/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQC/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -123,9 +164,14 @@ def test_analyze_mem_levels_HBM_LDS_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/mem_levels_HBM_LDS/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/mem_levels_HBM_LDS/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -133,9 +179,14 @@ def test_analyze_ipblocks_TCC_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TCC/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TCC/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -143,9 +194,14 @@ def test_analyze_ipblocks_TCC_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TCC/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TCC/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -153,9 +209,14 @@ def test_analyze_ipblocks_TCC_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TCC/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TCC/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -163,9 +224,14 @@ def test_analyze_ipblocks_TCC_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TCC/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TCC/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -173,18 +239,24 @@ def test_analyze_no_roof_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/no_roof/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/no_roof/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 def test_analyze_no_roof_MI100(): with pytest.raises(SystemExit) as e: with patch( - "sys.argv", ["omniperf", "analyze", "--path", "tests/workloads/no_roof/MI100"] + "sys.argv", + ["rocprof-compute", "analyze", "--path", "tests/workloads/no_roof/MI100"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -192,18 +264,24 @@ def test_analyze_no_roof_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/no_roof/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/no_roof/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 def test_analyze_no_roof_MI200(): with pytest.raises(SystemExit) as e: with patch( - "sys.argv", ["omniperf", "analyze", "--path", "tests/workloads/no_roof/MI200"] + "sys.argv", + ["rocprof-compute", "analyze", "--path", "tests/workloads/no_roof/MI200"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -212,13 +290,13 @@ def test_analyze_ipblocks_SQ_CPC_MI300X_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_CPC/MI300X_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -226,9 +304,14 @@ def test_analyze_ipblocks_SQ_CPC_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ_CPC/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ_CPC/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -237,13 +320,13 @@ def test_analyze_ipblocks_SQ_CPC_MI300A_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_CPC/MI300A_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -251,9 +334,14 @@ def test_analyze_ipblocks_SQ_CPC_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ_CPC/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ_CPC/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -261,9 +349,14 @@ def test_analyze_dispatch_0_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_0/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_0/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -271,9 +364,14 @@ def test_analyze_dispatch_0_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_0/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_0/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -281,9 +379,14 @@ def test_analyze_dispatch_0_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_0/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_0/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -291,9 +394,14 @@ def test_analyze_dispatch_0_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_0/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_0/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -301,9 +409,14 @@ def test_analyze_join_type_grid_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/join_type_grid/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/join_type_grid/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -311,9 +424,14 @@ def test_analyze_join_type_grid_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/join_type_grid/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/join_type_grid/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -321,9 +439,14 @@ def test_analyze_join_type_grid_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/join_type_grid/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/join_type_grid/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -331,9 +454,14 @@ def test_analyze_join_type_grid_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/join_type_grid/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/join_type_grid/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -341,18 +469,24 @@ def test_analyze_kernel_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 def test_analyze_kernel_MI100(): with pytest.raises(SystemExit) as e: with patch( - "sys.argv", ["omniperf", "analyze", "--path", "tests/workloads/kernel/MI100"] + "sys.argv", + ["rocprof-compute", "analyze", "--path", "tests/workloads/kernel/MI100"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -360,18 +494,24 @@ def test_analyze_kernel_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 def test_analyze_kernel_MI200(): with pytest.raises(SystemExit) as e: with patch( - "sys.argv", ["omniperf", "analyze", "--path", "tests/workloads/kernel/MI200"] + "sys.argv", + ["rocprof-compute", "analyze", "--path", "tests/workloads/kernel/MI200"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -379,9 +519,14 @@ def test_analyze_kernel_substr_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_substr/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_substr/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -389,9 +534,14 @@ def test_analyze_kernel_substr_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_substr/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_substr/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -399,9 +549,14 @@ def test_analyze_kernel_substr_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_substr/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_substr/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -409,9 +564,14 @@ def test_analyze_kernel_substr_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_substr/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_substr/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -419,9 +579,14 @@ def test_analyze_dispatch_7_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_7/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_7/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -429,9 +594,14 @@ def test_analyze_dispatch_7_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_7/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_7/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -439,9 +609,14 @@ def test_analyze_dispatch_7_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_7/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_7/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -449,9 +624,14 @@ def test_analyze_dispatch_7_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_7/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_7/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -459,9 +639,14 @@ def test_analyze_kernel_inv_int_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_inv_int/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_inv_int/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -469,9 +654,14 @@ def test_analyze_kernel_inv_int_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_inv_int/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_inv_int/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -479,9 +669,14 @@ def test_analyze_kernel_inv_int_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_inv_int/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_inv_int/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -489,9 +684,14 @@ def test_analyze_kernel_inv_int_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_inv_int/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_inv_int/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -499,9 +699,14 @@ def test_analyze_mem_levels_vL1D_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/mem_levels_vL1D/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/mem_levels_vL1D/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -509,9 +714,14 @@ def test_analyze_sort_kernels_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/sort_kernels/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/sort_kernels/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -519,9 +729,14 @@ def test_analyze_kernel_inv_str_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_inv_str/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_inv_str/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -529,9 +744,14 @@ def test_analyze_kernel_inv_str_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_inv_str/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_inv_str/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -539,9 +759,14 @@ def test_analyze_kernel_inv_str_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_inv_str/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_inv_str/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -549,9 +774,14 @@ def test_analyze_kernel_inv_str_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_inv_str/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_inv_str/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -560,13 +790,13 @@ def test_analyze_ipblocks_SQ_SPI_MI300X_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SPI/MI300X_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -574,9 +804,14 @@ def test_analyze_ipblocks_SQ_SPI_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ_SPI/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ_SPI/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -585,13 +820,13 @@ def test_analyze_ipblocks_SQ_SPI_MI300A_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SPI/MI300A_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -599,9 +834,14 @@ def test_analyze_ipblocks_SQ_SPI_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ_SPI/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ_SPI/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -609,9 +849,14 @@ def test_analyze_dispatch_2_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_2/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_2/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -619,9 +864,14 @@ def test_analyze_dispatch_2_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_2/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_2/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -629,9 +879,14 @@ def test_analyze_dispatch_2_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_2/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_2/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -639,9 +894,14 @@ def test_analyze_dispatch_2_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_2/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_2/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -649,9 +909,14 @@ def test_analyze_dispatch_0_1_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_0_1/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_0_1/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -659,9 +924,14 @@ def test_analyze_dispatch_0_1_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_0_1/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_0_1/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -669,9 +939,14 @@ def test_analyze_dispatch_0_1_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_0_1/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_0_1/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -679,9 +954,14 @@ def test_analyze_dispatch_0_1_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_0_1/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_0_1/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -689,9 +969,14 @@ def test_analyze_mem_levels_LDS_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/mem_levels_LDS/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/mem_levels_LDS/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -699,9 +984,14 @@ def test_analyze_ipblocks_TA_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TA/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TA/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -709,9 +999,14 @@ def test_analyze_ipblocks_TA_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TA/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TA/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -719,9 +1014,14 @@ def test_analyze_ipblocks_TA_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TA/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TA/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -729,9 +1029,14 @@ def test_analyze_ipblocks_TA_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TA/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TA/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -739,9 +1044,14 @@ def test_analyze_dispatch_6_8_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_6_8/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_6_8/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -749,9 +1059,14 @@ def test_analyze_dispatch_6_8_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_6_8/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_6_8/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -759,9 +1074,14 @@ def test_analyze_dispatch_6_8_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_6_8/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_6_8/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -769,9 +1089,14 @@ def test_analyze_dispatch_6_8_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_6_8/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_6_8/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 1 @@ -779,9 +1104,14 @@ def test_analyze_device_inv_int_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/device_inv_int/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/device_inv_int/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -789,9 +1119,14 @@ def test_analyze_device_inv_int_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/device_inv_int/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/device_inv_int/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -799,9 +1134,14 @@ def test_analyze_device_inv_int_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/device_inv_int/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/device_inv_int/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -809,9 +1149,14 @@ def test_analyze_device_inv_int_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/device_inv_int/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/device_inv_int/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -819,9 +1164,14 @@ def test_analyze_ipblocks_SQ_TA_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ_TA/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ_TA/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -829,9 +1179,14 @@ def test_analyze_ipblocks_SQ_TA_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ_TA/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ_TA/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -839,9 +1194,14 @@ def test_analyze_ipblocks_SQ_TA_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ_TA/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ_TA/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -849,9 +1209,14 @@ def test_analyze_ipblocks_SQ_TA_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ_TA/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ_TA/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -859,9 +1224,14 @@ def test_analyze_ipblocks_TD_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TD/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TD/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -869,9 +1239,14 @@ def test_analyze_ipblocks_TD_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TD/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TD/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -879,9 +1254,14 @@ def test_analyze_ipblocks_TD_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TD/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TD/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -889,9 +1269,14 @@ def test_analyze_ipblocks_TD_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_TD/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_TD/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -899,9 +1284,14 @@ def test_analyze_device_filter_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/device_filter/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/device_filter/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -909,9 +1299,14 @@ def test_analyze_device_filter_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/device_filter/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/device_filter/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -919,9 +1314,14 @@ def test_analyze_device_filter_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/device_filter/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/device_filter/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -929,9 +1329,14 @@ def test_analyze_device_filter_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/device_filter/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/device_filter/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -940,13 +1345,13 @@ def test_analyze_join_type_kernel_MI300X_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/join_type_kernel/MI300X_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -954,9 +1359,14 @@ def test_analyze_join_type_kernel_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/join_type_kernel/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/join_type_kernel/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -965,13 +1375,13 @@ def test_analyze_join_type_kernel_MI300A_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/join_type_kernel/MI300A_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -979,9 +1389,14 @@ def test_analyze_join_type_kernel_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/join_type_kernel/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/join_type_kernel/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -990,13 +1405,13 @@ def test_analyze_ipblocks_SQ_SQC_TCP_CPC_MI300X_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SQC_TCP_CPC/MI300X_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1005,13 +1420,13 @@ def test_analyze_ipblocks_SQ_SQC_TCP_CPC_MI100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SQC_TCP_CPC/MI100", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1020,13 +1435,13 @@ def test_analyze_ipblocks_SQ_SQC_TCP_CPC_MI300A_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SQC_TCP_CPC/MI300A_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1035,13 +1450,13 @@ def test_analyze_ipblocks_SQ_SQC_TCP_CPC_MI200(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SQC_TCP_CPC/MI200", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1050,13 +1465,13 @@ def test_analyze_mem_levels_L2_vL1d_LDS_MI200(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/mem_levels_L2_vL1d_LDS/MI200", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1064,9 +1479,14 @@ def test_analyze_ipblocks_CPF_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_CPF/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_CPF/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1074,9 +1494,14 @@ def test_analyze_ipblocks_CPF_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_CPF/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_CPF/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1084,9 +1509,14 @@ def test_analyze_ipblocks_CPF_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_CPF/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_CPF/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1094,9 +1524,14 @@ def test_analyze_ipblocks_CPF_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_CPF/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_CPF/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1104,9 +1539,14 @@ def test_analyze_sort_dispatches_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/sort_dispatches/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/sort_dispatches/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1114,9 +1554,14 @@ def test_analyze_kernel_names_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/kernel_names/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/kernel_names/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1125,13 +1570,13 @@ def test_analyze_mem_levels_vL1d_LDS_MI200(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/mem_levels_vL1d_LDS/MI200", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1139,9 +1584,14 @@ def test_analyze_ipblocks_SQ_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1149,9 +1599,14 @@ def test_analyze_ipblocks_SQ_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1159,9 +1614,14 @@ def test_analyze_ipblocks_SQ_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1169,9 +1629,14 @@ def test_analyze_ipblocks_SQ_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SQ/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SQ/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1179,9 +1644,14 @@ def test_analyze_mem_levels_L2_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/mem_levels_L2/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/mem_levels_L2/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1189,9 +1659,14 @@ def test_analyze_dispatch_inv_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_inv/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_inv/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1199,9 +1674,14 @@ def test_analyze_dispatch_inv_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_inv/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_inv/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1209,9 +1689,14 @@ def test_analyze_dispatch_inv_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_inv/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_inv/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1219,9 +1704,14 @@ def test_analyze_dispatch_inv_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/dispatch_inv/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/dispatch_inv/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1229,18 +1719,19 @@ def test_analyze_path_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/path/MI300X_A1"], + ["rocprof-compute", "analyze", "--path", "tests/workloads/path/MI300X_A1"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 def test_analyze_path_MI100(): with pytest.raises(SystemExit) as e: with patch( - "sys.argv", ["omniperf", "analyze", "--path", "tests/workloads/path/MI100"] + "sys.argv", + ["rocprof-compute", "analyze", "--path", "tests/workloads/path/MI100"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1248,18 +1739,19 @@ def test_analyze_path_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/path/MI300A_A1"], + ["rocprof-compute", "analyze", "--path", "tests/workloads/path/MI300A_A1"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 def test_analyze_path_MI200(): with pytest.raises(SystemExit) as e: with patch( - "sys.argv", ["omniperf", "analyze", "--path", "tests/workloads/path/MI200"] + "sys.argv", + ["rocprof-compute", "analyze", "--path", "tests/workloads/path/MI200"], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1267,9 +1759,14 @@ def test_analyze_ipblocks_CPC_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_CPC/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_CPC/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1277,9 +1774,14 @@ def test_analyze_ipblocks_CPC_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_CPC/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_CPC/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1287,9 +1789,14 @@ def test_analyze_ipblocks_CPC_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_CPC/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_CPC/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1297,9 +1804,14 @@ def test_analyze_ipblocks_CPC_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_CPC/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_CPC/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1308,13 +1820,13 @@ def test_analyze_ipblocks_SQ_SPI_TA_TCC_CPF_MI300X_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SPI_TA_TCC_CPF/MI300X_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1323,13 +1835,13 @@ def test_analyze_ipblocks_SQ_SPI_TA_TCC_CPF_MI100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SPI_TA_TCC_CPF/MI100", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1338,13 +1850,13 @@ def test_analyze_ipblocks_SQ_SPI_TA_TCC_CPF_MI300A_A1(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SPI_TA_TCC_CPF/MI300A_A1", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1353,13 +1865,13 @@ def test_analyze_ipblocks_SQ_SPI_TA_TCC_CPF_MI200(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "analyze", "--path", "tests/workloads/ipblocks_SQ_SPI_TA_TCC_CPF/MI200", ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1367,9 +1879,14 @@ def test_analyze_mem_levels_HBM_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/mem_levels_HBM/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/mem_levels_HBM/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1377,9 +1894,14 @@ def test_analyze_ipblocks_SPI_MI300X_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SPI/MI300X_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SPI/MI300X_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1387,9 +1909,14 @@ def test_analyze_ipblocks_SPI_MI100(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SPI/MI100"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SPI/MI100", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1397,9 +1924,14 @@ def test_analyze_ipblocks_SPI_MI300A_A1(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SPI/MI300A_A1"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SPI/MI300A_A1", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 @@ -1407,7 +1939,12 @@ def test_analyze_ipblocks_SPI_MI200(): with pytest.raises(SystemExit) as e: with patch( "sys.argv", - ["omniperf", "analyze", "--path", "tests/workloads/ipblocks_SPI/MI200"], + [ + "rocprof-compute", + "analyze", + "--path", + "tests/workloads/ipblocks_SPI/MI200", + ], ): - omniperf.main() + rocprof_compute.main() assert e.value.code == 0 diff --git a/tests/test_import_workloads.py b/tests/test_import_workloads.py index 7b169f8a9..32828071b 100644 --- a/tests/test_import_workloads.py +++ b/tests/test_import_workloads.py @@ -2,7 +2,7 @@ from unittest.mock import patch from importlib.machinery import SourceFileLoader -omniperf = SourceFileLoader("omniperf", "src/omniperf").load_module() +rocprof_compute = SourceFileLoader("rocprof-compute", "src/rocprof-compute").load_module() ################################################## ## Generated tests ## @@ -13,7 +13,7 @@ def test_import_D_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -28,14 +28,14 @@ def test_import_D_str_inv1_mi100(): "tests/workloads/D_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_D_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -50,14 +50,14 @@ def test_D_str_inv1_mi100(): "tests/workloads/D_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_dev01p3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -72,14 +72,14 @@ def test_import_dev01p3_mi100(): "tests/workloads/dev01p3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_SQC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -94,14 +94,14 @@ def test_import_SQC_mi100(): "tests/workloads/SQC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_SQC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -116,14 +116,14 @@ def test_SQC_mi100(): "tests/workloads/SQC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_Axes2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -138,14 +138,14 @@ def test_import_Axes2_mi100(): "tests/workloads/Axes2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_Axes2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -160,14 +160,14 @@ def test_Axes2_mi100(): "tests/workloads/Axes2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_SQ_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -182,14 +182,14 @@ def test_import_no_roof_SQ_mi100(): "tests/workloads/no_roof_SQ/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_SQ_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -204,14 +204,14 @@ def test_no_roof_SQ_mi100(): "tests/workloads/no_roof_SQ/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_CPF_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -226,14 +226,14 @@ def test_import_CPF_mi100(): "tests/workloads/CPF/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_CPF_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -248,14 +248,14 @@ def test_CPF_mi100(): "tests/workloads/CPF/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_LDS_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -270,14 +270,14 @@ def test_import_no_roof_LDS_mi100(): "tests/workloads/no_roof_LDS/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_LDS_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -292,14 +292,14 @@ def test_no_roof_LDS_mi100(): "tests/workloads/no_roof_LDS/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_D_str_inv4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -314,14 +314,14 @@ def test_import_D_str_inv4_mi100(): "tests/workloads/D_str_inv4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_D_str_inv4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -336,14 +336,14 @@ def test_D_str_inv4_mi100(): "tests/workloads/D_str_inv4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_K_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -358,14 +358,14 @@ def test_roof_only_K_int_inv2_mi100(): "tests/workloads/roof_only_K_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_SPI_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -380,14 +380,14 @@ def test_import_no_roof_SPI_mi100(): "tests/workloads/no_roof_SPI/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_SPI_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -402,14 +402,14 @@ def test_no_roof_SPI_mi100(): "tests/workloads/no_roof_SPI/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_K_str_valid_2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -424,14 +424,14 @@ def test_import_no_roof_K_str_valid_2_mi100(): "tests/workloads/no_roof_K_str_valid_2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_K_str_valid_2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -446,14 +446,14 @@ def test_no_roof_K_str_valid_2_mi100(): "tests/workloads/no_roof_K_str_valid_2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_mixbench1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -468,14 +468,14 @@ def test_import_no_roof_mixbench1_mi100(): "tests/workloads/no_roof_mixbench1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_mixbench1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -490,14 +490,14 @@ def test_no_roof_mixbench1_mi100(): "tests/workloads/no_roof_mixbench1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_TA_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -512,14 +512,14 @@ def test_import_no_roof_TA_mi100(): "tests/workloads/no_roof_TA/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_TA_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -534,14 +534,14 @@ def test_no_roof_TA_mi100(): "tests/workloads/no_roof_TA/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_CPF_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -556,14 +556,14 @@ def test_import_no_roof_CPF_mi100(): "tests/workloads/no_roof_CPF/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_CPF_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -578,14 +578,14 @@ def test_no_roof_CPF_mi100(): "tests/workloads/no_roof_CPF/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -600,14 +600,14 @@ def test_import_no_roof_CPC_mi100(): "tests/workloads/no_roof_CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -622,14 +622,14 @@ def test_no_roof_CPC_mi100(): "tests/workloads/no_roof_CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_K_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -644,14 +644,14 @@ def test_import_K_str_inv3_mi100(): "tests/workloads/K_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_K_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -666,14 +666,14 @@ def test_K_str_inv3_mi100(): "tests/workloads/K_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_LDS_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -688,14 +688,14 @@ def test_import_LDS_mi100(): "tests/workloads/LDS/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_LDS_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -710,14 +710,14 @@ def test_LDS_mi100(): "tests/workloads/LDS/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_K_str_valid_3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -732,14 +732,14 @@ def test_import_no_roof_K_str_valid_3_mi100(): "tests/workloads/no_roof_K_str_valid_3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_D_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -754,14 +754,14 @@ def test_roof_only_D_int_inv2_mi100(): "tests/workloads/roof_only_D_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_K_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -776,14 +776,14 @@ def test_roof_only_K_str_inv1_mi100(): "tests/workloads/roof_only_K_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_SQC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -798,14 +798,14 @@ def test_roof_only_SQC_mi100(): "tests/workloads/roof_only_SQC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_Axes2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -820,14 +820,14 @@ def test_import_no_roof_Axes2_mi100(): "tests/workloads/no_roof_Axes2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_Axes2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -842,14 +842,14 @@ def test_no_roof_Axes2_mi100(): "tests/workloads/no_roof_Axes2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_HBM_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -864,14 +864,14 @@ def test_import_HBM_mi100(): "tests/workloads/HBM/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_HBM_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -886,14 +886,14 @@ def test_HBM_mi100(): "tests/workloads/HBM/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_TA_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -908,14 +908,14 @@ def test_roof_only_TA_CPC_mi100(): "tests/workloads/roof_only_TA_CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_D_val_int_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -930,14 +930,14 @@ def test_roof_only_D_val_int_mi100(): "tests/workloads/roof_only_D_val_int/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_L2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -952,14 +952,14 @@ def test_import_no_roof_L2_mi100(): "tests/workloads/no_roof_L2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_L2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -974,14 +974,14 @@ def test_no_roof_L2_mi100(): "tests/workloads/no_roof_L2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_L2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -996,14 +996,14 @@ def test_import_L2_mi100(): "tests/workloads/L2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_L2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1018,14 +1018,14 @@ def test_L2_mi100(): "tests/workloads/L2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_dev1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1040,14 +1040,14 @@ def test_import_no_roof_dev1_mi100(): "tests/workloads/no_roof_dev1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_dev1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1062,14 +1062,14 @@ def test_no_roof_dev1_mi100(): "tests/workloads/no_roof_dev1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_K_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1084,14 +1084,14 @@ def test_roof_only_K_str_inv3_mi100(): "tests/workloads/roof_only_K_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_K_str_valid_1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1106,14 +1106,14 @@ def test_roof_only_K_str_valid_1_mi100(): "tests/workloads/roof_only_K_str_valid_1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1128,14 +1128,14 @@ def test_roof_only_CPC_mi100(): "tests/workloads/roof_only_CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_Axes3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1150,14 +1150,14 @@ def test_import_no_roof_Axes3_mi100(): "tests/workloads/no_roof_Axes3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_Axes3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1172,14 +1172,14 @@ def test_no_roof_Axes3_mi100(): "tests/workloads/no_roof_Axes3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_D_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1194,14 +1194,14 @@ def test_import_no_roof_D_str_inv3_mi100(): "tests/workloads/no_roof_D_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_D_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1216,14 +1216,14 @@ def test_no_roof_D_str_inv3_mi100(): "tests/workloads/no_roof_D_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_D_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1238,14 +1238,14 @@ def test_import_no_roof_D_int_inv2_mi100(): "tests/workloads/no_roof_D_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_D_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1260,14 +1260,14 @@ def test_no_roof_D_int_inv2_mi100(): "tests/workloads/no_roof_D_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_TD_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1282,14 +1282,14 @@ def test_import_TD_mi100(): "tests/workloads/TD/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_TD_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1304,14 +1304,14 @@ def test_TD_mi100(): "tests/workloads/TD/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_D_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1326,14 +1326,14 @@ def test_roof_only_D_int_inv1_mi100(): "tests/workloads/roof_only_D_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_D_val_int2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1348,14 +1348,14 @@ def test_import_D_val_int2_mi100(): "tests/workloads/D_val_int2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_D_val_int2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1370,14 +1370,14 @@ def test_D_val_int2_mi100(): "tests/workloads/D_val_int2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_mixbench2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1392,14 +1392,14 @@ def test_import_no_roof_mixbench2_mi100(): "tests/workloads/no_roof_mixbench2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_mixbench2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1414,14 +1414,14 @@ def test_no_roof_mixbench2_mi100(): "tests/workloads/no_roof_mixbench2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_SPI_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1436,14 +1436,14 @@ def test_roof_only_SPI_mi100(): "tests/workloads/roof_only_SPI/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_D_val_int2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1458,14 +1458,14 @@ def test_import_no_roof_D_val_int2_mi100(): "tests/workloads/no_roof_D_val_int2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_D_val_int2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1480,14 +1480,14 @@ def test_no_roof_D_val_int2_mi100(): "tests/workloads/no_roof_D_val_int2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_K_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1502,14 +1502,14 @@ def test_import_K_str_inv1_mi100(): "tests/workloads/K_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_K_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1524,14 +1524,14 @@ def test_K_str_inv1_mi100(): "tests/workloads/K_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_TA_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1546,14 +1546,14 @@ def test_roof_only_TA_mi100(): "tests/workloads/roof_only_TA/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_K_str_valid_3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1568,14 +1568,14 @@ def test_import_K_str_valid_3_mi100(): "tests/workloads/K_str_valid_3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_SQ_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1590,14 +1590,14 @@ def test_import_SQ_mi100(): "tests/workloads/SQ/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_SQ_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1612,14 +1612,14 @@ def test_SQ_mi100(): "tests/workloads/SQ/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_D_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1634,14 +1634,14 @@ def test_import_no_roof_D_str_inv1_mi100(): "tests/workloads/no_roof_D_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_D_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1656,14 +1656,14 @@ def test_no_roof_D_str_inv1_mi100(): "tests/workloads/no_roof_D_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_dev01p3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1678,14 +1678,14 @@ def test_import_no_roof_dev01p3_mi100(): "tests/workloads/no_roof_dev01p3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_D_val_int2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1700,14 +1700,14 @@ def test_roof_only_D_val_int2_mi100(): "tests/workloads/roof_only_D_val_int2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_D_str_inv4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1722,14 +1722,14 @@ def test_import_no_roof_D_str_inv4_mi100(): "tests/workloads/no_roof_D_str_inv4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_D_str_inv4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1744,14 +1744,14 @@ def test_no_roof_D_str_inv4_mi100(): "tests/workloads/no_roof_D_str_inv4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_CPF_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1766,14 +1766,14 @@ def test_roof_only_CPF_mi100(): "tests/workloads/roof_only_CPF/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_mixbench_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1788,14 +1788,14 @@ def test_import_mixbench_mi100(): "tests/workloads/mixbench/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_mixbench_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1810,14 +1810,14 @@ def test_mixbench_mi100(): "tests/workloads/mixbench/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_D_str_inv4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1832,14 +1832,14 @@ def test_roof_only_D_str_inv4_mi100(): "tests/workloads/roof_only_D_str_inv4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_kernels_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1854,14 +1854,14 @@ def test_import_no_roof_kernels_mi100(): "tests/workloads/no_roof_kernels/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_kernels_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1876,14 +1876,14 @@ def test_no_roof_kernels_mi100(): "tests/workloads/no_roof_kernels/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_TCC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1898,14 +1898,14 @@ def test_roof_only_TCC_mi100(): "tests/workloads/roof_only_TCC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_TA_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1920,14 +1920,14 @@ def test_import_TA_CPC_mi100(): "tests/workloads/TA_CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_TA_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1942,14 +1942,14 @@ def test_TA_CPC_mi100(): "tests/workloads/TA_CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_SQ_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1964,14 +1964,14 @@ def test_roof_only_SQ_mi100(): "tests/workloads/roof_only_SQ/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_K_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -1986,14 +1986,14 @@ def test_import_K_int_inv2_mi100(): "tests/workloads/K_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_K_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2008,14 +2008,14 @@ def test_K_int_inv2_mi100(): "tests/workloads/K_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_TCP_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2030,14 +2030,14 @@ def test_roof_only_TCP_mi100(): "tests/workloads/roof_only_TCP/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_K_str_valid_2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2052,14 +2052,14 @@ def test_roof_only_K_str_valid_2_mi100(): "tests/workloads/roof_only_K_str_valid_2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_D_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2074,14 +2074,14 @@ def test_import_D_int_inv2_mi100(): "tests/workloads/D_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_D_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2096,14 +2096,14 @@ def test_D_int_inv2_mi100(): "tests/workloads/D_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_Axes3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2118,14 +2118,14 @@ def test_roof_only_Axes3_mi100(): "tests/workloads/roof_only_Axes3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_dev0_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2140,14 +2140,14 @@ def test_import_dev0_mi100(): "tests/workloads/dev0/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_dev0_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2162,14 +2162,14 @@ def test_dev0_mi100(): "tests/workloads/dev0/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_K_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2184,14 +2184,14 @@ def test_roof_only_K_str_inv2_mi100(): "tests/workloads/roof_only_K_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_Axes1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2206,14 +2206,14 @@ def test_import_Axes1_mi100(): "tests/workloads/Axes1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_Axes1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2228,14 +2228,14 @@ def test_Axes1_mi100(): "tests/workloads/Axes1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_HBM_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2250,14 +2250,14 @@ def test_roof_only_HBM_mi100(): "tests/workloads/roof_only_HBM/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_D_val_int_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2272,14 +2272,14 @@ def test_import_D_val_int_mi100(): "tests/workloads/D_val_int/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_D_val_int_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2294,14 +2294,14 @@ def test_D_val_int_mi100(): "tests/workloads/D_val_int/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_TCC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2316,14 +2316,14 @@ def test_import_no_roof_TCC_mi100(): "tests/workloads/no_roof_TCC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_TCC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2338,14 +2338,14 @@ def test_no_roof_TCC_mi100(): "tests/workloads/no_roof_TCC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_SQC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2360,14 +2360,14 @@ def test_import_no_roof_SQC_mi100(): "tests/workloads/no_roof_SQC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_SQC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2382,14 +2382,14 @@ def test_no_roof_SQC_mi100(): "tests/workloads/no_roof_SQC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_TD_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2404,14 +2404,14 @@ def test_roof_only_TD_mi100(): "tests/workloads/roof_only_TD/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_K_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2426,14 +2426,14 @@ def test_import_no_roof_K_int_inv1_mi100(): "tests/workloads/no_roof_K_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_K_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2448,14 +2448,14 @@ def test_no_roof_K_int_inv1_mi100(): "tests/workloads/no_roof_K_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_Axes1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2470,14 +2470,14 @@ def test_import_no_roof_Axes1_mi100(): "tests/workloads/no_roof_Axes1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_Axes1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2492,14 +2492,14 @@ def test_no_roof_Axes1_mi100(): "tests/workloads/no_roof_Axes1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_SPI_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2514,14 +2514,14 @@ def test_import_SPI_mi100(): "tests/workloads/SPI/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_SPI_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2536,14 +2536,14 @@ def test_SPI_mi100(): "tests/workloads/SPI/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_D_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2558,14 +2558,14 @@ def test_roof_only_D_str_inv3_mi100(): "tests/workloads/roof_only_D_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_D_val_int_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2580,14 +2580,14 @@ def test_import_no_roof_D_val_int_mi100(): "tests/workloads/no_roof_D_val_int/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_D_val_int_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2602,14 +2602,14 @@ def test_no_roof_D_val_int_mi100(): "tests/workloads/no_roof_D_val_int/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_K_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2624,14 +2624,14 @@ def test_import_K_str_inv2_mi100(): "tests/workloads/K_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_K_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2646,14 +2646,14 @@ def test_K_str_inv2_mi100(): "tests/workloads/K_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2668,14 +2668,14 @@ def test_import_CPC_mi100(): "tests/workloads/CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2690,14 +2690,14 @@ def test_CPC_mi100(): "tests/workloads/CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_dispatches_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2712,14 +2712,14 @@ def test_roof_only_dispatches_mi100(): "tests/workloads/roof_only_dispatches/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_mixbench2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2734,14 +2734,14 @@ def test_roof_only_mixbench2_mi100(): "tests/workloads/roof_only_mixbench2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_Axes4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2756,14 +2756,14 @@ def test_import_Axes4_mi100(): "tests/workloads/Axes4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_Axes4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2778,14 +2778,14 @@ def test_Axes4_mi100(): "tests/workloads/Axes4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_TCP_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2800,14 +2800,14 @@ def test_import_no_roof_TCP_mi100(): "tests/workloads/no_roof_TCP/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_TCP_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2822,14 +2822,14 @@ def test_no_roof_TCP_mi100(): "tests/workloads/no_roof_TCP/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_LDS_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2844,14 +2844,14 @@ def test_roof_only_LDS_mi100(): "tests/workloads/roof_only_LDS/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_invdev_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2866,14 +2866,14 @@ def test_import_invdev_mi100(): "tests/workloads/invdev/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_invdev_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2888,14 +2888,14 @@ def test_invdev_mi100(): "tests/workloads/invdev/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_dev0_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2910,14 +2910,14 @@ def test_import_no_roof_dev0_mi100(): "tests/workloads/no_roof_dev0/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_dev0_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2932,14 +2932,14 @@ def test_no_roof_dev0_mi100(): "tests/workloads/no_roof_dev0/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_Axes1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2954,14 +2954,14 @@ def test_roof_only_Axes1_mi100(): "tests/workloads/roof_only_Axes1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_invdev_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2976,14 +2976,14 @@ def test_roof_only_invdev_mi100(): "tests/workloads/roof_only_invdev/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_D_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -2998,14 +2998,14 @@ def test_roof_only_D_str_inv2_mi100(): "tests/workloads/roof_only_D_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_K_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3020,14 +3020,14 @@ def test_import_no_roof_K_str_inv3_mi100(): "tests/workloads/no_roof_K_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_K_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3042,14 +3042,14 @@ def test_no_roof_K_str_inv3_mi100(): "tests/workloads/no_roof_K_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_K_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3064,14 +3064,14 @@ def test_import_no_roof_K_str_inv2_mi100(): "tests/workloads/no_roof_K_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_K_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3086,14 +3086,14 @@ def test_no_roof_K_str_inv2_mi100(): "tests/workloads/no_roof_K_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_D_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3108,14 +3108,14 @@ def test_import_D_str_inv2_mi100(): "tests/workloads/D_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_D_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3130,14 +3130,14 @@ def test_D_str_inv2_mi100(): "tests/workloads/D_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_kernels_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3152,14 +3152,14 @@ def test_import_kernels_mi100(): "tests/workloads/kernels/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_kernels_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3174,14 +3174,14 @@ def test_kernels_mi100(): "tests/workloads/kernels/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_Axes4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3196,14 +3196,14 @@ def test_import_no_roof_Axes4_mi100(): "tests/workloads/no_roof_Axes4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_Axes4_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3218,14 +3218,14 @@ def test_no_roof_Axes4_mi100(): "tests/workloads/no_roof_Axes4/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_CMD_INV_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3240,14 +3240,14 @@ def test_import_CMD_INV_mi100(): "tests/workloads/CMD_INV/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_K_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3262,14 +3262,14 @@ def test_import_K_int_inv1_mi100(): "tests/workloads/K_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_K_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3284,14 +3284,14 @@ def test_K_int_inv1_mi100(): "tests/workloads/K_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_mixbench2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3306,14 +3306,14 @@ def test_import_mixbench2_mi100(): "tests/workloads/mixbench2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_mixbench2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3328,14 +3328,14 @@ def test_mixbench2_mi100(): "tests/workloads/mixbench2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_Double_N_flag_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3350,14 +3350,14 @@ def test_roof_only_Double_N_flag_mi100(): "tests/workloads/roof_only_Double_N_flag/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_TD_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3372,14 +3372,14 @@ def test_import_no_roof_TD_mi100(): "tests/workloads/no_roof_TD/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_TD_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3394,14 +3394,14 @@ def test_no_roof_TD_mi100(): "tests/workloads/no_roof_TD/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_TCC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3416,14 +3416,14 @@ def test_import_TCC_mi100(): "tests/workloads/TCC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_TCC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3438,14 +3438,14 @@ def test_TCC_mi100(): "tests/workloads/TCC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_dev0_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3460,14 +3460,14 @@ def test_roof_only_dev0_mi100(): "tests/workloads/roof_only_dev0/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_D_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3482,14 +3482,14 @@ def test_import_no_roof_D_str_inv2_mi100(): "tests/workloads/no_roof_D_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_D_str_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3504,14 +3504,14 @@ def test_no_roof_D_str_inv2_mi100(): "tests/workloads/no_roof_D_str_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_L2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3526,14 +3526,14 @@ def test_roof_only_L2_mi100(): "tests/workloads/roof_only_L2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_TA_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3548,14 +3548,14 @@ def test_import_no_roof_TA_CPC_mi100(): "tests/workloads/no_roof_TA_CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_TA_CPC_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3570,14 +3570,14 @@ def test_no_roof_TA_CPC_mi100(): "tests/workloads/no_roof_TA_CPC/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_Double_N_flag_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3592,14 +3592,14 @@ def test_import_no_roof_Double_N_flag_mi100(): "tests/workloads/no_roof_Double_N_flag/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_Double_N_flag_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3614,14 +3614,14 @@ def test_no_roof_Double_N_flag_mi100(): "tests/workloads/no_roof_Double_N_flag/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_Double_N_flag_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3636,14 +3636,14 @@ def test_import_Double_N_flag_mi100(): "tests/workloads/Double_N_flag/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_Double_N_flag_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3658,14 +3658,14 @@ def test_Double_N_flag_mi100(): "tests/workloads/Double_N_flag/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_K_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3680,14 +3680,14 @@ def test_roof_only_K_int_inv1_mi100(): "tests/workloads/roof_only_K_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_K_str_valid_1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3702,14 +3702,14 @@ def test_import_no_roof_K_str_valid_1_mi100(): "tests/workloads/no_roof_K_str_valid_1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_K_str_valid_1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3724,14 +3724,14 @@ def test_no_roof_K_str_valid_1_mi100(): "tests/workloads/no_roof_K_str_valid_1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_mixbench1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3746,14 +3746,14 @@ def test_roof_only_mixbench1_mi100(): "tests/workloads/roof_only_mixbench1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_dev1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3768,14 +3768,14 @@ def test_import_dev1_mi100(): "tests/workloads/dev1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_dev1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3790,14 +3790,14 @@ def test_dev1_mi100(): "tests/workloads/dev1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_K_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3812,14 +3812,14 @@ def test_import_no_roof_K_str_inv1_mi100(): "tests/workloads/no_roof_K_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_K_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3834,14 +3834,14 @@ def test_no_roof_K_str_inv1_mi100(): "tests/workloads/no_roof_K_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_K_str_valid_1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3856,14 +3856,14 @@ def test_import_K_str_valid_1_mi100(): "tests/workloads/K_str_valid_1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_K_str_valid_1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3878,14 +3878,14 @@ def test_K_str_valid_1_mi100(): "tests/workloads/K_str_valid_1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_mixbench1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3900,14 +3900,14 @@ def test_import_mixbench1_mi100(): "tests/workloads/mixbench1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_mixbench1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3922,14 +3922,14 @@ def test_mixbench1_mi100(): "tests/workloads/mixbench1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_CMD_INV_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3944,14 +3944,14 @@ def test_import_no_roof_CMD_INV_mi100(): "tests/workloads/no_roof_CMD_INV/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_D_str_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3966,14 +3966,14 @@ def test_roof_only_D_str_inv1_mi100(): "tests/workloads/roof_only_D_str_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_HBM_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -3988,14 +3988,14 @@ def test_import_no_roof_HBM_mi100(): "tests/workloads/no_roof_HBM/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_HBM_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4010,14 +4010,14 @@ def test_no_roof_HBM_mi100(): "tests/workloads/no_roof_HBM/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_kernels_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4032,14 +4032,14 @@ def test_roof_only_kernels_mi100(): "tests/workloads/roof_only_kernels/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_D_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4054,14 +4054,14 @@ def test_import_D_int_inv1_mi100(): "tests/workloads/D_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_D_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4076,14 +4076,14 @@ def test_D_int_inv1_mi100(): "tests/workloads/D_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_K_str_valid_2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4098,14 +4098,14 @@ def test_import_K_str_valid_2_mi100(): "tests/workloads/K_str_valid_2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_K_str_valid_2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4120,14 +4120,14 @@ def test_K_str_valid_2_mi100(): "tests/workloads/K_str_valid_2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_TCP_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4142,14 +4142,14 @@ def test_import_TCP_mi100(): "tests/workloads/TCP/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_TCP_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4164,14 +4164,14 @@ def test_TCP_mi100(): "tests/workloads/TCP/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_Axes3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4186,14 +4186,14 @@ def test_import_Axes3_mi100(): "tests/workloads/Axes3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_Axes3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4208,14 +4208,14 @@ def test_Axes3_mi100(): "tests/workloads/Axes3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_invdev_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4230,14 +4230,14 @@ def test_import_no_roof_invdev_mi100(): "tests/workloads/no_roof_invdev/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_invdev_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4252,14 +4252,14 @@ def test_no_roof_invdev_mi100(): "tests/workloads/no_roof_invdev/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_dispatches_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4274,14 +4274,14 @@ def test_import_no_roof_dispatches_mi100(): "tests/workloads/no_roof_dispatches/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_dispatches_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4296,14 +4296,14 @@ def test_no_roof_dispatches_mi100(): "tests/workloads/no_roof_dispatches/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_D_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4318,14 +4318,14 @@ def test_import_D_str_inv3_mi100(): "tests/workloads/D_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_D_str_inv3_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4340,14 +4340,14 @@ def test_D_str_inv3_mi100(): "tests/workloads/D_str_inv3/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_TA_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4362,14 +4362,14 @@ def test_import_TA_mi100(): "tests/workloads/TA/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_TA_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4384,14 +4384,14 @@ def test_TA_mi100(): "tests/workloads/TA/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_D_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4406,14 +4406,14 @@ def test_import_no_roof_D_int_inv1_mi100(): "tests/workloads/no_roof_D_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_D_int_inv1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4428,14 +4428,14 @@ def test_no_roof_D_int_inv1_mi100(): "tests/workloads/no_roof_D_int_inv1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_dispatches_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4450,14 +4450,14 @@ def test_import_dispatches_mi100(): "tests/workloads/dispatches/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_dispatches_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4472,14 +4472,14 @@ def test_dispatches_mi100(): "tests/workloads/dispatches/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_roof_only_dev1_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4494,14 +4494,14 @@ def test_roof_only_dev1_mi100(): "tests/workloads/roof_only_dev1/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_import_no_roof_K_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4516,14 +4516,14 @@ def test_import_no_roof_K_int_inv2_mi100(): "tests/workloads/no_roof_K_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() def test_no_roof_K_int_inv2_mi100(): with patch( "sys.argv", [ - "omniperf", + "rocprof-compute", "database", "--import", "-H", @@ -4538,4 +4538,4 @@ def test_no_roof_K_int_inv2_mi100(): "tests/workloads/no_roof_K_int_inv2/mi100", ], ): - omniperf.main() + rocprof_compute.main() diff --git a/tests/test_profile_general.py b/tests/test_profile_general.py index 28b1e07b3..d6da91c0c 100644 --- a/tests/test_profile_general.py +++ b/tests/test_profile_general.py @@ -24,8 +24,8 @@ def check_arch_override(): - if "OMNIPERF_ARCH_OVERRIDE" in os.environ.keys(): - return os.environ["OMNIPERF_ARCH_OVERRIDE"] + if "ROCPROFCOMPUTE_ARCH_OVERRIDE" in os.environ.keys(): + return os.environ["ROCPROFCOMPUTE_ARCH_OVERRIDE"] return "" @@ -34,7 +34,9 @@ def check_arch_override(): # -- config = {} -config["omniperf"] = SourceFileLoader("omniperf", "src/omniperf").load_module() +config["rocprofiler-compute"] = SourceFileLoader( + "rocprofiler-compute", "src/rocprof-compute" +).load_module() config["kernel_name_1"] = "vecCopy(double*, double*, double*, int, int) [clone .kd]" config["app_1"] = ["./tests/vcopy", "-n", "1048576", "-b", "256", "-i", "3"] config["cleanup"] = True @@ -42,7 +44,7 @@ def check_arch_override(): config["METRIC_COMPARE"] = False config["METRIC_LOGGING"] = False -baseline_opts = ["omniperf", "profile", "-n", "app_1", "-VVV"] +baseline_opts = ["rocprof-compute", "profile", "-n", "app_1", "-VVV"] num_kernels = 3 num_devices = 1 @@ -312,7 +314,7 @@ def gpu_soc(): else: print( "Cannot parse MI300 details from rocminfo. Please verify output or set the arch using (e.g.,) " - 'export OMNIPERF_ARCH_OVERRIDE="MI300A"' + 'export ROCPROFCOMPUTE_ARCH_OVERRIDE="MI300A"' ) assert 0 return gpu_model @@ -364,7 +366,7 @@ def baseline_compare_metric(test_name, workload_dir, args=[]): t = subprocess.Popen( [ sys.executable, - "src/omniperf", + "src/rocprof_compute", "analyze", "--path", Baseline_dir, @@ -503,7 +505,7 @@ def validate(test_name, workload_dir, file_dict, args=[]): def test_path(): options = baseline_opts workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) @@ -526,7 +528,7 @@ def test_path(): def test_no_roof(): options = baseline_opts + ["--no-roof"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) if soc == "MI100": @@ -554,7 +556,9 @@ def test_no_roof(): def test_kernel_names(): options = baseline_opts + ["--roof-only", "--kernel-names"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -589,7 +593,7 @@ def test_device_filter(): options = baseline_opts + ["--device", device_id] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, 1, num_kernels) if soc == "MI100": @@ -617,7 +621,7 @@ def test_device_filter(): def test_kernel(): options = baseline_opts + ["--kernel", config["kernel_name_1"]] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) if soc == "MI100": @@ -643,7 +647,7 @@ def test_kernel(): def test_block_SQ(): options = baseline_opts + ["--block", "SQ"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -719,7 +723,7 @@ def test_block_SQ(): def test_block_SQC(): options = baseline_opts + ["--block", "SQC"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -749,7 +753,7 @@ def test_block_SQC(): def test_block_TA(): options = baseline_opts + ["--block", "TA"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -783,7 +787,7 @@ def test_block_TA(): def test_block_TD(): options = baseline_opts + ["--block", "TD"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -831,7 +835,7 @@ def test_block_TD(): def test_block_TCP(): options = baseline_opts + ["--block", "TCP"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -867,7 +871,7 @@ def test_block_TCP(): def test_block_TCC(): options = baseline_opts + ["--block", "TCC"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -933,7 +937,7 @@ def test_block_TCC(): def test_block_SPI(): options = baseline_opts + ["--block", "SPI"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -968,7 +972,7 @@ def test_block_SPI(): def test_block_CPC(): options = baseline_opts + ["--block", "CPC"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -996,7 +1000,7 @@ def test_block_CPC(): def test_block_CPF(): options = baseline_opts + ["--block", "CPF"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -1026,7 +1030,7 @@ def test_block_CPF(): def test_block_SQ_CPC(): options = baseline_opts + ["--block", "SQ", "CPC"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -1102,7 +1106,7 @@ def test_block_SQ_CPC(): def test_block_SQ_TA(): options = baseline_opts + ["--block", "SQ", "TA"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -1174,7 +1178,7 @@ def test_block_SQ_TA(): def test_block_SQ_SPI(): options = baseline_opts + ["--block", "SQ", "SPI"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -1249,7 +1253,7 @@ def test_block_SQ_SPI(): def test_block_SQ_SQC_TCP_CPC(): options = baseline_opts + ["--block", "SQ", "SQC", "TCP", "CPC"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -1321,7 +1325,7 @@ def test_block_SQ_SQC_TCP_CPC(): def test_block_SQ_SPI_TA_TCC_CPF(): options = baseline_opts + ["--block", "SQ", "SPI", "TA", "TCC", "CPF"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) expected_csvs = [ @@ -1397,7 +1401,7 @@ def test_block_SQ_SPI_TA_TCC_CPF(): def test_dispatch_0(): options = baseline_opts + ["--dispatch", "0"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, 1) if soc == "MI100": @@ -1427,7 +1431,7 @@ def test_dispatch_0(): def test_dispatch_0_1(): options = baseline_opts + ["--dispatch", "0:2"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, 2) if soc == "MI100": @@ -1454,7 +1458,7 @@ def test_dispatch_0_1(): def test_dispatch_2(): options = baseline_opts + ["--dispatch", dispatch_id] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, 1) if soc == "MI100": @@ -1484,7 +1488,7 @@ def test_dispatch_2(): def test_join_type_grid(): options = baseline_opts + ["--join-type", "grid"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) if soc == "MI100": @@ -1510,7 +1514,7 @@ def test_join_type_grid(): def test_join_type_kernel(): options = baseline_opts + ["--join-type", "kernel"] workload_dir = test_utils.get_output_dir() - test_utils.launch_omniperf(config, options, workload_dir) + test_utils.launch_rocprof_compute(config, options, workload_dir) file_dict = test_utils.check_csv_files(workload_dir, num_devices, num_kernels) @@ -1537,7 +1541,9 @@ def test_join_type_kernel(): def test_sort_dispatches(): options = baseline_opts + ["--roof-only", "--sort", "dispatches"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -1568,7 +1574,9 @@ def test_sort_dispatches(): def test_sort_kernels(): options = baseline_opts + ["--roof-only", "--sort", "kernels"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -1598,7 +1606,9 @@ def test_sort_kernels(): def test_mem_levels_HBM(): options = baseline_opts + ["--roof-only", "--mem-level", "HBM"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -1628,7 +1638,9 @@ def test_mem_levels_HBM(): def test_mem_levels_L2(): options = baseline_opts + ["--roof-only", "--mem-level", "L2"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -1658,7 +1670,9 @@ def test_mem_levels_L2(): def test_mem_levels_vL1D(): options = baseline_opts + ["--roof-only", "--mem-level", "vL1D"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -1688,7 +1702,9 @@ def test_mem_levels_vL1D(): def test_mem_levels_LDS(): options = baseline_opts + ["--roof-only", "--mem-level", "LDS"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -1718,7 +1734,9 @@ def test_mem_levels_LDS(): def test_mem_levels_HBM_LDS(): options = baseline_opts + ["--roof-only", "--mem-level", "HBM", "LDS"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -1748,7 +1766,9 @@ def test_mem_levels_HBM_LDS(): def test_mem_levels_vL1D_LDS(): options = baseline_opts + ["--roof-only", "--mem-level", "vL1D", "LDS"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run @@ -1778,7 +1798,9 @@ def test_mem_levels_vL1D_LDS(): def test_mem_levels_L2_vL1D_LDS(): options = baseline_opts + ["--roof-only", "--mem-level", "L2", "vL1D", "LDS"] workload_dir = test_utils.get_output_dir() - e = test_utils.launch_omniperf(config, options, workload_dir, check_success=False) + e = test_utils.launch_rocprof_compute( + config, options, workload_dir, check_success=False + ) if soc == "MI100" or "MI300" in soc: # assert that it did not run diff --git a/tests/test_utils.py b/tests/test_utils.py index 6ee8bac42..650c53324 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -86,7 +86,7 @@ def setup_workload_dir(input_dir, suffix="_tmp", clean_existing=True): def clean_output_dir(cleanup, output_dir): - """Remove output directory generated from omniperf execution + """Remove output directory generated from rocprof-compute execution Args: cleanup (boolean): flag to enable/disable directory cleanup @@ -126,12 +126,12 @@ def check_csv_files(output_dir, num_devices, num_kernels): return file_dict -def launch_omniperf(config, options, workload_dir, check_success=True): - """Launch Omniperf with command-line optoins +def launch_rocprof_compute(config, options, workload_dir, check_success=True): + """Launch rocprof-compute with command-line options Args: config (list): runtime configuration settings - options (list): command line options to provide to omniperf + options (list): command line options to provide to rocprof-compute workload_dir (string): desired output directory check_success (bool, optional): Whether to verify successful exit condition. Defaults to True. @@ -142,7 +142,7 @@ def launch_omniperf(config, options, workload_dir, check_success=True): with patch( "sys.argv", options + ["--path", workload_dir, "--"] + config["app_1"] ): - config["omniperf"].main() + config["rocprofiler-compute"].main() # verify run status if check_success: diff --git a/utils/build.sh b/utils/build.sh index 5aebc0f9b..80711889d 100755 --- a/utils/build.sh +++ b/utils/build.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash -pyinstaller src/omniperf.py \ - --name "omniperf" \ +pyinstaller src/rocprofiler-compute.py \ + --name "rocprofiler-compute" \ --add-data "src/perfmon_pub/*:perfmon_pub" \ --add-data "src/utils/*:utils" \ --add-data "src/soc_params/*.csv:soc_params" \ - --add-data "src/omniperf_analyze/*:omniperf_analyze" \ + --add-data "src/rocprof_compute_analyze/*:rocprof_compute_analyze" \ --hidden-import matplotlib.backends.backend_pdf \ ${@} @@ -53,14 +53,14 @@ echo "(build.sh) Loading dash_svg" # Take care of dash-svg module that isn't detected by PyInstaller dash_info=$(pip3 show dash_svg) dash_loc=$(sed -n '8p' <<<"$dash_info") -cp -r ${dash_loc:10}/dash_svg "$distpath"/omniperf/ +cp -r ${dash_loc:10}/dash_svg "$distpath"/rocprofiler-compute/ echo "(build.sh) Fixing flattened directories" #TODO: Copy orig file structure from over to flattened packaged version -rm -rf "$distpath"/omniperf/omniperf_analyze/ -cp -r src/omniperf_analyze/ "$distpath"/omniperf/ +rm -rf "$distpath"/rocprofiler-compute/rocprof_compute_analyze/ +cp -r src/rocprof_compute_analyze/ "$distpath"/rocprofiler-compute/ -rm -rf "$distpath"/omniperf/perfmon_pub/ -cp -r src/perfmon_pub/ "$distpath"/omniperf/ +rm -rf "$distpath"/rocprofiler-compute/perfmon_pub/ +cp -r src/perfmon_pub/ "$distpath"/rocprofiler-compute/ -rm -rf "$distpath"/omniperf/perfmon/ +rm -rf "$distpath"/rocprofiler-compute/perfmon/