diff --git a/CMakeLists.txt b/CMakeLists.txt index f78f23b27e..a53f8e6700 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,22 @@ add_subdirectory ( ${TEST_DIR} ${PROJECT_BINARY_DIR}/test ) ## Install information install ( TARGETS ${ROCPROFILER_TARGET} LIBRARY DESTINATION ${ROCPROFILER_NAME}/lib ) install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/inc/rocprofiler.h DESTINATION ${ROCPROFILER_NAME}/include ) +# rpl_run.sh tblextr.py txt2xml.sh +install ( FILES + ${CMAKE_CURRENT_SOURCE_DIR}/bin/rpl_run.sh + ${CMAKE_CURRENT_SOURCE_DIR}/bin/txt2xml.sh + ${CMAKE_CURRENT_SOURCE_DIR}/bin/tblextr.py + DESTINATION ${ROCPROFILER_NAME}/bin + PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) +# gfx_metrics.xml metrics.xml +install ( FILES + ${CMAKE_CURRENT_SOURCE_DIR}/test/tool/metrics.xml + ${CMAKE_CURRENT_SOURCE_DIR}/test/tool/gfx_metrics.xml + DESTINATION ${ROCPROFILER_NAME}/lib ) +# libtool.so +install ( FILES ${PROJECT_BINARY_DIR}/test/libtool.so DESTINATION ${ROCPROFILER_NAME}/tool ) +install ( FILES ${PROJECT_BINARY_DIR}/test/ctrl DESTINATION ${ROCPROFILER_NAME}/tool + PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) ## Packaging directives set ( CPACK_PACKAGE_NAME "${ROCPROFILER_NAME}-dev" ) diff --git a/bin/rpl_run.sh b/bin/rpl_run.sh new file mode 100755 index 0000000000..e172b59bb1 --- /dev/null +++ b/bin/rpl_run.sh @@ -0,0 +1,318 @@ +#!/bin/sh +time_stamp=`date +%y%m%d_%H%M%S` +BIN_DIR=`dirname $0` +BIN_DIR=`cd $BIN_DIR; pwd` +RUN_DIR=`pwd` +TMP_DIR="/tmp" +DATA_PATH=$TMP_DIR +DATA_DIR="rpl_data_${time_stamp}_$$" + +PKG_DIR=`echo $BIN_DIR | sed "s/\/bin\/*//"` +BIN_DIR=$PKG_DIR/bin + +# PATH to custom HSA and OpenCl runtimes +HSA_PATH=$PKG_DIR/lib/hsa + +export LD_LIBRARY_PATH=$PKG_DIR/lib:$PKG_DIR/tool:$HSA_PATH +export PATH=.:$PATH + +# enable error logging +export HSA_TOOLS_REPORT_LOAD_FAILURE=1 +export HSA_VEN_AMD_AQLPROFILE_LOG=1 +export ROCPROFILER_LOG=1 + +# ROC Profiler environment +# Loading of ROC Profiler by HSA runtime +export HSA_TOOLS_LIB=librocprofiler64.so +# Loading of the test tool by ROC Profiler +export ROCP_TOOL_LIB=libtool.so +# Enabling HSA dispatches intercepting by ROC PRofiler +export ROCP_HSA_INTERCEPT=1 +# Disabling internal ROC Profiler proxy queue (simple version supported for testing purposes) +unset ROCP_PROXY_QUEUE +# ROC Profiler metrics definition +export ROCP_METRICS=$PKG_DIR/lib/metrics.xml +# ROC Profiler package path +export ROCP_PACKAGE_DIR=$PKG_DIR + +# error handling +fatal() { + echo "$0: Error: $1" + echo "" + usage +} + +error() { + echo "$0: Error: $1" + echo "" + exit 1 +} + +# usage method +usage() { + bin_name=`basename $0` + echo "ROCm Profiling Library (RPL) run script, a part of ROCprofiler library package." + echo "Full path: $BIN_DIR/$bin_name" + echo "Metrics definition: $PKG_DIR/lib/metrics.xml" + echo "" + echo "Usage:" + echo " rpl_run.sh [-h] [--list-basic] [--list-derived] [-i ] [-o ] " + echo "" + echo "Options:" + echo " -h - this help" + echo " --verbose - verbose mode, dumping all base counters used in the input metrics" + echo " --list-basic - to print the list of basic HW counters" + echo " --list-derived - to print the list of derived metrics with formulas" + echo "" + echo " -i <.txt|.xml file> - input file" + echo " Input file .txt format, automatically rerun application for every pmc/sqtt line:" + echo "" + echo " # Perf counters group 1" + echo " pmc : Wavefronts VALUInsts SALUInsts SFetchInsts FlatVMemInsts LDSInsts FlatLDSInsts GDSInsts VALUUtilization FetchSize" + echo " # Perf counters group 2" + echo " pmc : WriteSize L2CacheHit" + echo " # Filter by dispatches range, GPU index and kernel names" + echo " # supported range formats: \"3:9\", \"3:\", \"3\"" + echo " range: 1 : 4" + echo " gpu: 0 1 2 3" + echo " kernel: simple Pass1 simpleConvolutionPass2" + echo "" + echo " Input file .xml format, for single profiling run:" + echo "" + echo " # Metrics list definition, also the form \":\" can be used" + echo " # All defined metrics can be found in the 'metrics.xml'" + echo " # There are basic metrics for raw HW counters and high-level metrics for derived counters" + echo " " + echo "" + echo " # Filter by dispatches range, GPU index and kernel names" + echo " " + echo "" + echo " -o - output CSV file [.csv]" + echo " -d - directory where profiler store profiling data including thread treaces [/tmp]" + echo " The data directory is renoving autonatically if the directory is matching the temporary one, which is the default." + echo " -t - to change the temporary directory [/tmp]" + echo " By changing the temporary directory you can prevent removing the profiling data from /tmp or enable removing from not '/tmp' directory." + echo "" + echo " --basenames - to turn on/off truncating of the kernel full function names till the base ones [off]" + echo " --timestamp - to turn on/off the kernel disoatches timestamps, dispatch/begin/end/complete [off]" + echo " --ctx-limit - maximum number of outstanding contexts [0 - unlimited]" + echo " --heartbeat - to turn on/off the kernel disoatches timestamps, dispatch/begin/end/complete [0 - disabled]" + echo " --sqtt-size - to set SQTT buffer size, aggregate for all SE [0x2000000]" + echo " Can be set in KB (1024B) or MB (1048576) units, examples 20K or 20M respectively." + echo " --sqtt-local - to allocate SQTT buffer in local GPU memory [on]" + echo "" + echo "Configuration file:" + echo " You can set your parameters defaults preferences in the configuration file 'rpl_rc.xml'. The search path sequence: .:${HOME}:" + echo " First the configuration file is looking in the current directory, then in your home, and then in the package directory." + echo " Configurable options: 'basenames', 'timestamp', 'ctx-limit', 'heartbeat', 'sqtt-size', 'sqtt-local'." + echo " An example of 'rpl_rc.xml':" + echo " " + echo "" + exit 1 +} + +# profiling run method +OUTPUT_LIST="" +run() { + export ROCP_INPUT="$1" + OUTPUT_DIR="$2" + shift + shift + APP_CMD=$* + + if [ "$OUTPUT_DIR" = "-" ] ; then + input_tag=`echo $ROCP_INPUT | sed "s/\.xml//"` + export ROCP_OUTPUT_DIR=${input_tag}_results_${time_stamp} + elif [ "$OUTPUT_DIR" = "--" ] ; then + unset ROCP_OUTPUT_DIR + else + export ROCP_OUTPUT_DIR=$OUTPUT_DIR + fi + echo "RPL: result dir '$ROCP_OUTPUT_DIR'" + + if [ ! -e "$ROCP_INPUT" ] ; then + error "Input file '$ROCP_INPUT' not found" + fi + + if [ -n "$ROCP_OUTPUT_DIR" ] ; then + if [ "$OUTPUT_DIR" = "-" ] ; then + if [ -e "$ROCP_OUTPUT_DIR" ] ; then + error "generated dir '$ROCP_OUTPUT_DIR' exists" + fi + fi + mkdir -p "$ROCP_OUTPUT_DIR" + fi + + if [ -n "$ROCP_OUTPUT_DIR" ] ; then + OUTPUT_LIST="$OUTPUT_LIST $ROCP_OUTPUT_DIR/results.txt" + eval "$APP_CMD 2>&1 | tee $ROCP_OUTPUT_DIR/log.txt" + else + eval "$APP_CMD" + fi +} + +# main +echo "RPL: on '$time_stamp' from '$PKG_DIR' in '$RUN_DIR'" +# Parsing arguments +if [ -z "$1" ] ; then + usage +fi + +INPUT_FILE="" +OUTPUT_DIR="-" +output="" +csv_output="" + +ARG_IN="" +while [ 1 ] ; do + ARG_IN=$1 + ARG_VAL=1 + if [ "$1" = "-h" ] ; then + usage + elif [ "$1" = "-i" ] ; then + INPUT_FILE="$2" + elif [ "$1" = "-o" ] ; then + output="$2" + elif [ "$1" = "-d" ] ; then + OUTPUT_DIR="$2" + DATA_PATH=$OUTPUT_DIR + elif [ "$1" = "-t" ] ; then + TMP_DIR="$2" + if [ "$OUTPUT_DIR" = "-" ] ; then + DATA_PATH=$TMP_DIR + fi + elif [ "$1" = "--list-basic" ] ; then + export ROCP_INFO=b + eval "$PKG_DIR/tool/ctrl" + exit 1 + elif [ "$1" = "--list-derived" ] ; then + export ROCP_INFO=d + eval "$PKG_DIR/tool/ctrl" + exit 1 + elif [ "$1" = "--basenames" ] ; then + if [ "$2" = "on" ] ; then + export ROCP_TRUNCATE_NAMES=1 + else + export ROCP_TRUNCATE_NAMES=0 + fi + elif [ "$1" = "--timestamp" ] ; then + if [ "$2" = "on" ] ; then + export ROCP_TIMESTAMP_ON=1 + else + export ROCP_TIMESTAMP_ON=0 + fi + elif [ "$1" = "--ctx-limit" ] ; then + export ROCP_OUTSTANDING_MAX="$2" + elif [ "$1" = "--heartbeat" ] ; then + export ROCP_OUTSTANDING_MON="$2" + elif [ "$1" = "--sqtt-size" ] ; then + size_m=`echo "$2" | sed -n "s/^\(.*\)M$/\1/p"` + size_k=`echo "$2" | sed -n "s/^\(.*\)K$/\1/p"` + if [ -n "$size_m" ] ; then size_b=$((size_m*1024*1024)) + elif [ -n "$size_k" ] ; then size_b=$((size_k*1024)) + else size_b=$2 + fi + export ROCP_SQTT_SIZE=$size_b + elif [ "$1" = "--sqtt-local" ] ; then + if [ "$2" = "on" ] ; then + export ROCP_SQTT_LOCAL=1 + else + export ROCP_SQTT_LOCAL=0 + fi + elif [ "$1" = "--verbose" ] ; then + ARG_VAL=0 + export ROCP_VERBOSE_MODE=1 + else + break + fi + shift + if [ "$ARG_VAL" = 1 ] ; then shift; fi +done + +ARG_CK=`echo $ARG_IN | sed "s/^-.*$/-/"` +if [ "$ARG_CK" = "-" ] ; then + fatal "Wrong option '$ARG_IN'" +fi + +if [ -z "$INPUT_FILE" ] ; then + fatal "Need input file" +fi + +input_base=`echo "$INPUT_FILE" | sed "s/^\(.*\)\.\([^\.]*\)$/\1/"` +input_type=`echo "$INPUT_FILE" | sed "s/^\(.*\)\.\([^\.]*\)$/\2/"` +if [ -z "${input_base}" -o -z "${input_type}" ] ; then + fatal "Bad input file '$INPUT_FILE'" +fi +input_base=`basename $input_base` + +if [ "$OUTPUT_DIR" = "--" ] ; then + fatal "Bad output dir '$OUTPUT_DIR'" +fi + +if [ -n "$output" ] ; then + if [ "$output" = "--" ] ; then + OUTPUT_DIR="--" + else + csv_output=$output + fi +else + csv_output=$RUN_DIR/${input_base}.csv +fi + +APP_CMD=$* + +echo "RPL: profiling '$APP_CMD'" +echo "RPL: input file '$INPUT_FILE'" + +input_list="" +RES_DIR="" +if [ "$input_type" = "xml" ] ; then + input_list=$INPUT_FILE +elif [ "$input_type" = "txt" ] ; then + OUTPUT_DIR="-" + RES_DIR=$DATA_PATH/$DATA_DIR + if [ -e $RES_DIR ] ; then + error "Rundir '$RES_DIR' exists" + fi + mkdir -p $RES_DIR + echo "RPL: output dir '$RES_DIR'" + $BIN_DIR/txt2xml.sh $INPUT_FILE $RES_DIR + input_list=`/bin/ls $RES_DIR/input*.xml` +else + fatal "Bad input file type '$INPUT_FILE'" +fi + +for name in $input_list; do + run $name $OUTPUT_DIR $APP_CMD +done + +if [ -n "$csv_output" ] ; then + python $BIN_DIR/tblextr.py $csv_output $OUTPUT_LIST + if [ "$?" = 1 ] ; then + error "CSV generation error, profiling results '$RES_DIR'" + fi + echo "RPL: '$csv_output' is generated" +fi + +if [ "$DATA_PATH" = "$TMP_DIR" ] ; then + if [ -e "$RES_DIR" ] ; then + rm -rf $RES_DIR + fi +fi + +exit 0 diff --git a/bin/tblextr.py b/bin/tblextr.py new file mode 100755 index 0000000000..3be933f744 --- /dev/null +++ b/bin/tblextr.py @@ -0,0 +1,97 @@ +#!/usr/bin/python +import os, sys, re + +# Parsing results in the format: +#dispatch[0], queue_index(0), kernel_name("SimpleConvolution"), time(1048928000311041,1048928006154674,1048928006168274,1048928006170503): +# GRBM_GUI_ACTIVE (74332) +# SQ_WAVES (4096) +# SQ_INSTS_VMEM_RD (36864) + +# global vars +var_list = ['Index', 'KernelName', 'DispatchNs', 'BeginNs', 'EndNs', 'CompleteNs'] +var_table = {} +############################################################# + +def fatal(msg): + sys.stderr.write(sys.argv[0] + ": " + msg + "\n"); + sys.exit(1) +############################################################# + +# parse results method +def parse_res(infile): + if not os.path.isfile(infile): fatal("Error: input file '" + infile + "' not found") + inp = open(infile, 'r') + + beg_pattern = re.compile("^dispatch\[(\d*)\], queue_index\(\d*\), kernel_name\(\"([^\"]*)\"\)") + ts_pattern = re.compile(", time\((\d*),(\d*),(\d*),(\d*)\)") + var_pattern = re.compile("^\s*([^\s]*)\s+\((\d*)\)") + + dispatch_number = 0 + for line in inp.readlines(): + record = line[:-1] + + m = var_pattern.match(record) + if m: + if not dispatch_number in var_table: fatal("Error: dispatch number not unique '" + str(dispatch_number) + "'") + var = m.group(1) + val = m.group(2) + var_table[dispatch_number][m.group(1)] = m.group(2) + if not var in var_list: var_list.append(var) + + m = beg_pattern.match(record) + if m: + dispatch_number = m.group(1) + if not dispatch_number in var_table: + var_table[dispatch_number] = { + 'Index': dispatch_number, + 'KernelName': "\"" + m.group(2) + "\"" + } + m = ts_pattern.search(record) + if m: + var_table[dispatch_number]['DispatchNs'] = m.group(1) + var_table[dispatch_number]['BeginNs'] = m.group(2) + var_table[dispatch_number]['EndNs'] = m.group(3) + var_table[dispatch_number]['CompleteNs'] = m.group(4) + + inp.close() +############################################################# + +# print results table method +def print_tbl(outfile): + global var_list + + out = open(outfile, 'w') + + keys = var_table.keys() + keys.sort(key=int) + + entry = var_table[keys[0]] + list1 = [] + for var in var_list: + if var in entry: + list1.append(var) + var_list = list1 + + for var in var_list: out.write(var + ',') + out.write("\n") + + for ind in keys: + entry = var_table[ind] + dispatch_number = entry['Index'] + if ind != dispatch_number: fatal("Dispatch #" + ind + " index mismatch (" + dispatch_number + ")\n") + for var in var_list: out.write(entry[var] + ',') + out.write("\n") + + out.close() +############################################################# + +# main +if (len(sys.argv) < 3): fatal("Usage: " + sys.argv[0] + " ") + +outfile = sys.argv[1] +infiles = sys.argv[2:] +for f in infiles : + parse_res(f) +print_tbl(outfile) +sys.exit(0) +############################################################# diff --git a/bin/txt2xml.sh b/bin/txt2xml.sh new file mode 100755 index 0000000000..f36507916e --- /dev/null +++ b/bin/txt2xml.sh @@ -0,0 +1,72 @@ +#!/bin/bash +timestamp=`date +%y%m%d_%H%M%S` + +if [ $# = 0 ] ; then + echo "Usage: $0 [output dir]" + exit -1 +fi + +input=$1 +outdir=$2 +if [ -z "$outdir" ] ; then + outdir="." +fi + +range="" +kernel="" +gpu_index="" + +parse() { + scan="$1" + index=0 + while read -r line ; do + line=`echo $line | sed "s/\s*#.*$//"` + if [ -z "$line" ] ; then + continue + fi + + feature=`echo $line | sed -n "s/^\s*\([a-z]*\)\s*:.*$/\1/p"` + line=`echo $line | sed "s/^[^:]*:\s*//"` + line=`echo "$line" | sed -e "s/\s*=\s*/=/g" -e "s/\s*:\s*/:/g" -e "s/,\{1,\}/ /g" -e "s/\s\{1,\}/ /g" -e "s/\s*$//"` + + if [ "$scan" = 0 ] ; then + line=`echo "$line" | sed -e "s/ /,/g"` + if [ "$feature" == "range" ] ; then + range=$line + fi + if [ "$feature" == "kernel" ] ; then + kernel=$line + fi + if [ "$feature" == "gpu" ] ; then + gpu_index=$line + fi + else + output=$outdir/input${index}.xml + header="# $timestamp '$output' generated with '$0 $*'" + + if [ "$feature" == "pmc" ] ; then + line=`echo "$line" | sed -e "s/ /,/g"` + cat >> $output < + +EOF + fi + + if [ "$feature" == "sqtt" ] ; then + cat >> $output < + +EOF + fi + fi + + index=$((index + 1)) + done < $input +} + +parse 0 +parse 1 + +exit 0 diff --git a/test/tool/gfx_metrics.xml b/test/tool/gfx_metrics.xml index 899ca85e72..54dc50337c 100644 --- a/test/tool/gfx_metrics.xml +++ b/test/tool/gfx_metrics.xml @@ -13,11 +13,11 @@ - - - - - + + + + + @@ -26,8 +26,8 @@ - - + + @@ -47,11 +47,11 @@ - - - - - + + + + +