Merge pull request #162 from AMDResearch/dev

Prep v1.0.9

[ROCm/rocprofiler-compute commit: 9aeac83961]
This commit is contained in:
Cole Ramos
2023-08-16 14:29:40 -07:00
committed by GitHub
61 changed files with 2320 additions and 943 deletions
File diff suppressed because one or more lines are too long
@@ -7,7 +7,7 @@ gpgkey=https://repo.radeon.com/rocm/rocm.gpg.key
[amdgpu]
name=amdgpu
baseurl=https://repo.radeon.com/amdgpu/latest/rhel/8.5/main/x86_64
baseurl=https://repo.radeon.com/amdgpu/latest/rhel/8.8/main/x86_64
enabled=1
gpgcheck=1
gpgkey=https://repo.radeon.com/rocm/rocm.gpg.key
@@ -0,0 +1,13 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-eslint-config
*/
{
"extends": ["@grafana/eslint-config"],
"root": true,
"rules": {
"react/prop-types": "off"
}
}
@@ -0,0 +1,16 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
*/
module.exports = {
"endOfLine": "auto",
"printWidth": 120,
"trailingComma": "es5",
"semi": true,
"jsxSingleQuote": false,
"singleQuote": true,
"useTabs": false,
"tabWidth": 2
};
@@ -0,0 +1,16 @@
ARG grafana_version=latest
ARG grafana_image=grafana-enterprise
FROM grafana/${grafana_image}:${grafana_version}
# Make it as simple as possible to access the grafana instance for development purposes
# Do NOT enable these settings in a public facing / production grafana instance
ENV GF_AUTH_ANONYMOUS_ORG_ROLE "Admin"
ENV GF_AUTH_ANONYMOUS_ENABLED "true"
ENV GF_AUTH_BASIC_ENABLED "false"
# Set development mode so plugins can be loaded without the need to sign
ENV GF_DEFAULT_APP_MODE "development"
# Inject livereload script into grafana index.html
USER root
RUN sed -i 's/<\/body><\/html>/<script src=\"http:\/\/localhost:35729\/livereload.js\"><\/script><\/body><\/html>/g' /usr/share/grafana/public/views/index.html
@@ -0,0 +1,164 @@
# Default build configuration by Grafana
**This is an auto-generated directory and is not intended to be changed! ⚠️**
The `.config/` directory holds basic configuration for the different tools
that are used to develop, test and build the project. In order to make it updates easier we ask you to
not edit files in this folder to extend configuration.
## How to extend the basic configs?
Bear in mind that you are doing it at your own risk, and that extending any of the basic configuration can lead
to issues around working with the project.
### Extending the ESLint config
Edit the `.eslintrc` file in the project root in order to extend the ESLint configuration.
**Example:**
```json
{
"extends": "./.config/.eslintrc",
"rules": {
"react/prop-types": "off"
}
}
```
---
### Extending the Prettier config
Edit the `.prettierrc.js` file in the project root in order to extend the Prettier configuration.
**Example:**
```javascript
module.exports = {
// Prettier configuration provided by Grafana scaffolding
...require('./.config/.prettierrc.js'),
semi: false,
};
```
---
### Extending the Jest config
There are two configuration in the project root that belong to Jest: `jest-setup.js` and `jest.config.js`.
**`jest-setup.js`:** A file that is run before each test file in the suite is executed. We are using it to
set up the Jest DOM for the testing library and to apply some polyfills. ([link to Jest docs](https://jestjs.io/docs/configuration#setupfilesafterenv-array))
**`jest.config.js`:** The main Jest configuration file that extends the Grafana recommended setup. ([link to Jest docs](https://jestjs.io/docs/configuration))
#### ESM errors with Jest
A common issue found with the current jest config involves importing an npm package which only offers an ESM build. These packages cause jest to error with `SyntaxError: Cannot use import statement outside a module`. To work around this we provide a list of known packages to pass to the `[transformIgnorePatterns](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring)` jest configuration property. If need be this can be extended in the following way:
```javascript
process.env.TZ = 'UTC';
const { grafanaESModules, nodeModulesToTransform } = require('./config/jest/utils');
module.exports = {
// Jest configuration provided by Grafana
...require('./.config/jest.config'),
// Inform jest to only transform specific node_module packages.
transformIgnorePatterns: [nodeModulesToTransform([...grafanaESModules, 'packageName'])],
};
```
---
### Extending the TypeScript config
Edit the `tsconfig.json` file in the project root in order to extend the TypeScript configuration.
**Example:**
```json
{
"extends": "./.config/tsconfig.json",
"compilerOptions": {
"preserveConstEnums": true
}
}
```
---
### Extending the Webpack config
Follow these steps to extend the basic Webpack configuration that lives under `.config/`:
#### 1. Create a new Webpack configuration file
Create a new config file that is going to extend the basic one provided by Grafana.
It can live in the project root, e.g. `webpack.config.ts`.
#### 2. Merge the basic config provided by Grafana and your custom setup
We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge) for this.
```typescript
// webpack.config.ts
import type { Configuration } from 'webpack';
import { merge } from 'webpack-merge';
import grafanaConfig from './.config/webpack/webpack.config';
const config = async (env): Promise<Configuration> => {
const baseConfig = await grafanaConfig(env);
return merge(baseConfig, {
// Add custom config here...
output: {
asyncChunks: true,
},
});
};
export default config;
```
#### 3. Update the `package.json` to use the new Webpack config
We need to update the `scripts` in the `package.json` to use the extended Webpack configuration.
**Update for `build`:**
```diff
-"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
+"build": "webpack -c ./webpack.config.ts --env production",
```
**Update for `dev`:**
```diff
-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
+"dev": "webpack -w -c ./webpack.config.ts --env development",
```
### Configure grafana image to use when running docker
By default `grafana-enterprise` will be used as the docker image for all docker related commands. If you want to override this behaviour simply alter the `docker-compose.yaml` by adding the following build arg `grafana_image`.
**Example:**
```yaml
version: '3.7'
services:
grafana:
container_name: 'myorg-basic-app'
build:
context: ./.config
args:
grafana_version: ${GRAFANA_VERSION:-9.1.2}
grafana_image: ${GRAFANA_IMAGE:-grafana}
```
In this example we are assigning the environment variable `GRAFANA_IMAGE` to the build arg `grafana_image` with a default value of `grafana`. This will give you the possibility to set the value while running the docker-compose commands which might be convinent in some scenarios.
---
@@ -0,0 +1,25 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-jest-config
*/
import '@testing-library/jest-dom';
// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
Object.defineProperty(global, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
HTMLCanvasElement.prototype.getContext = () => {};
@@ -0,0 +1,43 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-jest-config
*/
const path = require('path');
const { grafanaESModules, nodeModulesToTransform } = require('./jest/utils');
module.exports = {
moduleNameMapper: {
'\\.(css|scss|sass)$': 'identity-obj-proxy',
'react-inlinesvg': path.resolve(__dirname, 'jest', 'mocks', 'react-inlinesvg.tsx'),
},
modulePaths: ['<rootDir>/src'],
setupFilesAfterEnv: ['<rootDir>/jest-setup.js'],
testEnvironment: 'jest-environment-jsdom',
testMatch: [
'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
'<rootDir>/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}',
'<rootDir>/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}',
],
transform: {
'^.+\\.(t|j)sx?$': [
'@swc/jest',
{
sourceMaps: 'inline',
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
decorators: false,
dynamicImport: true,
},
},
},
],
},
// Jest will throw `Cannot use import statement outside module` if it tries to load an
// ES module without it being transformed first. ./config/README.md#esm-errors-with-jest
transformIgnorePatterns: [nodeModulesToTransform(grafanaESModules)],
};
@@ -0,0 +1,25 @@
// Due to the grafana/ui Icon component making fetch requests to
// `/public/img/icon/<icon_name>.svg` we need to mock react-inlinesvg to prevent
// the failed fetch requests from displaying errors in console.
import React from 'react';
type Callback = (...args: any[]) => void;
export interface StorageItem {
content: string;
queue: Callback[];
status: string;
}
export const cacheStore: { [key: string]: StorageItem } = Object.create(null);
const SVG_FILE_NAME_REGEX = /(.+)\/(.+)\.svg$/;
const InlineSVG = ({ src }: { src: string }) => {
// testId will be the file name without extension (e.g. `public/img/icons/angle-double-down.svg` -> `angle-double-down`)
const testId = src.replace(SVG_FILE_NAME_REGEX, '$2');
return <svg xmlns="http://www.w3.org/2000/svg" data-testid={testId} viewBox="0 0 24 24" />;
};
export default InlineSVG;
@@ -0,0 +1,31 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
*/
/*
* This utility function is useful in combination with jest `transformIgnorePatterns` config
* to transform specific packages (e.g.ES modules) in a projects node_modules folder.
*/
const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!(${moduleNames.join('|')})\/)`;
// Array of known nested grafana package dependencies that only bundle an ESM version
const grafanaESModules = [
'.pnpm', // Support using pnpm symlinked packages
'@grafana/schema',
'd3',
'd3-color',
'd3-force',
'd3-interpolate',
'd3-scale-chromatic',
'ol',
'react-colorful',
'rxjs',
'uuid',
];
module.exports = {
nodeModulesToTransform,
grafanaESModules,
};
@@ -0,0 +1,26 @@
/*
* THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY.
*
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-typescript-config
*/
{
"compilerOptions": {
"alwaysStrict": true,
"declaration": false,
"rootDir": "../src",
"baseUrl": "../src",
"typeRoots": ["../node_modules/@types"],
"resolveJsonModule": true
},
"ts-node": {
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"esModuleInterop": true
},
"transpileOnly": true
},
"include": ["../src", "./types"],
"extends": "@grafana/tsconfig"
}
@@ -0,0 +1,37 @@
// Image declarations
declare module '*.gif' {
const src: string;
export default src;
}
declare module '*.jpg' {
const src: string;
export default src;
}
declare module '*.jpeg' {
const src: string;
export default src;
}
declare module '*.png' {
const src: string;
export default src;
}
declare module '*.webp' {
const src: string;
export default src;
}
declare module '*.svg' {
const content: string;
export default content;
}
// Font declarations
declare module '*.woff';
declare module '*.woff2';
declare module '*.eot';
declare module '*.ttf';
declare module '*.otf';
@@ -0,0 +1,2 @@
export const SOURCE_DIR = 'src';
export const DIST_DIR = 'dist';
@@ -0,0 +1,40 @@
import fs from 'fs';
import path from 'path';
import util from 'util';
import { glob } from 'glob';
import { SOURCE_DIR } from './constants';
export function getPackageJson() {
return require(path.resolve(process.cwd(), 'package.json'));
}
export function getPluginJson() {
return require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
}
export function hasReadme() {
return fs.existsSync(path.resolve(process.cwd(), SOURCE_DIR, 'README.md'));
}
// Support bundling nested plugins by finding all plugin.json files in src directory
// then checking for a sibling module.[jt]sx? file.
export async function getEntries(): Promise<Record<string, string>> {
const pluginsJson = await glob('**/src/**/plugin.json', { absolute: true });
const plugins = await Promise.all(pluginsJson.map((pluginJson) => {
const folder = path.dirname(pluginJson);
return glob(`${folder}/module.{ts,tsx,js,jsx}`, { absolute: true });
})
);
return plugins.reduce((result, modules) => {
return modules.reduce((result, module) => {
const pluginPath = path.dirname(module);
const pluginName = path.relative(process.cwd(), pluginPath).replace(/src\/?/i, '');
const entryName = pluginName === '' ? 'module' : `${pluginName}/module`;
result[entryName] = module;
return result;
}, result);
}, {});
}
@@ -0,0 +1,201 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-webpack-config
*/
import CopyWebpackPlugin from 'copy-webpack-plugin';
import ESLintPlugin from 'eslint-webpack-plugin';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import LiveReloadPlugin from 'webpack-livereload-plugin';
import path from 'path';
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
import { Configuration } from 'webpack';
import { getPackageJson, getPluginJson, hasReadme, getEntries } from './utils';
import { SOURCE_DIR, DIST_DIR } from './constants';
const pluginJson = getPluginJson();
const config = async (env): Promise<Configuration> => ({
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
},
context: path.join(process.cwd(), SOURCE_DIR),
devtool: env.production ? 'source-map' : 'eval-source-map',
entry: await getEntries(),
externals: [
'lodash',
'jquery',
'moment',
'slate',
'emotion',
'@emotion/react',
'@emotion/css',
'prismjs',
'slate-plain-serializer',
'@grafana/slate-react',
'react',
'react-dom',
'react-redux',
'redux',
'rxjs',
'react-router',
'react-router-dom',
'd3',
'angular',
'@grafana/ui',
'@grafana/runtime',
'@grafana/data',
// Mark legacy SDK imports as external if their name starts with the "grafana/" prefix
({ request }, callback) => {
const prefix = 'grafana/';
const hasPrefix = (request) => request.indexOf(prefix) === 0;
const stripPrefix = (request) => request.substr(prefix.length);
if (hasPrefix(request)) {
return callback(undefined, stripPrefix(request));
}
callback();
},
],
mode: env.production ? 'production' : 'development',
module: {
rules: [
{
exclude: /(node_modules)/,
test: /\.[tj]sx?$/,
use: {
loader: 'swc-loader',
options: {
jsc: {
baseUrl: './src',
target: 'es2015',
loose: false,
parser: {
syntax: 'typescript',
tsx: true,
decorators: false,
dynamicImport: true,
},
},
},
},
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.s[ac]ss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: 'asset/resource',
generator: {
// Keep publicPath relative for host.com/grafana/ deployments
publicPath: `public/plugins/${pluginJson.id}/img/`,
outputPath: 'img/',
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
},
},
{
test: /\.(woff|woff2|eot|ttf|otf)(\?v=\d+\.\d+\.\d+)?$/,
type: 'asset/resource',
generator: {
// Keep publicPath relative for host.com/grafana/ deployments
publicPath: `public/plugins/${pluginJson.id}/fonts/`,
outputPath: 'fonts/',
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
},
},
],
},
output: {
clean: {
keep: new RegExp(`.*?_(amd64|arm(64)?)(.exe)?`),
},
filename: '[name].js',
library: {
type: 'amd',
},
path: path.resolve(process.cwd(), DIST_DIR),
publicPath: '/',
},
plugins: [
new CopyWebpackPlugin({
patterns: [
// If src/README.md exists use it; otherwise the root README
// To `compiler.options.output`
{ from: hasReadme() ? 'README.md' : '../README.md', to: '.', force: true },
{ from: 'plugin.json', to: '.' },
{ from: '../LICENSE', to: '.' },
{ from: '../CHANGELOG.md', to: '.', force: true },
{ from: '**/*.json', to: '.' }, // TODO<Add an error for checking the basic structure of the repo>
{ from: '**/*.svg', to: '.', noErrorOnMissing: true }, // Optional
{ from: '**/*.png', to: '.', noErrorOnMissing: true }, // Optional
{ from: '**/*.html', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'img/**/*', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'libs/**/*', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'static/**/*', to: '.', noErrorOnMissing: true }, // Optional
],
}),
// Replace certain template-variables in the README and plugin.json
new ReplaceInFileWebpackPlugin([
{
dir: DIST_DIR,
files: ['plugin.json', 'README.md'],
rules: [
{
search: /\%VERSION\%/g,
replace: getPackageJson().version,
},
{
search: /\%TODAY\%/g,
replace: new Date().toISOString().substring(0, 10),
},
{
search: /\%PLUGIN_ID\%/g,
replace: pluginJson.id,
},
],
},
]),
new ForkTsCheckerWebpackPlugin({
async: Boolean(env.development),
issue: {
include: [{ file: '**/*.{ts,tsx}' }],
},
typescript: { configFile: path.join(process.cwd(), 'tsconfig.json') },
}),
new ESLintPlugin({
extensions: ['.ts', '.tsx'],
lintDirtyModulesOnly: Boolean(env.development), // don't lint on start, only lint changed files
}),
...(env.development ? [new LiveReloadPlugin()] : []),
],
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
// handle resolving "rootDir" paths
modules: [path.resolve(process.cwd(), 'src'), 'node_modules'],
unsafeCache: true,
},
});
export default config;
@@ -0,0 +1,3 @@
{
"extends": "./.config/.eslintrc"
}
@@ -0,0 +1 @@
16
@@ -1,3 +1,4 @@
module.exports = {
...require("./node_modules/@grafana/toolkit/src/config/prettier.plugin.config.json"),
};
// Prettier configuration provided by Grafana scaffolding
...require("./.config/.prettierrc.js")
};
@@ -0,0 +1,15 @@
version: '3.0'
services:
grafana:
container_name: 'amd-custom-svg'
build:
context: ./.config
args:
grafana_image: ${GRAFANA_IMAGE:-grafana-enterprise}
grafana_version: ${GRAFANA_VERSION:-9.5.3}
ports:
- 3000:3000/tcp
volumes:
- ./dist:/var/lib/grafana/plugins/amd-custom-svg
- ./provisioning:/etc/grafana/provisioning
@@ -0,0 +1,2 @@
// Jest setup provided by Grafana scaffolding
import './.config/jest-setup';
@@ -0,0 +1,8 @@
// force timezone to UTC to allow tests to work regardless of local timezone
// generally used by snapshots, but can affect specific tests
process.env.TZ = 'UTC';
module.exports = {
// Jest configuration provided by Grafana scaffolding
...require('./.config/jest.config'),
};
@@ -3,29 +3,72 @@
"version": "1.0.0",
"description": "",
"scripts": {
"build": "grafana-toolkit plugin:build",
"test": "grafana-toolkit plugin:test",
"dev": "grafana-toolkit plugin:dev",
"watch": "grafana-toolkit plugin:dev --watch",
"sign": "grafana-toolkit plugin:sign",
"start": "yarn watch"
"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
"e2e": "yarn exec cypress install && yarn exec grafana-e2e run",
"e2e:update": "yarn exec cypress install && yarn exec grafana-e2e run --update-screenshots",
"lint": "eslint --cache --ignore-path ./.gitignore --ext .js,.jsx,.ts,.tsx .",
"lint:fix": "yarn run lint --fix",
"server": "docker-compose up --build",
"sign": "npx --yes @grafana/sign-plugin@latest",
"start": "yarn watch",
"test": "jest --watch --onlyChanged",
"test:ci": "jest --passWithNoTests --maxWorkers 4",
"typecheck": "tsc --noEmit"
},
"author": "Audacious Software Group",
"license": "MIT",
"devDependencies": {
"@grafana/toolkit": "latest",
"@babel/core": "^7.21.4",
"@grafana/e2e": "9.5.3",
"@grafana/e2e-selectors": "9.5.3",
"@grafana/eslint-config": "^6.0.0",
"@grafana/tsconfig": "^1.2.0-rc1",
"@swc/core": "^1.3.62",
"@swc/helpers": "^0.5.0",
"@swc/jest": "^0.2.26",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.4",
"@types/jest": "^29.5.0",
"@types/lodash": "^4.14.194",
"@types/node": "^18.15.11",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.3",
"emotion": "10.0.27",
"eslint-webpack-plugin": "^4.0.1",
"fork-ts-checker-webpack-plugin": "^8.0.0",
"glob": "^10.2.7",
"identity-obj-proxy": "3.0.0",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"prettier": "^2.8.7",
"react-monaco-editor": "^0.44.0",
"tslib": "^2.3.1"
"replace-in-file-webpack-plugin": "^1.0.6",
"sass": "1.63.2",
"sass-loader": "13.3.1",
"style-loader": "3.3.3",
"swc-loader": "^0.2.3",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"tslib": "^2.3.1",
"typescript": "4.8.4",
"webpack": "^5.86.0",
"webpack-cli": "^5.1.4",
"webpack-livereload-plugin": "^3.0.2"
},
"engines": {
"node": ">=14"
},
"dependencies": {
"@grafana/runtime": "9.1.2",
"@emotion/css": "^11.1.3",
"@grafana/data": "9.1.2",
"@grafana/runtime": "9.1.2",
"@grafana/ui": "9.1.2",
"@svgdotjs/svg.js": "^3.1.1"
"@svgdotjs/svg.js": "^3.1.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"tslib": "2.5.3"
},
"_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 Omniperf. It's the user's responsibility to accept any licensing implications before building the project.",
"packageManager": "yarn@1.22.19"
}
@@ -1,11 +1,3 @@
{
"extends": "./node_modules/@grafana/toolkit/src/config/tsconfig.plugin.json",
"include": ["src", "types"],
"compilerOptions": {
"types": ["@emotion/core"],
"rootDir": "./src",
"baseUrl": "./src",
"typeRoots": ["./node_modules/@types"],
"jsx": "react"
}
}
"extends": "./.config/tsconfig.json"
}
+41 -49
View File
@@ -40,7 +40,7 @@ from parser import parse
from utils import specs
from utils.perfagg import perfmon_filter, pmc_filter, pmc_perf_split, join_prof
from utils import remove_workload
from utils import csv_converter # Import workload
from utils import csv_processor # Import workload
from omniperf_analyze.omniperf_analyze import roofline_only # Standalone roofline
from omniperf_analyze.omniperf_analyze import analyze # CLI analysis
@@ -254,13 +254,12 @@ def gen_sysinfo(workload_name, workload_dir, ip_blocks, app_cmd, skip_roof):
def mongo_import(args, profileAndImport):
# Validate target directory
connectionInfo, Extractionlvl = csv_converter.parse(args, profileAndImport)
connectionInfo, Extractionlvl = csv_processor.parse(args, profileAndImport)
# Convert and upload data
print("-- Conversion & Upload in Progress --")
csv_converter.convert_folder(connectionInfo, Extractionlvl)
csv_processor.convert_folder(connectionInfo, Extractionlvl)
print("-- Complete! --")
################################################
# Roofline Helpers
################################################
@@ -439,30 +438,15 @@ def characterize_app(args, VER):
else:
run_prof(fname, workload_dir, perfmon_dir, app_cmd, args.target, log, args.verbose)
# run again with timestamps
success, output = capture_subprocess_output(
[
rocprof_cmd,
# "-i", fname,
# "-m", perfmon_dir + "/" + "metrics.xml",
"--timestamp",
"on",
"-o",
workload_dir + "/" + "timestamps.csv",
'"' + app_cmd + '"',
]
)
log.write(output)
# Update pmc_perf.csv timestamps
# Update timestamps
replace_timestamps(workload_dir, log)
# Manually join each pmc_perf*.csv output
if args.use_rocscope == False:
# Manually join each pmc_perf*.csv output
join_prof(workload_dir, args.join_type, log, args.verbose)
# Close log
# Demangle and overwrite original KernelNames
csv_processor.kernel_name_shortener(workload_dir, args.kernelVerbose)
log.close()
@@ -559,6 +543,10 @@ def omniperf_profile(args, VER):
print("IP Blocks: All")
else:
print("IP Blocks: ", args.ipblocks)
if args.kernelVerbose > 5:
print("KernelName verbose level: DISABLED")
else:
print("KernelName verbose level: ", str(args.kernelVerbose))
# Set up directories
workload_dir = args.path + "/" + args.name + "/" + args.target
@@ -675,27 +663,16 @@ def omniperf_profile(args, VER):
run_rocscope(args, fname)
else:
run_prof(fname, workload_dir, perfmon_dir, args.remaining, args.target, log, args.verbose)
# run again with timestamps
success, output = capture_subprocess_output(
[
rocprof_cmd,
# "-i", fname,
# "-m", perfmon_dir + "/" + "metrics.xml",
"--timestamp",
"on",
"-o",
workload_dir + "/" + "timestamps.csv",
'"' + args.remaining + '"',
]
)
log.write(output)
# Update pmc_perf.csv timestamps
# Update timestamps
replace_timestamps(workload_dir, log)
# Manually join each pmc_perf*.csv output
if args.use_rocscope == False:
# Manually join each pmc_perf*.csv output
join_prof(workload_dir, args.join_type, log, args.verbose)
# Demangle and overwrite original KernelNames
csv_processor.kernel_name_shortener(workload_dir, args.kernelVerbose)
# Generate sysinfo
gen_sysinfo(args.name, workload_dir, args.ipblocks, args.remaining, args.no_roof)
@@ -768,6 +745,7 @@ def main():
# PROFILE MODE
##############
if args.mode == "profile":
Extractionlvl = args.kernelVerbose
print("Resolving rocprof")
resolve_rocprof()
# Cannot access parent directories
@@ -878,6 +856,20 @@ def main():
my_parser,
"Access denied. Cannot access parent directories in path ../",
)
if args.filter_metrics and args.gui:
throw_parse_error(
my_parser,
"""
omniperf analyze --path <workload_path> [analyze options]
\n\n-------------------------------------------------------------------------------
\nExamples:
\n\tomniperf analyze -p workloads/vcopy/mi200/ --list-metrics gfx90a
\n\tomniperf analyze -p workloads/mixbench/mi200/ --filter-dispatch-ids 12 34 --decimal 3
\n\tomniperf analyze -p workloads/mixbench/mi200/ --gui
\n-------------------------------------------------------------------------------\n
\ntool: error: --gui cannot be used in combination with: -b/--metric
"""
)
print("\n--------\nAnalyze\n--------\n")
# Ensure absolute path
for dir in args.path:
@@ -899,15 +891,15 @@ def main():
throw_parse_error(
my_parser,
"""
omniperf analyze --path <workload_path> [analyze options]
\n\n-------------------------------------------------------------------------------
\nExamples:
\n\tomniperf analyze -p workloads/vcopy/mi200/ --list-metrics gfx90a
\n\tomniperf analyze -p workloads/mixbench/mi200/ --filter-dispatch-ids 12 34 --decimal 3
\n\tomniperf analyze -p workloads/mixbench/mi200/ --gui
\n-------------------------------------------------------------------------------\n
\ntool: error: the following arguments are required: -p/--path
""",
omniperf analyze --path <workload_path> [analyze options]
\n\n-------------------------------------------------------------------------------
\nExamples:
\n\tomniperf analyze -p workloads/vcopy/mi200/ --list-metrics gfx90a
\n\tomniperf analyze -p workloads/mixbench/mi200/ --filter-dispatch-ids 12 34 --decimal 3
\n\tomniperf analyze -p workloads/mixbench/mi200/ --gui
\n-------------------------------------------------------------------------------\n
\ntool: error: the following arguments are required: -p/--path
""",
)
sys.exit(0) # Indicate successful on exit
@@ -213,6 +213,15 @@ ul#nav li {
font-size: 14px;
text-align: left;
}
.dash-dropdown input{
color: black;
}
.dash-dropdown .Select-placeholder{
color: black;
}
.VirtualizedSelectOption {
overflow: hidden;
}
@@ -11,6 +11,7 @@ Panel Config:
data source:
- metric_table:
id: 201
title: Speed-of-Light
header:
metric: Metric
value: Value
@@ -13,40 +13,61 @@ Panel Config:
title: Instruction Mix
header:
metric: Metric
count: Count
avg: Avg
min: Min
max: Max
unit: Unit
tips: Tips
style:
type: simple_bar
label_txt: (# of instr + $normUnit)
metric:
VALU - Vector:
count: None # No HW module
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
VMEM:
count: None # No HW module
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
LDS:
count: AVG((SQ_INSTS_LDS / $denom))
unit: $normUnit
avg: AVG((SQ_INSTS_LDS / $denom))
min: MIN((SQ_INSTS_LDS / $denom))
max: MAX((SQ_INSTS_LDS / $denom))
unit: (instr + $normUnit)
tips:
VALU - MFMA:
count: None # No HW module
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
SALU:
count: AVG((SQ_INSTS_SALU / $denom))
avg: AVG((SQ_INSTS_SALU / $denom))
min: MIN((SQ_INSTS_SALU / $denom))
max: MAX((SQ_INSTS_SALU / $denom))
unit: (instr + $normUnit)
tips:
SMEM:
count: AVG((SQ_INSTS_SMEM / $denom))
avg: AVG((SQ_INSTS_SMEM / $denom))
min: MIN((SQ_INSTS_SMEM / $denom))
max: MAX((SQ_INSTS_SMEM / $denom))
unit: (instr + $normUnit)
tips:
Branch:
count: AVG((SQ_INSTS_BRANCH / $denom))
avg: AVG((SQ_INSTS_BRANCH / $denom))
min: MIN((SQ_INSTS_BRANCH / $denom))
max: MAX((SQ_INSTS_BRANCH / $denom))
unit: (instr + $normUnit)
tips:
GDS:
count: AVG((SQ_INSTS_GDS / $denom))
avg: AVG((SQ_INSTS_GDS / $denom))
min: MIN((SQ_INSTS_GDS / $denom))
max: MAX((SQ_INSTS_GDS / $denom))
unit: (instr + $normUnit)
tips:
@@ -55,68 +76,103 @@ Panel Config:
title: VALU Arithmetic Instr Mix
header:
metric: Metric
count: Count
avg: Avg
min: Min
max: Max
unit: Unit
tips: Tips
style:
type: simple_bar
label_txt: (# of instr + $normUnit)
metric:
INT-32:
count: None # No perf counter
unit: $normUnit
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
INT-64:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F16-ADD:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F16-Mult:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F16-FMA:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F16-Trans:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F32-ADD:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F32-Mult:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F32-FMA:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F32-Trans:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F64-ADD:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F64-Mult:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F64-FMA:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
F64-Trans:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
Conversion:
count: None # No perf counter
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
@@ -15,6 +15,11 @@ Panel Config:
metric: Metric
value: Value
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
valu_flops_pop:
value: None # No perf counter
@@ -14,21 +14,31 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Utilization:
value: AVG(((100 * SQ_LDS_IDX_ACTIVE) / (GRBM_GUI_ACTIVE * $numCU)))
unit: Pct of Peak
tips:
Access Rate:
value: AVG(((200 * SQ_ACTIVE_INST_LDS) / (GRBM_GUI_ACTIVE * $numCU)))
unit: Pct of Peak
tips:
Bandwidth (Pct-of-Peak):
value: AVG((((((SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT) * 4) * TO_INT($LDSBanks))
/ (EndNs - BeginNs)) / (($sclk * $numCU) * 0.00128)))
unit: Pct of Peak
tips:
Bank Conflict Rate:
value: AVG((((SQ_LDS_BANK_CONFLICT * 3.125) / (SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT))
if ((SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT) != 0) else None))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,15 +14,23 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Bandwidth:
value: AVG(((SQC_ICACHE_REQ * 100000) / (($sclk * $numSQC)
* (EndNs - BeginNs))))
unit: Pct of Peak
tips:
Cache Hit:
value: AVG(((SQC_ICACHE_HITS * 100) / ((SQC_ICACHE_HITS + SQC_ICACHE_MISSES)
+ SQC_ICACHE_MISSES_DUPLICATE)))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,16 +14,24 @@ Panel Config:
header:
mertic: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Bandwidth:
value: AVG(((SQC_DCACHE_REQ * 100000) / (($sclk * $numSQC)
* (EndNs - BeginNs))))
unit: Pct of Peak
tips:
Cache Hit:
value:
AVG((((SQC_DCACHE_HITS * 100) / (SQC_DCACHE_HITS + SQC_DCACHE_MISSES + SQC_DCACHE_MISSES_DUPLICATE))
if ((SQC_DCACHE_HITS + SQC_DCACHE_MISSES + SQC_DCACHE_MISSES_DUPLICATE) != 0) else None))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,25 +14,35 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Buffer Coalescing:
value: AVG(((((TA_TOTAL_WAVEFRONTS_sum * 64) * 100) / (TCP_TOTAL_ACCESSES_sum
* 4)) if (TCP_TOTAL_ACCESSES_sum != 0) else None))
unit: Pct of Peak
tips:
Cache Util:
value: AVG((((TCP_GATE_EN2_sum * 100) / TCP_GATE_EN1_sum) if (TCP_GATE_EN1_sum
!= 0) else None))
unit: Pct of Peak
tips:
Cache BW:
value: ((100 * AVG(((TCP_TOTAL_CACHE_ACCESSES_sum * 64) / (EndNs - BeginNs))))
/ ((($sclk / 1000) * 64) * $numCU))
unit: Pct of Peak
tips:
Cache Hit:
value: AVG(((100 - ((100 * (((TCP_TCC_READ_REQ_sum + TCP_TCC_WRITE_REQ_sum)
+ TCP_TCC_ATOMIC_WITH_RET_REQ_sum) + TCP_TCC_ATOMIC_WITHOUT_RET_REQ_sum))
/ TCP_TOTAL_CACHE_ACCESSES_sum)) if (TCP_TOTAL_CACHE_ACCESSES_sum != 0) else
None))
unit: Pct of Peak
tips:
- metric_table:
@@ -248,6 +258,8 @@ Panel Config:
max: Max
unit: Unit
tips: Tips
style:
type: simple_multi_bar
metric:
NC - Read:
xfer: Read
@@ -361,7 +373,7 @@ Panel Config:
mean: AVG((TCP_UTCL1_REQUEST_sum / $denom))
min: MIN((TCP_UTCL1_REQUEST_sum / $denom))
max: MAX((TCP_UTCL1_REQUEST_sum / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
Hit Ratio:
mean: AVG((((100 * TCP_UTCL1_TRANSLATION_HIT_sum) / TCP_UTCL1_REQUEST_sum) if
@@ -376,17 +388,17 @@ Panel Config:
mean: AVG((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
min: MIN((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
max: MAX((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
units: ( + $normUnit)
units: (Hits + $normUnit)
tips:
Misses (Translation):
mean: AVG((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
min: MIN((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
max: MAX((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
units: ( + $normUnit)
units: (Misses + $normUnit)
tips:
Misses (Permission):
mean: AVG((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
min: MIN((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
max: MAX((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
units: ( + $normUnit)
units: (Misses + $normUnit)
tips:
@@ -16,6 +16,8 @@ Panel Config:
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
metric:
L2 Util:
value: AVG(((TCC_BUSY_sum * 100) / (TO_INT($L2Banks) * GRBM_GUI_ACTIVE)))
@@ -301,6 +303,8 @@ Panel Config:
max: Max
unit: Unit
tips: Tips
style:
type: simple_multi_bar
metric:
Read - Remote Socket Stall:
type: Remote Socket Stall
@@ -204,7 +204,7 @@ Panel Config:
+ TO_INT(TCC_REQ[22])) + TO_INT(TCC_REQ[23])) + TO_INT(TCC_REQ[24])) + TO_INT(TCC_REQ[25]))
+ TO_INT(TCC_REQ[26])) + TO_INT(TCC_REQ[27])) + TO_INT(TCC_REQ[28])) + TO_INT(TCC_REQ[29]))
+ TO_INT(TCC_REQ[30])) + TO_INT(TCC_REQ[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Read Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_READ[0]) + TO_INT(TCC_READ[1]))
@@ -247,7 +247,7 @@ Panel Config:
+ TO_INT(TCC_READ[24])) + TO_INT(TCC_READ[25])) + TO_INT(TCC_READ[26])) +
TO_INT(TCC_READ[27])) + TO_INT(TCC_READ[28])) + TO_INT(TCC_READ[29])) + TO_INT(TCC_READ[30]))
+ TO_INT(TCC_READ[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Write Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_WRITE[0]) + TO_INT(TCC_WRITE[1]))
@@ -294,7 +294,7 @@ Panel Config:
+ TO_INT(TCC_WRITE[24])) + TO_INT(TCC_WRITE[25])) + TO_INT(TCC_WRITE[26]))
+ TO_INT(TCC_WRITE[27])) + TO_INT(TCC_WRITE[28])) + TO_INT(TCC_WRITE[29]))
+ TO_INT(TCC_WRITE[30])) + TO_INT(TCC_WRITE[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Atomic Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_ATOMIC[0]) + TO_INT(TCC_ATOMIC[1]))
@@ -345,7 +345,7 @@ Panel Config:
+ TO_INT(TCC_ATOMIC[26])) + TO_INT(TCC_ATOMIC[27])) + TO_INT(TCC_ATOMIC[28]))
+ TO_INT(TCC_ATOMIC[29])) + TO_INT(TCC_ATOMIC[30])) + TO_INT(TCC_ATOMIC[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Read Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_RDREQ[0]) + TO_INT(TCC_EA_RDREQ[1]))
@@ -396,7 +396,7 @@ Panel Config:
+ TO_INT(TCC_EA_RDREQ[26])) + TO_INT(TCC_EA_RDREQ[27])) + TO_INT(TCC_EA_RDREQ[28]))
+ TO_INT(TCC_EA_RDREQ[29])) + TO_INT(TCC_EA_RDREQ[30])) + TO_INT(TCC_EA_RDREQ[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Write Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_WRREQ[0]) + TO_INT(TCC_EA_WRREQ[1]))
@@ -447,7 +447,7 @@ Panel Config:
+ TO_INT(TCC_EA_WRREQ[26])) + TO_INT(TCC_EA_WRREQ[27])) + TO_INT(TCC_EA_WRREQ[28]))
+ TO_INT(TCC_EA_WRREQ[29])) + TO_INT(TCC_EA_WRREQ[30])) + TO_INT(TCC_EA_WRREQ[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Atomic Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_ATOMIC[0]) + TO_INT(TCC_EA_ATOMIC[1]))
@@ -498,7 +498,7 @@ Panel Config:
+ TO_INT(TCC_EA_ATOMIC[26])) + TO_INT(TCC_EA_ATOMIC[27])) + TO_INT(TCC_EA_ATOMIC[28]))
+ TO_INT(TCC_EA_ATOMIC[29])) + TO_INT(TCC_EA_ATOMIC[30])) + TO_INT(TCC_EA_ATOMIC[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Read Lat:
mean: AVG((((((((((((((((((((((((((((((((((TCC_EA_RDREQ_LEVEL[0] + TCC_EA_RDREQ_LEVEL[1])
@@ -11,6 +11,7 @@ Panel Config:
data source:
- metric_table:
id: 201
title: Speed-of-Light
header:
metric: Metric
value: Value
@@ -13,40 +13,61 @@ Panel Config:
title: Instruction Mix
header:
metric: Metric
count: Count
avg: Avg
min: Min
max: Max
unit: Unit
tips: Tips
style:
type: simple_bar
label_txt: (# of instr + $normUnit)
metric:
VALU - Vector:
count: AVG(((SQ_INSTS_VALU - SQ_INSTS_MFMA) / $denom))
avg: AVG(((SQ_INSTS_VALU - SQ_INSTS_MFMA) / $denom))
min: MIN(((SQ_INSTS_VALU - SQ_INSTS_MFMA) / $denom))
max: MAX(((SQ_INSTS_VALU - SQ_INSTS_MFMA) / $denom))
unit: (instr + $normUnit)
tips:
VMEM:
count: AVG(((SQ_INSTS_VMEM - SQ_INSTS_FLAT_LDS_ONLY) / $denom))
avg: AVG(((SQ_INSTS_VMEM - SQ_INSTS_FLAT_LDS_ONLY) / $denom))
min: MIN(((SQ_INSTS_VMEM - SQ_INSTS_FLAT_LDS_ONLY) / $denom))
max: MAX(((SQ_INSTS_VMEM - SQ_INSTS_FLAT_LDS_ONLY) / $denom))
unit: (instr + $normUnit)
tips:
LDS:
count: AVG((SQ_INSTS_LDS / $denom))
avg: AVG((SQ_INSTS_LDS / $denom))
min: MIN((SQ_INSTS_LDS / $denom))
max: MAX((SQ_INSTS_LDS / $denom))
unit: (instr + $normUnit)
tips:
VALU - MFMA:
count: None # No HW module
avg: None # No HW module
min: None # No HW module
max: None # No HW module
unit: (instr + $normUnit)
tips:
SALU:
count: AVG((SQ_INSTS_SALU / $denom))
avg: AVG((SQ_INSTS_SALU / $denom))
min: MIN((SQ_INSTS_SALU / $denom))
max: MAX((SQ_INSTS_SALU / $denom))
unit: (instr + $normUnit)
tips:
SMEM:
count: AVG((SQ_INSTS_SMEM / $denom))
avg: AVG((SQ_INSTS_SMEM / $denom))
min: MIN((SQ_INSTS_SMEM / $denom))
max: MAX((SQ_INSTS_SMEM / $denom))
unit: (instr + $normUnit)
tips:
Branch:
count: AVG((SQ_INSTS_BRANCH / $denom))
avg: AVG((SQ_INSTS_BRANCH / $denom))
min: MIN((SQ_INSTS_BRANCH / $denom))
max: MAX((SQ_INSTS_BRANCH / $denom))
unit: (instr + $normUnit)
tips:
GDS:
count: AVG((SQ_INSTS_GDS / $denom))
avg: AVG((SQ_INSTS_GDS / $denom))
min: MIN((SQ_INSTS_GDS / $denom))
max: MAX((SQ_INSTS_GDS / $denom))
unit: (instr + $normUnit)
tips:
@@ -55,68 +76,103 @@ Panel Config:
title: VALU Arithmetic Instr Mix
header:
metric: Metric
count: Count
avg: Avg
min: Min
max: Max
unit: Unit
tips: Tips
style:
type: simple_bar
label_txt: (# of instr + $normUnit)
metric:
INT-32:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
INT-64:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F16-ADD:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F16-Mult:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F16-FMA:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F16-Trans:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F32-ADD:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F32-Mult:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F32-FMA:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F32-Trans:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F64-ADD:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F64-Mult:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F64-FMA:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
F64-Trans:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
Conversion:
count: None # No perf counter
avg: None # No perf counter
min: None # No perf counter
max: None # No perf counter
unit: (instr + $normUnit)
tips:
@@ -15,6 +15,11 @@ Panel Config:
metric: Metric
value: Value
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
valu_flops_pop:
value: None # No perf counter
@@ -14,21 +14,31 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Utilization:
value: AVG(((100 * SQ_LDS_IDX_ACTIVE) / (GRBM_GUI_ACTIVE * $numCU)))
unit: Pct of Peak
tips:
Access Rate:
value: AVG(((200 * SQ_ACTIVE_INST_LDS) / (GRBM_GUI_ACTIVE * $numCU)))
unit: Pct of Peak
tips:
Bandwidth (Pct-of-Peak):
value: AVG((((((SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT) * 4) * TO_INT($LDSBanks))
/ (EndNs - BeginNs)) / (($sclk * $numCU) * 0.00128)))
unit: Pct of Peak
tips:
Bank Conflict Rate:
value: AVG((((SQ_LDS_BANK_CONFLICT * 3.125) / (SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT))
if ((SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT) != 0) else None))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,15 +14,23 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Bandwidth:
value: AVG(((SQC_ICACHE_REQ * 100000) / (($sclk * $numSQC)
* (EndNs - BeginNs))))
unit: Pct of Peak
tips:
Cache Hit:
value: AVG(((SQC_ICACHE_HITS * 100) / ((SQC_ICACHE_HITS + SQC_ICACHE_MISSES)
+ SQC_ICACHE_MISSES_DUPLICATE)))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,16 +14,24 @@ Panel Config:
header:
mertic: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Bandwidth:
value: AVG(((SQC_DCACHE_REQ * 100000) / (($sclk * $numSQC)
* (EndNs - BeginNs))))
unit: Pct of Peak
tips:
Cache Hit:
value:
AVG((((SQC_DCACHE_HITS * 100) / (SQC_DCACHE_HITS + SQC_DCACHE_MISSES + SQC_DCACHE_MISSES_DUPLICATE))
if ((SQC_DCACHE_HITS + SQC_DCACHE_MISSES + SQC_DCACHE_MISSES_DUPLICATE) != 0) else None))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,25 +14,35 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Buffer Coalescing:
value: AVG(((((TA_TOTAL_WAVEFRONTS_sum * 64) * 100) / (TCP_TOTAL_ACCESSES_sum
* 4)) if (TCP_TOTAL_ACCESSES_sum != 0) else None))
unit: Pct of Peak
tips:
Cache Util:
value: AVG((((TCP_GATE_EN2_sum * 100) / TCP_GATE_EN1_sum) if (TCP_GATE_EN1_sum
!= 0) else None))
unit: Pct of Peak
tips:
Cache BW:
value: ((100 * AVG(((TCP_TOTAL_CACHE_ACCESSES_sum * 64) / (EndNs - BeginNs))))
/ ((($sclk / 1000) * 64) * $numCU))
unit: Pct of Peak
tips:
Cache Hit:
value: AVG(((100 - ((100 * (((TCP_TCC_READ_REQ_sum + TCP_TCC_WRITE_REQ_sum)
+ TCP_TCC_ATOMIC_WITH_RET_REQ_sum) + TCP_TCC_ATOMIC_WITHOUT_RET_REQ_sum))
/ TCP_TOTAL_CACHE_ACCESSES_sum)) if (TCP_TOTAL_CACHE_ACCESSES_sum != 0) else
None))
unit: Pct of Peak
tips:
- metric_table:
@@ -248,6 +258,8 @@ Panel Config:
max: Max
unit: Unit
tips: Tips
style:
type: simple_multi_bar
metric:
NC - Read:
xfer: Read
@@ -361,7 +373,7 @@ Panel Config:
mean: AVG((TCP_UTCL1_REQUEST_sum / $denom))
min: MIN((TCP_UTCL1_REQUEST_sum / $denom))
max: MAX((TCP_UTCL1_REQUEST_sum / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
Hit Ratio:
mean: AVG((((100 * TCP_UTCL1_TRANSLATION_HIT_sum) / TCP_UTCL1_REQUEST_sum) if
@@ -376,17 +388,17 @@ Panel Config:
mean: AVG((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
min: MIN((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
max: MAX((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
units: ( + $normUnit)
units: (Hits + $normUnit)
tips:
Misses (Translation):
mean: AVG((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
min: MIN((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
max: MAX((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
units: ( + $normUnit)
units: (Misses + $normUnit)
tips:
Misses (Permission):
mean: AVG((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
min: MIN((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
max: MAX((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
units: ( + $normUnit)
units: (Misses + $normUnit)
tips:
@@ -16,6 +16,8 @@ Panel Config:
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
metric:
L2 Util:
value: AVG(((TCC_BUSY_sum * 100) / (TO_INT($L2Banks) * GRBM_GUI_ACTIVE)))
@@ -301,6 +303,8 @@ Panel Config:
max: Max
unit: Unit
tips: Tips
style:
type: simple_multi_bar
metric:
Read - Remote Socket Stall:
type: Remote Socket Stall
@@ -204,7 +204,7 @@ Panel Config:
+ TO_INT(TCC_REQ[22])) + TO_INT(TCC_REQ[23])) + TO_INT(TCC_REQ[24])) + TO_INT(TCC_REQ[25]))
+ TO_INT(TCC_REQ[26])) + TO_INT(TCC_REQ[27])) + TO_INT(TCC_REQ[28])) + TO_INT(TCC_REQ[29]))
+ TO_INT(TCC_REQ[30])) + TO_INT(TCC_REQ[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Read Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_READ[0]) + TO_INT(TCC_READ[1]))
@@ -247,7 +247,7 @@ Panel Config:
+ TO_INT(TCC_READ[24])) + TO_INT(TCC_READ[25])) + TO_INT(TCC_READ[26])) +
TO_INT(TCC_READ[27])) + TO_INT(TCC_READ[28])) + TO_INT(TCC_READ[29])) + TO_INT(TCC_READ[30]))
+ TO_INT(TCC_READ[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Write Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_WRITE[0]) + TO_INT(TCC_WRITE[1]))
@@ -294,7 +294,7 @@ Panel Config:
+ TO_INT(TCC_WRITE[24])) + TO_INT(TCC_WRITE[25])) + TO_INT(TCC_WRITE[26]))
+ TO_INT(TCC_WRITE[27])) + TO_INT(TCC_WRITE[28])) + TO_INT(TCC_WRITE[29]))
+ TO_INT(TCC_WRITE[30])) + TO_INT(TCC_WRITE[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Atomic Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_ATOMIC[0]) + TO_INT(TCC_ATOMIC[1]))
@@ -345,7 +345,7 @@ Panel Config:
+ TO_INT(TCC_ATOMIC[26])) + TO_INT(TCC_ATOMIC[27])) + TO_INT(TCC_ATOMIC[28]))
+ TO_INT(TCC_ATOMIC[29])) + TO_INT(TCC_ATOMIC[30])) + TO_INT(TCC_ATOMIC[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Read Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_RDREQ[0]) + TO_INT(TCC_EA_RDREQ[1]))
@@ -396,7 +396,7 @@ Panel Config:
+ TO_INT(TCC_EA_RDREQ[26])) + TO_INT(TCC_EA_RDREQ[27])) + TO_INT(TCC_EA_RDREQ[28]))
+ TO_INT(TCC_EA_RDREQ[29])) + TO_INT(TCC_EA_RDREQ[30])) + TO_INT(TCC_EA_RDREQ[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Write Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_WRREQ[0]) + TO_INT(TCC_EA_WRREQ[1]))
@@ -447,7 +447,7 @@ Panel Config:
+ TO_INT(TCC_EA_WRREQ[26])) + TO_INT(TCC_EA_WRREQ[27])) + TO_INT(TCC_EA_WRREQ[28]))
+ TO_INT(TCC_EA_WRREQ[29])) + TO_INT(TCC_EA_WRREQ[30])) + TO_INT(TCC_EA_WRREQ[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Atomic Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_ATOMIC[0]) + TO_INT(TCC_EA_ATOMIC[1]))
@@ -498,7 +498,7 @@ Panel Config:
+ TO_INT(TCC_EA_ATOMIC[26])) + TO_INT(TCC_EA_ATOMIC[27])) + TO_INT(TCC_EA_ATOMIC[28]))
+ TO_INT(TCC_EA_ATOMIC[29])) + TO_INT(TCC_EA_ATOMIC[30])) + TO_INT(TCC_EA_ATOMIC[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Read Lat:
mean: AVG((((((((((((((((((((((((((((((((((TCC_EA_RDREQ_LEVEL[0] + TCC_EA_RDREQ_LEVEL[1])
@@ -11,6 +11,7 @@ Panel Config:
data source:
- metric_table:
id: 201
title: Speed-of-Light
header:
metric: Metric
value: Value
@@ -44,9 +45,9 @@ Panel Config:
MFMA FLOPs (BF16):
value: AVG(((SQ_INSTS_VALU_MFMA_MOPS_BF16 * 512) / (EndNs - BeginNs)))
unit: GFLOP
peak: ((($sclk * $numCU) * 512) / 1000)
peak: ((($sclk * $numCU) * 1024) / 1000)
pop: ((100 * AVG(((SQ_INSTS_VALU_MFMA_MOPS_BF16 * 512) / (EndNs - BeginNs))))
/ ((($sclk * $numCU) * 512) / 1000))
/ ((($sclk * $numCU) * 1024) / 1000))
tips:
MFMA FLOPs (F16):
value: AVG(((SQ_INSTS_VALU_MFMA_MOPS_F16 * 512) / (EndNs - BeginNs)))
@@ -13,40 +13,61 @@ Panel Config:
title: Instruction Mix
header:
metric: Metric
count: Count
avg: Avg
min: Min
max: Max
unit: Unit
tips: Tips
style:
type: simple_bar
label_txt: (# of instr + $normUnit)
metric:
VALU - Vector:
count: AVG(((SQ_INSTS_VALU - SQ_INSTS_MFMA) / $denom))
avg: AVG(((SQ_INSTS_VALU - SQ_INSTS_MFMA) / $denom))
min: MIN(((SQ_INSTS_VALU - SQ_INSTS_MFMA) / $denom))
max: MAX(((SQ_INSTS_VALU - SQ_INSTS_MFMA) / $denom))
unit: (instr + $normUnit)
tips:
VMEM:
count: AVG(((SQ_INSTS_VMEM - SQ_INSTS_FLAT_LDS_ONLY) / $denom))
avg: AVG(((SQ_INSTS_VMEM - SQ_INSTS_FLAT_LDS_ONLY) / $denom))
min: MIN(((SQ_INSTS_VMEM - SQ_INSTS_FLAT_LDS_ONLY) / $denom))
max: MAX(((SQ_INSTS_VMEM - SQ_INSTS_FLAT_LDS_ONLY) / $denom))
unit: (instr + $normUnit)
tips:
LDS:
count: AVG((SQ_INSTS_LDS / $denom))
avg: AVG((SQ_INSTS_LDS / $denom))
min: MIN((SQ_INSTS_LDS / $denom))
max: MAX((SQ_INSTS_LDS / $denom))
unit: (instr + $normUnit)
tips:
VALU - MFMA:
count: AVG((SQ_INSTS_MFMA / $denom))
avg: AVG((SQ_INSTS_MFMA / $denom))
min: MIN((SQ_INSTS_MFMA / $denom))
max: MAX((SQ_INSTS_MFMA / $denom))
unit: (instr + $normUnit)
tips:
SALU:
count: AVG((SQ_INSTS_SALU / $denom))
avg: AVG((SQ_INSTS_SALU / $denom))
min: MIN((SQ_INSTS_SALU / $denom))
max: MAX((SQ_INSTS_SALU / $denom))
unit: (instr + $normUnit)
tips:
SMEM:
count: AVG((SQ_INSTS_SMEM / $denom))
avg: AVG((SQ_INSTS_SMEM / $denom))
min: MIN((SQ_INSTS_SMEM / $denom))
max: MAX((SQ_INSTS_SMEM / $denom))
unit: (instr + $normUnit)
tips:
Branch:
count: AVG((SQ_INSTS_BRANCH / $denom))
avg: AVG((SQ_INSTS_BRANCH / $denom))
min: MIN((SQ_INSTS_BRANCH / $denom))
max: MAX((SQ_INSTS_BRANCH / $denom))
unit: (instr + $normUnit)
tips:
GDS:
count: AVG((SQ_INSTS_GDS / $denom))
avg: AVG((SQ_INSTS_GDS / $denom))
min: MIN((SQ_INSTS_GDS / $denom))
max: MAX((SQ_INSTS_GDS / $denom))
unit: (instr + $normUnit)
tips:
@@ -55,68 +76,103 @@ Panel Config:
title: VALU Arithmetic Instr Mix
header:
metric: Metric
count: Count
avg: Avg
min: Min
max: Max
unit: Unit
tips: Tips
style:
type: simple_bar
label_txt: (# of instr + $normUnit)
metric:
INT32:
count: AVG((SQ_INSTS_VALU_INT32 / $denom))
avg: AVG((SQ_INSTS_VALU_INT32 / $denom))
min: MIN((SQ_INSTS_VALU_INT32 / $denom))
max: MAX((SQ_INSTS_VALU_INT32 / $denom))
unit: (instr + $normUnit)
tips:
INT64:
count: AVG((SQ_INSTS_VALU_INT64 / $denom))
avg: AVG((SQ_INSTS_VALU_INT64 / $denom))
min: MIN((SQ_INSTS_VALU_INT64 / $denom))
max: MAX((SQ_INSTS_VALU_INT64 / $denom))
unit: (instr + $normUnit)
tips:
F16-ADD:
count: AVG((SQ_INSTS_VALU_ADD_F16 / $denom))
avg: AVG((SQ_INSTS_VALU_ADD_F16 / $denom))
min: MIN((SQ_INSTS_VALU_ADD_F16 / $denom))
max: MAX((SQ_INSTS_VALU_ADD_F16 / $denom))
unit: (instr + $normUnit)
tips:
F16-MUL:
count: AVG((SQ_INSTS_VALU_MUL_F16 / $denom))
avg: AVG((SQ_INSTS_VALU_MUL_F16 / $denom))
min: MIN((SQ_INSTS_VALU_MUL_F16 / $denom))
max: MAX((SQ_INSTS_VALU_MUL_F16 / $denom))
unit: (instr + $normUnit)
tips:
F16-FMA:
count: AVG((SQ_INSTS_VALU_FMA_F16 / $denom))
avg: AVG((SQ_INSTS_VALU_FMA_F16 / $denom))
min: MIN((SQ_INSTS_VALU_FMA_F16 / $denom))
max: MAX((SQ_INSTS_VALU_FMA_F16 / $denom))
unit: (instr + $normUnit)
tips:
F16-Trans:
count: AVG((SQ_INSTS_VALU_TRANS_F16 / $denom))
avg: AVG((SQ_INSTS_VALU_TRANS_F16 / $denom))
min: MIN((SQ_INSTS_VALU_TRANS_F16 / $denom))
max: MAX((SQ_INSTS_VALU_TRANS_F16 / $denom))
unit: (instr + $normUnit)
tips:
F32-ADD:
count: AVG((SQ_INSTS_VALU_ADD_F32 / $denom))
avg: AVG((SQ_INSTS_VALU_ADD_F32 / $denom))
min: MIN((SQ_INSTS_VALU_ADD_F32 / $denom))
max: MAX((SQ_INSTS_VALU_ADD_F32 / $denom))
unit: (instr + $normUnit)
tips:
F32-MUL:
count: AVG((SQ_INSTS_VALU_MUL_F32 / $denom))
avg: AVG((SQ_INSTS_VALU_MUL_F32 / $denom))
min: MIN((SQ_INSTS_VALU_MUL_F32 / $denom))
max: MAX((SQ_INSTS_VALU_MUL_F32 / $denom))
unit: (instr + $normUnit)
tips:
F32-FMA:
count: AVG((SQ_INSTS_VALU_FMA_F32 / $denom))
avg: AVG((SQ_INSTS_VALU_FMA_F32 / $denom))
min: MIN((SQ_INSTS_VALU_FMA_F32 / $denom))
max: MAX((SQ_INSTS_VALU_FMA_F32 / $denom))
unit: (instr + $normUnit)
tips:
F32-Trans:
count: AVG((SQ_INSTS_VALU_TRANS_F32 / $denom))
avg: AVG((SQ_INSTS_VALU_TRANS_F32 / $denom))
min: MIN((SQ_INSTS_VALU_TRANS_F32 / $denom))
max: MAX((SQ_INSTS_VALU_TRANS_F32 / $denom))
unit: (instr + $normUnit)
tips:
F64-ADD:
count: AVG((SQ_INSTS_VALU_ADD_F64 / $denom))
avg: AVG((SQ_INSTS_VALU_ADD_F64 / $denom))
min: MIN((SQ_INSTS_VALU_ADD_F64 / $denom))
max: MAX((SQ_INSTS_VALU_ADD_F64 / $denom))
unit: (instr + $normUnit)
tips:
F64-MUL:
count: AVG((SQ_INSTS_VALU_MUL_F64 / $denom))
avg: AVG((SQ_INSTS_VALU_MUL_F64 / $denom))
min: MIN((SQ_INSTS_VALU_MUL_F64 / $denom))
max: MAX((SQ_INSTS_VALU_MUL_F64 / $denom))
unit: (instr + $normUnit)
tips:
F64-FMA:
count: AVG((SQ_INSTS_VALU_FMA_F64 / $denom))
avg: AVG((SQ_INSTS_VALU_FMA_F64 / $denom))
min: MIN((SQ_INSTS_VALU_FMA_F64 / $denom))
max: MAX((SQ_INSTS_VALU_FMA_F64 / $denom))
unit: (instr + $normUnit)
tips:
F64-Trans:
count: AVG((SQ_INSTS_VALU_TRANS_F64 / $denom))
avg: AVG((SQ_INSTS_VALU_TRANS_F64 / $denom))
min: MIN((SQ_INSTS_VALU_TRANS_F64 / $denom))
max: MAX((SQ_INSTS_VALU_TRANS_F64 / $denom))
unit: (instr + $normUnit)
tips:
Conversion:
count: AVG((SQ_INSTS_VALU_CVT / $denom))
avg: AVG((SQ_INSTS_VALU_CVT / $denom))
min: MIN((SQ_INSTS_VALU_CVT / $denom))
max: MAX((SQ_INSTS_VALU_CVT / $denom))
unit: (instr + $normUnit)
tips:
@@ -14,7 +14,13 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
valu_flops_pop:
value: ((100 * AVG(((((64 * (((SQ_INSTS_VALU_ADD_F16 + SQ_INSTS_VALU_MUL_F16)
@@ -23,26 +29,32 @@ Panel Config:
+ (64 * (((SQ_INSTS_VALU_ADD_F64 + SQ_INSTS_VALU_MUL_F64) + SQ_INSTS_VALU_TRANS_F64)
+ (2 * SQ_INSTS_VALU_FMA_F64)))) / (EndNs - BeginNs)))) / (((($sclk
* $numCU) * 64) * 2) / 1000))
unit: Pct of Peak
tips:
mfma_flops_bf16_pop:
value: ((100 * AVG(((SQ_INSTS_VALU_MFMA_MOPS_BF16 * 512) / (EndNs - BeginNs))))
/ ((($sclk * $numCU) * 512) / 1000))
unit: Pct of Peak
tips:
mfma_flops_f16_pop:
value: ((100 * AVG(((SQ_INSTS_VALU_MFMA_MOPS_F16 * 512) / (EndNs - BeginNs))))
/ ((($sclk * $numCU) * 1024) / 1000))
unit: Pct of Peak
tips:
mfma_flops_f32_pop:
value: ((100 * AVG(((SQ_INSTS_VALU_MFMA_MOPS_F32 * 512) / (EndNs - BeginNs))))
/ ((($sclk * $numCU) * 256) / 1000))
unit: Pct of Peak
tips:
mfma_flops_f64_pop:
value: ((100 * AVG(((SQ_INSTS_VALU_MFMA_MOPS_F64 * 512) / (EndNs - BeginNs))))
/ ((($sclk * $numCU) * 256) / 1000))
unit: Pct of Peak
tips:
mfma_flops_i8_pop:
value: ((100 * AVG(((SQ_INSTS_VALU_MFMA_MOPS_I8 * 512) / (EndNs - BeginNs))))
/ ((($sclk * $numCU) * 1024) / 1000))
unit: Pct of Peak
tips:
- metric_table:
@@ -187,5 +199,4 @@ Panel Config:
max: MAX((((64 * (((SQ_INSTS_VALU_ADD_F64 + SQ_INSTS_VALU_MUL_F64) + SQ_INSTS_VALU_TRANS_F64)
+ (SQ_INSTS_VALU_FMA_F64 * 2))) + (512 * SQ_INSTS_VALU_MFMA_MOPS_F64)) / $denom))
unit: (OPs + $normUnit)
tips:
tips:
@@ -14,21 +14,31 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Utilization:
value: AVG(((100 * SQ_LDS_IDX_ACTIVE) / (GRBM_GUI_ACTIVE * $numCU)))
unit: Pct of Peak
tips:
Access Rate:
value: AVG(((200 * SQ_ACTIVE_INST_LDS) / (GRBM_GUI_ACTIVE * $numCU)))
unit: Pct of Peak
tips:
Bandwidth (Pct-of-Peak):
value: AVG((((((SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT) * 4) * TO_INT($LDSBanks))
/ (EndNs - BeginNs)) / (($sclk * $numCU) * 0.00128)))
unit: Pct of Peak
tips:
Bank Conflict Rate:
value: AVG((((SQ_LDS_BANK_CONFLICT * 3.125) / (SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT))
if ((SQ_LDS_IDX_ACTIVE - SQ_LDS_BANK_CONFLICT) != 0) else None))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,15 +14,23 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Bandwidth:
value: AVG(((SQC_ICACHE_REQ * 100000) / (($sclk * $numSQC)
* (EndNs - BeginNs))))
unit: Pct of Peak
tips:
Cache Hit:
value: AVG(((SQC_ICACHE_HITS * 100) / ((SQC_ICACHE_HITS + SQC_ICACHE_MISSES)
+ SQC_ICACHE_MISSES_DUPLICATE)))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,16 +14,24 @@ Panel Config:
header:
mertic: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Bandwidth:
value: AVG(((SQC_DCACHE_REQ * 100000) / (($sclk * $numSQC)
* (EndNs - BeginNs))))
unit: Pct of Peak
tips:
Cache Hit:
value:
AVG((((SQC_DCACHE_HITS * 100) / (SQC_DCACHE_HITS + SQC_DCACHE_MISSES + SQC_DCACHE_MISSES_DUPLICATE))
if ((SQC_DCACHE_HITS + SQC_DCACHE_MISSES + SQC_DCACHE_MISSES_DUPLICATE) != 0) else None))
unit: Pct of Peak
tips:
- metric_table:
@@ -14,25 +14,35 @@ Panel Config:
header:
metric: Metric
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
range_color: [1, 100]
label_txt: (%)
xrange: [0, 110]
metric:
Buffer Coalescing:
value: AVG(((((TA_TOTAL_WAVEFRONTS_sum * 64) * 100) / (TCP_TOTAL_ACCESSES_sum
* 4)) if (TCP_TOTAL_ACCESSES_sum != 0) else None))
unit: Pct of Peak
tips:
Cache Util:
value: AVG((((TCP_GATE_EN2_sum * 100) / TCP_GATE_EN1_sum) if (TCP_GATE_EN1_sum
!= 0) else None))
unit: Pct of Peak
tips:
Cache BW:
value: ((100 * AVG(((TCP_TOTAL_CACHE_ACCESSES_sum * 64) / (EndNs - BeginNs))))
/ ((($sclk / 1000) * 64) * $numCU))
unit: Pct of Peak
tips:
Cache Hit:
value: AVG(((100 - ((100 * (((TCP_TCC_READ_REQ_sum + TCP_TCC_WRITE_REQ_sum)
+ TCP_TCC_ATOMIC_WITH_RET_REQ_sum) + TCP_TCC_ATOMIC_WITHOUT_RET_REQ_sum))
/ TCP_TOTAL_CACHE_ACCESSES_sum)) if (TCP_TOTAL_CACHE_ACCESSES_sum != 0) else
None))
unit: Pct of Peak
tips:
- metric_table:
@@ -248,6 +258,8 @@ Panel Config:
max: Max
unit: Unit
tips: Tips
style:
type: simple_multi_bar
metric:
NC - Read:
xfer: Read
@@ -361,7 +373,7 @@ Panel Config:
mean: AVG((TCP_UTCL1_REQUEST_sum / $denom))
min: MIN((TCP_UTCL1_REQUEST_sum / $denom))
max: MAX((TCP_UTCL1_REQUEST_sum / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
Hit Ratio:
mean: AVG((((100 * TCP_UTCL1_TRANSLATION_HIT_sum) / TCP_UTCL1_REQUEST_sum) if
@@ -376,17 +388,17 @@ Panel Config:
mean: AVG((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
min: MIN((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
max: MAX((TCP_UTCL1_TRANSLATION_HIT_sum / $denom))
units: ( + $normUnit)
units: (Hits + $normUnit)
tips:
Misses (Translation):
mean: AVG((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
min: MIN((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
max: MAX((TCP_UTCL1_TRANSLATION_MISS_sum / $denom))
units: ( + $normUnit)
units: (Misses + $normUnit)
tips:
Misses (Permission):
mean: AVG((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
min: MIN((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
max: MAX((TCP_UTCL1_PERMISSION_MISS_sum / $denom))
units: ( + $normUnit)
units: (Misses + $normUnit)
tips:
@@ -16,6 +16,8 @@ Panel Config:
value: Value
unit: Unit
tips: Tips
style:
type: simple_bar
metric:
L2 Util:
value: AVG(((TCC_BUSY_sum * 100) / (TO_INT($L2Banks) * GRBM_GUI_ACTIVE)))
@@ -301,6 +303,8 @@ Panel Config:
max: Max
unit: Unit
tips: Tips
style:
type: simple_multi_bar
metric:
Read - Remote Socket Stall:
type: Remote Socket Stall
@@ -204,7 +204,7 @@ Panel Config:
+ TO_INT(TCC_REQ[22])) + TO_INT(TCC_REQ[23])) + TO_INT(TCC_REQ[24])) + TO_INT(TCC_REQ[25]))
+ TO_INT(TCC_REQ[26])) + TO_INT(TCC_REQ[27])) + TO_INT(TCC_REQ[28])) + TO_INT(TCC_REQ[29]))
+ TO_INT(TCC_REQ[30])) + TO_INT(TCC_REQ[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Read Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_READ[0]) + TO_INT(TCC_READ[1]))
@@ -247,7 +247,7 @@ Panel Config:
+ TO_INT(TCC_READ[24])) + TO_INT(TCC_READ[25])) + TO_INT(TCC_READ[26])) +
TO_INT(TCC_READ[27])) + TO_INT(TCC_READ[28])) + TO_INT(TCC_READ[29])) + TO_INT(TCC_READ[30]))
+ TO_INT(TCC_READ[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Write Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_WRITE[0]) + TO_INT(TCC_WRITE[1]))
@@ -294,7 +294,7 @@ Panel Config:
+ TO_INT(TCC_WRITE[24])) + TO_INT(TCC_WRITE[25])) + TO_INT(TCC_WRITE[26]))
+ TO_INT(TCC_WRITE[27])) + TO_INT(TCC_WRITE[28])) + TO_INT(TCC_WRITE[29]))
+ TO_INT(TCC_WRITE[30])) + TO_INT(TCC_WRITE[31])) / 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L1 - L2 Atomic Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_ATOMIC[0]) + TO_INT(TCC_ATOMIC[1]))
@@ -345,7 +345,7 @@ Panel Config:
+ TO_INT(TCC_ATOMIC[26])) + TO_INT(TCC_ATOMIC[27])) + TO_INT(TCC_ATOMIC[28]))
+ TO_INT(TCC_ATOMIC[29])) + TO_INT(TCC_ATOMIC[30])) + TO_INT(TCC_ATOMIC[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Read Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_RDREQ[0]) + TO_INT(TCC_EA_RDREQ[1]))
@@ -396,7 +396,7 @@ Panel Config:
+ TO_INT(TCC_EA_RDREQ[26])) + TO_INT(TCC_EA_RDREQ[27])) + TO_INT(TCC_EA_RDREQ[28]))
+ TO_INT(TCC_EA_RDREQ[29])) + TO_INT(TCC_EA_RDREQ[30])) + TO_INT(TCC_EA_RDREQ[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Write Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_WRREQ[0]) + TO_INT(TCC_EA_WRREQ[1]))
@@ -447,7 +447,7 @@ Panel Config:
+ TO_INT(TCC_EA_WRREQ[26])) + TO_INT(TCC_EA_WRREQ[27])) + TO_INT(TCC_EA_WRREQ[28]))
+ TO_INT(TCC_EA_WRREQ[29])) + TO_INT(TCC_EA_WRREQ[30])) + TO_INT(TCC_EA_WRREQ[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Atomic Req:
mean: AVG((((((((((((((((((((((((((((((((((TO_INT(TCC_EA_ATOMIC[0]) + TO_INT(TCC_EA_ATOMIC[1]))
@@ -498,7 +498,7 @@ Panel Config:
+ TO_INT(TCC_EA_ATOMIC[26])) + TO_INT(TCC_EA_ATOMIC[27])) + TO_INT(TCC_EA_ATOMIC[28]))
+ TO_INT(TCC_EA_ATOMIC[29])) + TO_INT(TCC_EA_ATOMIC[30])) + TO_INT(TCC_EA_ATOMIC[31]))
/ 32) / $denom))
units: ( + $normUnit)
units: (Req + $normUnit)
tips:
L2 - EA Read Lat:
mean: AVG((((((((((((((((((((((((((((((((((TCC_EA_RDREQ_LEVEL[0] + TCC_EA_RDREQ_LEVEL[1])
@@ -45,39 +45,47 @@ import os.path
from pathlib import Path
from omniperf_analyze.utils import parser, file_io
from omniperf_analyze.utils.gui_components.roofline import get_roofline
from utils import csv_processor
archConfigs = {}
def initialize_run(args, normalization_filter=None):
import pandas as pd
from collections import OrderedDict
################################################
# Helper Functions
################################################
def generate_config(arch, config_dir, list_kernels, filter_metrics):
from omniperf_analyze.utils import schema
single_panel_config = file_io.is_single_panel_config(Path(config_dir))
global archConfigs
ac = schema.ArchConfig()
if list_kernels:
ac.panel_configs = file_io.top_stats_build_in_config
else:
arch_panel_config = (
config_dir if single_panel_config else config_dir.joinpath(arch)
)
ac.panel_configs = file_io.load_panel_configs(arch_panel_config)
# TODO: filter_metrics should/might be one per arch
# print(ac)
parser.build_dfs(ac, filter_metrics)
archConfigs[arch] = ac
return archConfigs # Note: This return comes in handy for rocScope which borrows generate_configs() in its rocomni plugin
def list_metrics(args):
import pandas as pd
from tabulate import tabulate
# Fixme: cur_root.parent.joinpath('soc_params')
soc_params_dir = os.path.join(os.path.dirname(__file__), "..", "soc_params")
soc_spec_df = file_io.load_soc_params(soc_params_dir)
single_panel_config = file_io.is_single_panel_config(Path(args.config_dir))
global archConfigs
archConfigs = {}
for arch in file_io.supported_arch.keys():
ac = schema.ArchConfig()
if args.list_kernels:
ac.panel_configs = file_io.top_stats_build_in_config
else:
arch_panel_config = (
args.config_dir if single_panel_config else args.config_dir.joinpath(arch)
)
ac.panel_configs = file_io.load_panel_configs(arch_panel_config)
# TODO: filter_metrics should/might be one per arch
# print(ac)
parser.build_dfs(ac, args.filter_metrics)
archConfigs[arch] = ac
if args.list_metrics in file_io.supported_arch.keys():
arch = args.list_metrics
if arch not in archConfigs.keys():
generate_config(arch, args.config_dir, args.list_kernels, args.filter_metrics)
print(
tabulate(
pd.DataFrame.from_dict(
@@ -91,7 +99,12 @@ def initialize_run(args, normalization_filter=None):
file=output,
)
sys.exit(0)
else:
print("Error: Unsupported arch")
sys.exit(-1)
def load_options(args, normalization_filter):
# Use original normalization or user input from GUI
if not normalization_filter:
for k, v in archConfigs.items():
@@ -100,10 +113,7 @@ def initialize_run(args, normalization_filter=None):
for k, v in archConfigs.items():
parser.build_metric_value_string(v.dfs, v.dfs_type, normalization_filter)
runs = OrderedDict()
# err checking for multiple runs and multiple gpu_kernel filter
# TODO: move it to util
if args.gpu_kernel and (len(args.path) != len(args.gpu_kernel)):
if len(args.gpu_kernel) == 1:
for i in range(len(args.path) - 1):
@@ -115,6 +125,31 @@ def initialize_run(args, normalization_filter=None):
)
sys.exit(-1)
################################################
# Core Functions
################################################
def initialize_run(args, normalization_filter=None):
from collections import OrderedDict
from omniperf_analyze.utils import schema
# Fixme: cur_root.parent.joinpath('soc_params')
soc_params_dir = os.path.join(os.path.dirname(__file__), "..", "soc_params")
soc_spec_df = file_io.load_soc_params(soc_params_dir)
if args.list_metrics:
list_metrics(args)
# Load required configs
for d in args.path:
sys_info = file_io.load_sys_info(Path(d[0], "sysinfo.csv"))
arch = sys_info.iloc[0]["gpu_soc"]
generate_config(arch, args.config_dir, args.list_kernels, args.filter_metrics)
load_options(args, normalization_filter)
runs = OrderedDict()
# Todo: warning single -d with multiple dirs
for d in args.path:
w = schema.Workload()
@@ -161,7 +196,7 @@ def run_gui(args, runs):
gui.build_layout(
app,
runs,
archConfigs["gfx90a"],
archConfigs[runs[args.path[0][0]].sys_info.iloc[0]["gpu_soc"]],
input_filters,
args.decimal,
args.time_unit,
@@ -187,6 +222,9 @@ def run_cli(args, runs):
# which archConfig passed into show_all function.
# After decide to how to manage kernels display patterns, we can revisit it.
for d in args.path:
# Demangle and overwrite original KernelNames
csv_processor.kernel_name_shortener(d[0], args.kernelVerbose)
file_io.create_df_kernel_top_stats(
d[0],
runs[d[0]].filter_gpu_ids,
@@ -201,10 +239,21 @@ def run_cli(args, runs):
parser.load_table_data(
runs[d[0]], d[0], is_gui, args.g, args.verbose
) # create the loaded table
# TODO: In show_* functions always assume newest architecture. This way newest configs/figures are loaded
if args.list_kernels:
tty.show_kernels(args, runs, archConfigs["gfx90a"], output)
tty.show_kernels(
args,
runs,
archConfigs[runs[args.path[0][0]].sys_info.iloc[0]["gpu_soc"]],
output,
)
else:
tty.show_all(args, runs, archConfigs["gfx90a"], output)
tty.show_all(
args,
runs,
archConfigs[runs[args.path[0][0]].sys_info.iloc[0]["gpu_soc"]],
output,
)
def roofline_only(path_to_dir, dev_id, sort_type, mem_level, kernel_names, verbose):
@@ -219,7 +268,7 @@ def roofline_only(path_to_dir, dev_id, sort_type, mem_level, kernel_names, verbo
app_path = path_to_dir + "/pmc_perf.csv"
roofline_exists = os.path.isfile(app_path)
if not roofline_exists:
print("Error: {} does not exist")
print("Error: {} does not exist".format(app_path))
sys.exit(0)
t_df = OrderedDict()
t_df["pmc_perf"] = pd.read_csv(app_path)
@@ -154,17 +154,17 @@ def build_bar_chart(display_df, table_config, norm_filt):
# Insr Mix bar chart
if table_config["id"] in barchart_elements["instr_mix"]:
display_df["Count"] = [
x.astype(int) if x != "" else int(0) for x in display_df["Count"]
display_df["Avg"] = [
x.astype(int) if x != "" else int(0) for x in display_df["Avg"]
]
df_unit = display_df["Unit"][0]
d_figs.append(
px.bar(
display_df,
x="Count",
x="Avg",
y="Metric",
color="Count",
labels={"Count": "# of {}".format(df_unit.lower())},
color="Avg",
labels={"Avg": "# of {}".format(df_unit.lower())},
height=400,
orientation="h",
)
@@ -321,6 +321,71 @@ def update_normUnit_string(equation, unit):
).capitalize()
def gen_counter_list(formula):
function_filter = {
"MIN": None,
"MAX": None,
"AVG": None,
"ROUND": None,
"TO_INT": None,
"GB": None,
"STD": None,
"GFLOP": None,
"GOP": None,
"OP": None,
"CU": None,
"NC": None,
"UC": None,
"CC": None,
"RW": None,
"GIOP": None,
"GFLOPs": None,
"CONCAT": None,
"MOD": None,
}
built_in_counter = [
"lds",
"grd",
"wgr",
"arch_vgpr",
"accum_vgpr",
"sgpr",
"scr",
"BeginNs",
"EndNs",
]
visited = False
counters = []
if not isinstance(formula, str):
return visited, counters
try:
tree = ast.parse(
formula.replace("$normUnit", "SQ_WAVES")
.replace("$denom", "SQ_WAVES")
.replace(
"$numActiveCUs",
"TO_INT(MIN((((ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) / GRBM_GUI_ACTIVE)), \
0) / $maxWavesPerCU) * 8) + MIN(MOD(ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) \
/ GRBM_GUI_ACTIVE)), 0), $maxWavesPerCU), 8)), $numCU))",
)
.replace("$", "")
)
for node in ast.walk(tree):
if isinstance(node, ast.Name):
val = str(node.id)[:-4] if str(node.id).endswith("_sum") else str(node.id)
if val.isupper() and val not in function_filter:
counters.append(val)
visited = True
if val in built_in_counter:
visited = True
except:
pass
return visited, counters
def build_dfs(archConfigs, filter_metrics):
"""
- Build dataframe for each type of data source within each panel.
@@ -338,10 +403,16 @@ def build_dfs(archConfigs, filter_metrics):
d = {}
metric_list = {}
dfs_type = {}
metric_counters = {}
for panel_id, panel in archConfigs.panel_configs.items():
panel_idx = str(panel_id // 100)
for data_source in panel["data source"]:
for type, data_cofig in data_source.items():
if type == "metric_table":
metric_list[panel_idx] = panel["title"]
table_idx = panel_idx + "." + str(data_cofig["id"] % 100)
metric_list[table_idx] = data_cofig["title"]
headers = ["Index"]
for key, tile in data_cofig["header"].items():
if key != "tips":
@@ -355,20 +426,16 @@ def build_dfs(archConfigs, filter_metrics):
i = 0
for key, entries in data_cofig["metric"].items():
data_source_idx = (
str(data_cofig["id"] // 100)
+ "."
+ str(data_cofig["id"] % 100)
)
metric_idx = data_source_idx + "." + str(i)
metric_idx = table_idx + "." + str(i)
values = []
eqn_content = []
if (
(not filter_metrics)
or (metric_idx in filter_metrics) # no filter
or # metric in filter
# the whole table in filter
(data_source_idx in filter_metrics)
(table_idx in filter_metrics)
or
# the whole IP block in filter
(str(panel_id // 100) in filter_metrics)
@@ -378,6 +445,7 @@ def build_dfs(archConfigs, filter_metrics):
for k, v in entries.items():
if k != "tips" and k != "coll_level" and k != "alias":
values.append(v)
eqn_content.append(v)
if "alias" in entries.keys():
values.append(entries["alias"])
@@ -395,7 +463,21 @@ def build_dfs(archConfigs, filter_metrics):
df = pd.concat([df, df_new_row])
# collect metric_list
metric_list[metric_idx] = key.replace(" ", "_")
metric_list[metric_idx] = key
# generate mapping of counters and metrics
filter = {}
_visited = False
for formula in eqn_content:
if formula is not None and formula != "None":
visited, counters = gen_counter_list(formula)
if visited:
_visited = True
for k in counters:
filter[k] = None
if len(filter) > 0 or _visited:
metric_counters[key] = list(filter)
i += 1
df.set_index("Index", inplace=True)
@@ -431,6 +513,7 @@ def build_dfs(archConfigs, filter_metrics):
setattr(archConfigs, "dfs", d)
setattr(archConfigs, "metric_list", metric_list)
setattr(archConfigs, "dfs_type", dfs_type)
setattr(archConfigs, "metric_counters", metric_counters)
def build_metric_value_string(dfs, dfs_type, normal_unit):
@@ -469,7 +552,12 @@ def eval_metric(dfs, dfs_type, sys_info, soc_spec, raw_pmc_df, debug):
# confirm no illogical counter values (only consider non-roofline runs)
roof_only_run = sys_info.ip_blocks == "roofline"
if not roof_only_run and (raw_pmc_df["pmc_perf"]["GRBM_GUI_ACTIVE"] == 0).any():
rocscope_run = sys_info.ip_blocks == "rocscope"
if (
not rocscope_run
and not roof_only_run
and (raw_pmc_df["pmc_perf"]["GRBM_GUI_ACTIVE"] == 0).any()
):
print("WARNING: Dectected GRBM_GUI_ACTIVE == 0\nHaulting execution.")
sys.exit(1)
@@ -711,12 +799,13 @@ def load_kernel_top(workload, dir):
workload.dfs.update(tmp)
def load_table_data(workload, dir, is_gui, debug, verbose):
def load_table_data(workload, dir, is_gui, debug, verbose, skipKernelTop=False):
"""
Load data for all "raw_csv_table".
Calculate mertric value for all "metric_table".
"""
load_kernel_top(workload, dir)
if not skipKernelTop:
load_kernel_top(workload, dir)
eval_metric(
workload.dfs,
@@ -52,6 +52,9 @@ class ArchConfig:
# [Index: Metric name] pairs
metric_list: Dict[str, str] = field(default_factory=dict)
# [Metric name: Counters] pairs
metric_counters: Dict[str, list] = field(default_factory=dict)
@dataclass
class Workload:
@@ -0,0 +1,119 @@
##############################################################################bl
# MIT License
#
# Copyright (c) 2021 - 2023 Advanced Micro Devices, Inc. All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
##############################################################################el
import plotly.express as px
import pandas as pd
# Notes:
# This file includes implementation of a few simple but common charts in CLI.
# We try to auto-size the layout to cover most of the cases as default. If it
# doesn't work, apply style config in yaml for each dashboard.
def simple_bar(df, title: str = None, id=None, style: dict = None, orientation="h"):
"""
Plot data with simple bar chart
"""
# TODO: handle None properly
if "Metric" in df.columns and ("Count" in df.columns or "Value" in df.columns):
detected_label = "Count" if "Count" in df.columns else "Value"
df[detected_label] = [
x.astype(int) if x != "" else int(0) for x in df[detected_label]
]
else:
raise NameError("simple_bar: No Metric or Count in df columns!")
# Assign figure characteristics
range_color = style.get("range_color", None)
label_txt = style.get("label_txt", None)
xrange = style.get("xrange", None)
if label_txt is not None:
label_txt = label_txt.strip("()")
try:
label_txt = label_txt.replace("+ $normUnit", df["Unit"][0])
except KeyError:
print("No units found in df. Auto labeling.")
# Overrides for figure chatacteristics
if id == 1701.1:
label_txt = "%"
range_color = [0, 100]
xrange = [0, 110]
if id == 1701.2:
label_txt = "Gb/s"
range_color = [0, 1638]
xrange = [0, 1638]
fig = px.bar(
df,
title=title,
x=detected_label,
y="Metric",
color=detected_label,
range_color=range_color,
labels={detected_label: label_txt},
orientation=orientation,
).update_xaxes(range=xrange)
return fig
def simple_multi_bar(df, title=None, id=None):
"""
Plot data with simple multiple bar chart
"""
# TODO: handle Nan and None properly
if "Metric" in df.columns and "Avg" in df.columns:
df["Avg"] = [x.astype(int) if x != "" else int(0) for x in df["Avg"]]
else:
raise NameError("simple_multi_bar: No Metric or Count in df columns!")
dfigs = []
nested_bar = {}
df_unit = df["Unit"][0]
if id == 1604:
nested_bar = {"NC": {}, "UC": {}, "RW": {}, "CC": {}}
for index, row in df.iterrows():
nested_bar[row["Coherency"]][row["Xfer"]] = row["Avg"]
if id == 1704:
nested_bar = {"Read": {}, "Write": {}}
for index, row in df.iterrows():
nested_bar[row["Transaction"]][row["Type"]] = row["Avg"]
for group, metric in nested_bar.items():
dfigs.append(
px.bar(
title=group,
x=metric.values(),
y=metric.keys(),
labels={"x": df_unit, "y": ""},
text=metric.values(),
)
.update_xaxes(showgrid=False, rangemode="nonnegative")
.update_yaxes(showgrid=False)
)
return dfigs
+17 -9
View File
@@ -204,6 +204,14 @@ def parse(my_parser):
nargs=argparse.REMAINDER,
help="\t\t\tProvide command for profiling after double dash.",
)
profile_group.add_argument(
"--kernelVerbose",
required=False,
metavar="",
help="\t\t\tSpecify Kernel Name verbose level 1-5. Lower the level, shorter the kernel name. (DEFAULT: 2) (DISABLE: 5)",
default=2,
type=int,
)
## Roofline Command Line Options
roofline_group.add_argument(
@@ -342,15 +350,6 @@ def parse(my_parser):
dest="workload",
help="\t\t\t\tSpecify name of workload (to remove) or path to workload (to import)",
)
connection_group.add_argument(
"-k",
"--kernelVerbose",
required=False,
metavar="",
help="\t\t\t\tSpecify Kernel Name verbose level 1-5. Lower the level, shorter the kernel name. (DEFAULT: 2) (DISABLE: 5)",
default=2,
type=int,
)
## Analyze Command Line Options
## ----------------------------
@@ -430,6 +429,7 @@ def parse(my_parser):
help="\t\tSpecify kernel id(s) from --list-kernels for filtering.",
)
analyze_group.add_argument(
"-d",
"--dispatch",
dest="gpu_dispatch_id",
metavar="",
@@ -514,3 +514,11 @@ def parse(my_parser):
action="store_true",
help="\t\tRandomly generate a port to launch GUI application.\n\t\tRegistered Ports range inclusive (1024-49151).",
)
analyze_group.add_argument(
"--kernelVerbose",
required=False,
metavar="",
help="\t\tSpecify Kernel Name verbose level 1-5. Lower the level, shorter the kernel name. (DEFAULT: 5) (DISABLE: 5)",
default=5,
type=int,
)
@@ -1,264 +0,0 @@
##############################################################################bl
# MIT License
#
# Copyright (c) 2021 - 2023 Advanced Micro Devices, Inc. All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
##############################################################################el
import argparse
import collections
import os
import sys
import re
import pandas as pd
import getpass
from pymongo import MongoClient
from tqdm import tqdm
import shutil
cache = dict()
supported_arch = {"gfx906": "mi50", "gfx908": "mi100", "gfx90a": "mi200"}
MAX_SERVER_SEL_DELAY = 5000 # 5 sec connection timeout
def kernel_name_shortener(df, cache, level):
if level >= 5:
return df
columnName = ""
if "KernelName" in df:
columnName = "KernelName"
if "Name" in df:
columnName = "Name"
if columnName == "KernelName" or columnName == "Name":
# loop through all indices
for index in df.index:
original_name = df.loc[index, columnName]
if original_name in cache:
continue
# cache miss, add the shortened name to the dictionary
new_name = ""
matches = ""
names_and_args = re.compile(r"(?P<name>[( )A-Za-z0-9_]+)([ ,*<>()]+)(::)?")
# works for name Kokkos::namespace::init_lock_array_kernel_threadid(int) [clone .kd]
if names_and_args.search(original_name):
matches = names_and_args.findall(original_name)
else:
# Works for first case '__amd_rocclr_fillBuffer.kd'
# remove .kd and then parse through original regex
first_case = re.compile(r"([^\s]+)(.kd)")
Mod_name_and_args = re.compile(r"(?P<name>[( )A-Za-z0-9_]+)([ ,*<>()]*)")
interim_name = first_case.search(original_name).group(1)
matches = Mod_name_and_args.findall(interim_name)
current_level = 0
for name in matches:
##can cause errors if a function name or argument is equal to 'clone'
if name[0] == "clone":
continue
if len(name) == 3:
if name[2] == "::":
continue
if current_level < level:
new_name += name[0]
# closing '>' is to be taken account by the while loop
if name[1].count(">") == 0:
if current_level < level:
if not (current_level == level - 1 and name[1].count("<") > 0):
new_name += name[1]
current_level += name[1].count("<")
curr_index = 0
# cases include '>' '> >, ' have to go in depth here to not lose account of commas and current level
while name[1].count(">") > 0 and curr_index < len(name[1]):
if current_level < level:
new_name += name[1][curr_index:]
current_level -= name[1][curr_index:].count(">")
curr_index = len(name[1])
elif name[1][curr_index] == (">"):
current_level -= 1
curr_index += 1
cache[original_name] = new_name
if new_name == None or new_name == "":
cache[original_name] = original_name
df[columnName] = df[columnName].map(cache)
return df
# Verify target directory and setup connection
def parse(args, profileAndExport):
host = args.host
port = str(args.port)
username = args.username
Extractionlvl = args.kernelVerbose
if profileAndExport:
workload = args.workload + "/" + args.target + "/"
else:
workload = args.workload
# Verify directory path is valid
print("Pulling data from ", workload)
if os.path.isdir(workload):
print("The directory exists")
else:
raise argparse.ArgumentTypeError("Directory does not exist")
sysInfoPath = workload + "/sysinfo.csv"
if os.path.isfile(sysInfoPath):
print("Found sysinfo file")
sysInfo = pd.read_csv(sysInfoPath)
# Extract SoC
arch = sysInfo["gpu_soc"][0]
soc = supported_arch[arch]
# Extract name
name = sysInfo["workload_name"][0]
else:
print("Unable to parse SoC or workload name from sysinfo.csv")
sys.exit(1)
db = "omniperf_" + str(args.team) + "_" + str(name) + "_" + soc
if Extractionlvl >= 5:
print("KernelName shortening disabled")
else:
print("KernelName shortening enabled")
print("Kernel name verbose level:", Extractionlvl)
if args.password == "":
try:
password = getpass.getpass()
except Exception as error:
print("PASSWORD ERROR", error)
else:
print("Password recieved")
else:
password = args.password
if db.find(".") != -1 or db.find("-") != -1:
raise ValueError("'-' and '.' are not permited in workload name", db)
connectionInfo = {
"username": username,
"password": password,
"host": host,
"port": port,
"workload": workload,
"db": db,
}
return connectionInfo, Extractionlvl
def convert_folder(connectionInfo, Extractionlvl):
# Test connection
connection_str = (
"mongodb://"
+ connectionInfo["username"]
+ ":"
+ connectionInfo["password"]
+ "@"
+ connectionInfo["host"]
+ ":"
+ connectionInfo["port"]
+ "/?authSource=admin"
)
client = MongoClient(connection_str, serverSelectionTimeoutMS=MAX_SERVER_SEL_DELAY)
try:
client.server_info()
except:
print("ERROR: Unable to connect to the server")
sys.exit(1)
# Set up directories
if Extractionlvl < 5:
newfilepath = connectionInfo["workload"]
newfilepath_h = newfilepath + "/renamedFiles/"
if not os.path.exists(newfilepath_h):
os.mkdir(newfilepath_h)
newfilepath = newfilepath_h + connectionInfo["db"] + "/"
if not os.path.exists(newfilepath):
os.mkdir(newfilepath)
# Upload files
i = 0
file = "blank"
for file in tqdm(os.listdir(connectionInfo["workload"])):
if file.endswith(".csv"):
print(connectionInfo["workload"] + "/" + file)
try:
fileName = file[0 : file.find(".")]
# Only shorten KernelNames if instructed to
if Extractionlvl < 5:
t1 = pd.read_csv(
connectionInfo["workload"] + "/" + file,
on_bad_lines="skip",
engine="python",
)
t2 = kernel_name_shortener(t1, cache, level=Extractionlvl)
df_saved_file = t2.to_csv(newfilepath + file)
cmd = (
"mongoimport --quiet --uri mongodb://{}:{}@{}:{}/{}?authSource=admin --file {} -c {} --drop --type csv --headerline"
).format(
connectionInfo["username"],
connectionInfo["password"],
connectionInfo["host"],
connectionInfo["port"],
connectionInfo["db"],
newfilepath + file,
fileName,
)
os.system(cmd)
else:
cmd = (
"mongoimport --quiet --uri mongodb://{}:{}@{}:{}/{}?authSource=admin --file {} -c {} --drop --type csv --headerline"
).format(
connectionInfo["username"],
connectionInfo["password"],
connectionInfo["host"],
connectionInfo["port"],
connectionInfo["db"],
connectionInfo["workload"] + "/" + file,
fileName,
)
os.system(cmd)
i += 1
except pd.errors.EmptyDataError:
print("Skipping empty csv " + file)
mydb = client["workload_names"]
mycol = mydb["names"]
value = {"name": connectionInfo["db"]}
newValue = {"name": connectionInfo["db"]}
mycol.replace_one(value, newValue, upsert=True)
# Remove tmp directory if we shortened KernelNames
if Extractionlvl < 5:
shutil.rmtree(newfilepath_h)
print("{} collections added.".format(i))
print("Workload name uploaded")
@@ -0,0 +1,249 @@
##############################################################################bl
# MIT License
#
# Copyright (c) 2021 - 2023 Advanced Micro Devices, Inc. All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
##############################################################################el
import argparse
import collections
import os
import subprocess
import sys
import re
import pandas as pd
import getpass
from pymongo import MongoClient
from tqdm import tqdm
import glob
cache = dict()
supported_arch = {"gfx906": "mi50", "gfx908": "mi100", "gfx90a": "mi200"}
MAX_SERVER_SEL_DELAY = 5000 # 5 sec connection timeout
def kernel_name_shortener(workload_dir, level):
def shorten_file(df, level):
global cache
columnName = ""
if "KernelName" in df:
columnName = "KernelName"
if "Name" in df:
columnName = "Name"
if columnName == "KernelName" or columnName == "Name":
# loop through all indices
for index in df.index:
original_name = df.loc[index, columnName]
if original_name in cache:
continue
cmd = ["/opt/rocm/llvm/bin/llvm-cxxfilt", original_name]
proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
demangled_name, e = proc.communicate()
demangled_name = str(demangled_name, "UTF-8").strip()
# cache miss, add the shortened name to the dictionary
new_name = ""
matches = ""
names_and_args = re.compile(
r"(?P<name>[( )A-Za-z0-9_]+)([ ,*<>()]+)(::)?"
)
# works for name Kokkos::namespace::init_lock_array_kernel_threadid(int) [clone .kd]
if names_and_args.search(demangled_name):
matches = names_and_args.findall(demangled_name)
else:
# Works for first case '__amd_rocclr_fillBuffer.kd'
cache[original_name] = new_name
if new_name == None or new_name == "":
cache[original_name] = demangled_name
continue
current_level = 0
for name in matches:
##can cause errors if a function name or argument is equal to 'clone'
if name[0] == "clone":
continue
if len(name) == 3:
if name[2] == "::":
continue
if current_level < level:
new_name += name[0]
# closing '>' is to be taken account by the while loop
if name[1].count(">") == 0:
if current_level < level:
if not (
current_level == level - 1 and name[1].count("<") > 0
):
new_name += name[1]
current_level += name[1].count("<")
curr_index = 0
# cases include '>' '> >, ' have to go in depth here to not lose account of commas and current level
while name[1].count(">") > 0 and curr_index < len(name[1]):
if current_level < level:
new_name += name[1][curr_index:]
current_level -= name[1][curr_index:].count(">")
curr_index = len(name[1])
elif name[1][curr_index] == (">"):
current_level -= 1
curr_index += 1
cache[original_name] = new_name
if new_name == None or new_name == "":
cache[original_name] = demangled_name
df[columnName] = df[columnName].map(cache)
return df
# Only shorten if valid shortening level
if level < 5:
for fpath in glob.glob(workload_dir + "/*.csv"):
try:
orig_df = pd.read_csv(
fpath,
on_bad_lines="skip",
engine="python",
)
modified_df = shorten_file(orig_df, level)
modified_df.to_csv(fpath, index=False)
except pd.errors.EmptyDataError:
print("Skipping empty csv " + str(fpath))
# Verify target directory and setup connection
def parse(args, profileAndExport):
host = args.host
port = str(args.port)
username = args.username
Extractionlvl = args.kernelVerbose
if profileAndExport:
workload = args.workload + "/" + args.target + "/"
else:
workload = args.workload
# Verify directory path is valid
print("Pulling data from ", workload)
if os.path.isdir(workload):
print("The directory exists")
else:
raise argparse.ArgumentTypeError("Directory does not exist")
sysInfoPath = workload + "/sysinfo.csv"
if os.path.isfile(sysInfoPath):
print("Found sysinfo file")
sysInfo = pd.read_csv(sysInfoPath)
# Extract SoC
arch = sysInfo["gpu_soc"][0]
soc = supported_arch[arch]
# Extract name
name = sysInfo["workload_name"][0]
else:
print("Unable to parse SoC or workload name from sysinfo.csv")
sys.exit(1)
db = "omniperf_" + str(args.team) + "_" + str(name) + "_" + soc
if args.password == "":
try:
password = getpass.getpass()
except Exception as error:
print("PASSWORD ERROR", error)
else:
print("Password recieved")
else:
password = args.password
if db.find(".") != -1 or db.find("-") != -1:
raise ValueError("'-' and '.' are not permited in workload name", db)
connectionInfo = {
"username": username,
"password": password,
"host": host,
"port": port,
"workload": workload,
"db": db,
}
return connectionInfo, Extractionlvl
def convert_folder(connectionInfo, Extractionlvl):
# Test connection
connection_str = (
"mongodb://"
+ connectionInfo["username"]
+ ":"
+ connectionInfo["password"]
+ "@"
+ connectionInfo["host"]
+ ":"
+ connectionInfo["port"]
+ "/?authSource=admin"
)
client = MongoClient(connection_str, serverSelectionTimeoutMS=MAX_SERVER_SEL_DELAY)
try:
client.server_info()
except:
print("ERROR: Unable to connect to the server")
sys.exit(1)
i = 0
file = "blank"
for file in tqdm(os.listdir(connectionInfo["workload"])):
if file.endswith(".csv"):
print(connectionInfo["workload"] + "/" + file)
try:
fileName = file[0 : file.find(".")]
cmd = (
"mongoimport --quiet --uri mongodb://{}:{}@{}:{}/{}?authSource=admin --file {} -c {} --drop --type csv --headerline"
).format(
connectionInfo["username"],
connectionInfo["password"],
connectionInfo["host"],
connectionInfo["port"],
connectionInfo["db"],
connectionInfo["workload"] + "/" + file,
fileName,
)
os.system(cmd)
i += 1
except pd.errors.EmptyDataError:
print("Skipping empty csv " + file)
mydb = client["workload_names"]
mycol = mydb["names"]
value = {"name": connectionInfo["db"]}
newValue = {"name": connectionInfo["db"]}
mycol.replace_one(value, newValue, upsert=True)
print("{} collections added.".format(i))
print("Workload name uploaded")
+164 -76
View File
@@ -95,13 +95,19 @@ def test_df_column_equality(df):
# joins disparate runs less dumbly than rocprof
def join_prof(workload_dir, join_type, log_file, verbose, out=None):
# Set default output directory if not specified
if out == None:
out = workload_dir + "/pmc_perf.csv"
files = glob.glob(workload_dir + "/" + "pmc_perf_*.csv")
df = None
if type(workload_dir) == str:
if out is None:
out = workload_dir + "/pmc_perf.csv"
files = glob.glob(workload_dir + "/" + "pmc_perf_*.csv")
elif type(workload_dir) == list:
files = workload_dir
else:
print("ERROR: Invalid workload_dir")
sys.exit(1)
df = None
for i, file in enumerate(files):
_df = pd.read_csv(file)
_df = pd.read_csv(file) if type(workload_dir) == str else file
if join_type == "kernel":
key = _df.groupby("KernelName").cumcount()
_df["key"] = _df.KernelName + " - " + key.astype(str)
@@ -127,10 +133,15 @@ def join_prof(workload_dir, join_type, log_file, verbose, out=None):
"wgr": [col for col in df.columns if "wgr" in col],
"lds": [col for col in df.columns if "lds" in col],
"scr": [col for col in df.columns if "scr" in col],
"arch_vgpr": [col for col in df.columns if "arch_vgpr" in col],
"accum_vgpr": [col for col in df.columns if "accum_vgpr" in col],
"spgr": [col for col in df.columns if "sgpr" in col],
}
# Check for vgpr counter in ROCm < 5.3
if "vgpr" in df.columns:
duplicate_cols["vgpr"] = [col for col in df.columns if "vgpr" in col]
# Check for vgpr counter in ROCm >= 5.3
else:
duplicate_cols["arch_vgpr"] = [col for col in df.columns if "arch_vgpr" in col]
duplicate_cols["accum_vgpr"] = [col for col in df.columns if "accum_vgpr" in col]
for key, cols in duplicate_cols.items():
_df = df[cols]
if not test_df_column_equality(_df):
@@ -140,10 +151,12 @@ def join_prof(workload_dir, join_type, log_file, verbose, out=None):
)
)
warnings.warn(msg)
log_file.write(msg + "\n")
if log_file:
log_file.write(msg + "\n")
else:
msg = "Successfully joined {} in pmc_perf.csv".format(key)
log_file.write(msg + "\n")
if log_file:
log_file.write(msg + "\n")
if test_df_column_equality(_df) and verbose:
print(msg)
@@ -173,6 +186,8 @@ def join_prof(workload_dir, join_type, log_file, verbose, out=None):
"fbar",
"sig",
"obj",
# rocscope specific merged counters, keep original
"dispatch_",
]
)
]
@@ -183,7 +198,15 @@ def join_prof(workload_dir, join_type, log_file, verbose, out=None):
[
k
for k in df.keys()
if not any(check in k for check in ["DispatchNs", "CompleteNs"])
if not any(
check in k
for check in [
"DispatchNs",
"CompleteNs",
# rocscope specific timestamp
"HostDuration",
]
)
]
]
#   C) sanity check the name and key
@@ -210,12 +233,14 @@ def join_prof(workload_dir, join_type, log_file, verbose, out=None):
df["EndNs"] = endNs
# finally, join the drop key
df = df.drop(columns=["key"])
# and save to file
df.to_csv(out, index=False)
# and delete old file(s)
if not verbose:
for file in files:
os.remove(file)
# save to file and delete old file(s), skip if we're being called outside of Omniperf
if type(workload_dir) == str:
df.to_csv(out, index=False)
if not verbose:
for file in files:
os.remove(file)
else:
return df
def pmc_perf_split(workload_dir):
@@ -250,7 +275,94 @@ def pmc_perf_split(workload_dir):
os.remove(workload_perfmon_dir + "/pmc_perf.txt")
def perfmon_coalesce(pmc_files_list, workload_dir, soc):
def update_pmc_bucket(
counters, save_file, soc, pmc_list=None, stext=None, workload_perfmon_dir=None
):
# Verify inputs.
# If save_file is True, we're being called internally, from perfmon_coalesce
# Else we're being called externally, from rocomni
detected_external_call = False
if save_file and (stext is None or workload_perfmon_dir is None):
raise ValueError(
"stext and workload_perfmon_dir must be specified if save_file is True"
)
if pmc_list is None:
detected_external_call = True
pmc_list = dict(
[
("SQ", []),
("GRBM", []),
("TCP", []),
("TA", []),
("TD", []),
("TCC", []),
("SPI", []),
("CPC", []),
("CPF", []),
("GDS", []),
("TCC2", {}), # per-channel TCC perfmon
]
)
for ch in range(perfmon_config[soc]["TCC_channels"]):
pmc_list["TCC2"][str(ch)] = []
if "SQ_ACCUM_PREV_HIRES" in counters and not detected_external_call:
# save all level counters separately
nindex = counters.index("SQ_ACCUM_PREV_HIRES")
level_counter = counters[nindex - 1]
if save_file:
# Save to level counter file, file name = level counter name
fd = open(workload_perfmon_dir + "/" + level_counter + ".txt", "w")
fd.write(stext + "\n\n")
fd.write("gpu:\n")
fd.write("range:\n")
fd.write("kernel:\n")
fd.close()
return pmc_list
# save normal pmc counters in matching buckets
for counter in counters:
IP_block = counter.split(sep="_")[0].upper()
# SQC and SQ belong to the IP block, coalesce them
if IP_block == "SQC":
IP_block = "SQ"
if IP_block != "TCC":
# Insert unique pmc counters into its bucket
if counter not in pmc_list[IP_block]:
pmc_list[IP_block].append(counter)
else:
# TCC counters processing
m = re.match(r"[\s\S]+\[(\d+)\]", counter)
if m is None:
# Aggregated TCC counters
if counter not in pmc_list[IP_block]:
pmc_list[IP_block].append(counter)
else:
# TCC channel ID
ch = m.group(1)
# fake IP block for per channel TCC
if str(ch) in pmc_list["TCC2"]:
# append unique counter into the channel
if counter not in pmc_list["TCC2"][str(ch)]:
pmc_list["TCC2"][str(ch)].append(counter)
else:
# initial counter in this channel
pmc_list["TCC2"][str(ch)] = [counter]
if detected_external_call:
# sort the per channel counter, so that same counter in all channels can be aligned
for ch in range(perfmon_config[soc]["TCC_channels"]):
pmc_list["TCC2"][str(ch)].sort()
return pmc_list
def perfmon_coalesce(pmc_files_list, soc, workload_dir):
workload_perfmon_dir = workload_dir + "/perfmon"
# match pattern for pmc counters
@@ -290,54 +402,20 @@ def perfmon_coalesce(pmc_files_list, workload_dir, soc):
# we have found all the counters, store them in buckets
counters = m.group(1).split()
if "SQ_ACCUM_PREV_HIRES" in counters:
# save all level counters separately
nindex = counters.index("SQ_ACCUM_PREV_HIRES")
level_counter = counters[nindex - 1]
# Utilitze helper function once a list of counters has be extracted
save_file = True
pmc_list = update_pmc_bucket(
counters, save_file, soc, pmc_list, stext, workload_perfmon_dir
)
# Save to level counter file, file name = level counter name
fd = open(workload_perfmon_dir + "/" + level_counter + ".txt", "w")
fd.write(stext + "\n\n")
fd.write("gpu:\n")
fd.write("range:\n")
fd.write("kernel:\n")
fd.close()
continue
# save normal pmc counters in matching buckets
for counter in counters:
IP_block = counter.split(sep="_")[0].upper()
# SQC and SQ belong to the IP block, coalesce them
if IP_block == "SQC":
IP_block = "SQ"
if IP_block != "TCC":
# Insert unique pmc counters into its bucket
if counter not in pmc_list[IP_block]:
pmc_list[IP_block].append(counter)
else:
# TCC counters processing
m = re.match(r"[\s\S]+\[(\d+)\]", counter)
if m is None:
# Aggregated TCC counters
if counter not in pmc_list[IP_block]:
pmc_list[IP_block].append(counter)
else:
# TCC channel ID
ch = m.group(1)
# fake IP block for per channel TCC
if str(ch) in pmc_list["TCC2"]:
# append unique counter into the channel
if counter not in pmc_list["TCC2"][str(ch)]:
pmc_list["TCC2"][str(ch)].append(counter)
else:
# initial counter in this channel
pmc_list["TCC2"][str(ch)] = [counter]
# add a timestamp file
fd = open(workload_perfmon_dir + "/timestamps.txt", "w")
fd.write("pmc:\n\n")
fd.write("gpu:\n")
fd.write("range:\n")
fd.write("kernel:\n")
fd.close()
# sort the per channel counter, so that same counter in all channels can be aligned
for ch in range(perfmon_config[soc]["TCC_channels"]):
@@ -346,9 +424,7 @@ def perfmon_coalesce(pmc_files_list, workload_dir, soc):
return pmc_list
def perfmon_emit(pmc_list, workload_dir, soc):
workload_perfmon_dir = workload_dir + "/perfmon"
def perfmon_emit(pmc_list, soc, workload_dir=None):
# Calculate the minimum number of iteration to save the pmc counters
# non-TCC counters
pmc_cnt = [
@@ -370,7 +446,11 @@ def perfmon_emit(pmc_list, workload_dir, soc):
niter = max(math.ceil(max(pmc_cnt)), math.ceil(tcc_cnt) + math.ceil(max(tcc2_cnt)))
# Emit PMC counters into pmc config file
fd = open(workload_perfmon_dir + "/pmc_perf.txt", "w")
if workload_dir:
workload_perfmon_dir = workload_dir + "/perfmon"
fd = open(workload_perfmon_dir + "/pmc_perf.txt", "w")
else:
batches = []
tcc2_index = 0
for iter in range(niter):
@@ -400,12 +480,20 @@ def perfmon_emit(pmc_list, workload_dir, soc):
# TCC aggregated counters
line = line + " " + " ".join(tcc_counters)
fd.write(line + "\n")
if workload_dir:
fd.write(line + "\n")
else:
b = line.split()
b.remove("pmc:")
batches.append(b)
fd.write("\ngpu:\n")
fd.write("range:\n")
fd.write("kernel:\n")
fd.close()
if workload_dir:
fd.write("\ngpu:\n")
fd.write("range:\n")
fd.write("kernel:\n")
fd.close()
else:
return batches
def perfmon_filter(workload_dir, perfmon_dir, args):
@@ -445,8 +533,8 @@ def perfmon_filter(workload_dir, perfmon_dir, args):
pmc_files_list = ref_pmc_files_list
# Coalesce and writeback workload specific perfmon
pmc_list = perfmon_coalesce(pmc_files_list, workload_dir, soc)
perfmon_emit(pmc_list, workload_dir, soc)
pmc_list = perfmon_coalesce(pmc_files_list, soc, workload_dir)
perfmon_emit(pmc_list, soc, workload_dir)
def pmc_filter(workload_dir, perfmon_dir, soc):
@@ -463,5 +551,5 @@ def pmc_filter(workload_dir, perfmon_dir, soc):
pmc_files_list = ref_pmc_files_list
# Coalesce and writeback workload specific perfmon
pmc_list = perfmon_coalesce(pmc_files_list, workload_dir, soc)
perfmon_emit(pmc_list, workload_dir, soc)
pmc_list = perfmon_coalesce(pmc_files_list, soc, workload_dir)
perfmon_emit(pmc_list, soc, workload_dir)