2024-05-29 15:35:10 +05:30
#!/usr/bin/env python3
import os
import sys
import argparse
import subprocess
2024-07-26 21:46:53 -05:00
class dotdict ( dict ):
"""dot.notation access to dictionary attributes"""
__getattr__ = dict . get
__setattr__ = dict . __setitem__
__delattr__ = dict . __delitem__
def __init__ ( self , d ):
super ( dotdict , self ) . __init__ ( d )
for k , v in self . items ():
if isinstance ( v , dict ):
self . __setitem__ ( k , dotdict ( v ))
elif isinstance ( v , ( list , tuple )):
self . __setitem__ (
k ,
[ dotdict ( i ) if isinstance ( i , ( list , tuple , dict )) else i for i in v ],
)
2024-05-29 15:35:10 +05:30
def fatal_error ( msg , exit_code = 1 ):
sys . stderr . write ( f "Fatal error: { msg } \n " )
sys . stderr . flush ()
sys . exit ( exit_code )
2024-07-26 21:46:53 -05:00
def strtobool ( val ):
"""Convert a string representation of truth to true or false.
True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
'val' is anything else.
"""
if isinstance ( val , ( list , tuple )):
if len ( val ) > 1 :
val_type = type ( val ) . __name__
raise ValueError ( f "invalid truth value { val } (type= { val_type } )" )
else :
val = val [ 0 ]
if isinstance ( val , bool ):
return val
elif isinstance ( val , str ) and val . lower () in ( "y" , "yes" , "t" , "true" , "on" , "1" ):
return True
elif isinstance ( val , str ) and val . lower () in ( "n" , "no" , "f" , "false" , "off" , "0" ):
return False
else :
val_type = type ( val ) . __name__
raise ValueError ( f "invalid truth value { val } (type= { val_type } )" )
class booleanArgAction ( argparse . Action ):
def __call__ ( self , parser , args , value , option_string = None ):
setattr ( args , self . dest , strtobool ( value ))
2024-05-29 15:35:10 +05:30
def parse_arguments ( args = None ):
usage_examples = """
%(prog)s requires double-hyphen (--) before the application to be executed, e.g.
$ rocprofv3 [<rocprofv3-option> ...] -- <application> [<application-arg> ...]
$ rocprofv3 --hip-trace -- ./myapp -n 1
For MPI applications (or other job launchers such as SLURM), place rocprofv3 inside the job launcher:
$ mpirun -n 4 rocprofv3 --hip-trace -- ./mympiapp
"""
# Create the parser
parser = argparse . ArgumentParser (
description = "ROCProfilerV3 Run Script" ,
usage = " %(prog)s [options] -- <application> [application options]" ,
epilog = usage_examples ,
formatter_class = argparse . RawTextHelpFormatter ,
)
2024-09-09 11:20:55 -05:00
def add_parser_bool_argument ( gparser , * args , ** kwargs ):
gparser . add_argument (
2024-07-26 21:46:53 -05:00
* args ,
** kwargs ,
action = booleanArgAction ,
nargs = "?" ,
const = True ,
type = str ,
required = False ,
metavar = "BOOL" ,
)
2024-09-09 11:20:55 -05:00
io_options = parser . add_argument_group ( "I/O options" )
io_options . add_argument (
"-i" ,
"--input" ,
help = "Input file for counter collection" ,
required = False ,
)
io_options . add_argument (
"-o" ,
"--output-file" ,
help = "For the output file name" ,
default = os . environ . get ( "ROCPROF_OUTPUT_FILE_NAME" , None ),
type = str ,
required = False ,
)
io_options . add_argument (
"-d" ,
"--output-directory" ,
help = "For adding output path where the output files will be saved" ,
default = os . environ . get ( "ROCPROF_OUTPUT_PATH" , None ),
type = str ,
required = False ,
)
io_options . add_argument (
"--output-format" ,
help = "For adding output format (supported formats: csv, json, pftrace, otf2)" ,
nargs = "+" ,
default = None ,
choices = ( "csv" , "json" , "pftrace" , "otf2" ),
type = str . lower ,
)
io_options . add_argument (
"--log-level" ,
help = "Set the log level" ,
default = None ,
choices = ( "fatal" , "error" , "warning" , "info" , "trace" , "env" ),
type = str . lower ,
)
aggregate_tracing_options = parser . add_argument_group ( "Aggregate tracing options" )
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
aggregate_tracing_options ,
"-r" ,
"--runtime-trace" ,
2024-09-11 22:42:58 -07:00
help = "Collect tracing data for HIP runtime API, Marker (ROCTx) API, RCCL API, Memory operations (copies and scratch), and Kernel dispatches. Similar to --sys-trace but without tracing HIP compiler API and the underlying HSA API." ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
aggregate_tracing_options ,
"-s" ,
"--sys-trace" ,
2024-09-11 22:42:58 -07:00
help = "Collect tracing data for HIP API, HSA API, Marker (ROCTx) API, RCCL API, Memory operations (copies and scratch), and Kernel dispatches." ,
2024-05-29 15:35:10 +05:30
)
2024-09-09 11:20:55 -05:00
basic_tracing_options = parser . add_argument_group ( "Basic tracing options" )
# Add the arguments
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
basic_tracing_options ,
"--hip-trace" ,
help = "For collecting HIP Traces (runtime + compiler)" ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
basic_tracing_options ,
2024-05-29 15:35:10 +05:30
"--marker-trace" ,
2024-09-09 11:20:55 -05:00
help = "For collecting Marker (ROCTx) Traces" ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
basic_tracing_options ,
2024-05-29 15:35:10 +05:30
"--kernel-trace" ,
2024-09-09 11:20:55 -05:00
help = "For collecting Kernel Dispatch Traces" ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
basic_tracing_options ,
2024-05-29 15:35:10 +05:30
"--memory-copy-trace" ,
2024-09-09 11:20:55 -05:00
help = "For collecting Memory Copy Traces" ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
basic_tracing_options ,
2024-05-29 15:35:10 +05:30
"--scratch-memory-trace" ,
2024-09-09 11:20:55 -05:00
help = "For collecting Scratch Memory operations Traces" ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
basic_tracing_options ,
"--hsa-trace" ,
help = "For collecting HSA Traces (core + amd + image + finalizer)" ,
)
2024-09-11 22:42:58 -07:00
add_parser_bool_argument (
basic_tracing_options ,
"--rccl-trace" ,
help = "For collecting RCCL Traces" ,
)
2024-09-12 00:46:07 -05:00
add_parser_bool_argument (
basic_tracing_options ,
"--kokkos-trace" ,
help = "Enable built-in Kokkos Tools support (implies --marker-trace and --kernel-rename)" ,
)
2024-09-09 11:20:55 -05:00
extended_tracing_options = parser . add_argument_group ( "Granular tracing options" )
add_parser_bool_argument (
extended_tracing_options ,
"--hip-runtime-trace" ,
help = "For collecting HIP Runtime API Traces, e.g. public HIP API functions starting with 'hip' (i.e. hipSetDevice)." ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
extended_tracing_options ,
"--hip-compiler-trace" ,
help = "For collecting HIP Compiler generated code Traces, e.g. HIP API functions starting with '__hip' (i.e. __hipRegisterFatBinary)." ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
extended_tracing_options ,
2024-05-29 15:35:10 +05:30
"--hsa-core-trace" ,
2024-09-09 11:20:55 -05:00
help = "For collecting HSA API Traces (core API), e.g. HSA functions prefixed with only 'hsa_' (i.e. hsa_init)." ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
extended_tracing_options ,
2024-05-29 15:35:10 +05:30
"--hsa-amd-trace" ,
2024-09-09 11:20:55 -05:00
help = "For collecting HSA API Traces (AMD-extension API), e.g. HSA function prefixed with 'hsa_amd_' (i.e. hsa_amd_coherency_get_type)." ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
extended_tracing_options ,
2024-05-29 15:35:10 +05:30
"--hsa-image-trace" ,
2024-09-09 11:20:55 -05:00
help = "For collecting HSA API Traces (Image-extenson API), e.g. HSA functions prefixed with only 'hsa_ext_image_' (i.e. hsa_ext_image_get_capability)." ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
extended_tracing_options ,
2024-05-29 15:35:10 +05:30
"--hsa-finalizer-trace" ,
2024-09-09 11:20:55 -05:00
help = "For collecting HSA API Traces (Finalizer-extension API), e.g. HSA functions prefixed with only 'hsa_ext_program_' (i.e. hsa_ext_program_create)." ,
2024-05-29 15:35:10 +05:30
)
2024-09-09 11:20:55 -05:00
post_processing_options = parser . add_argument_group ( "Post-processing tracing options" )
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
post_processing_options ,
"--stats" ,
help = "For collecting statistics of enabled tracing types" ,
2024-05-29 15:35:10 +05:30
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
post_processing_options ,
"-S" ,
"--summary" ,
help = "Output single summary of tracing data at the conclusion of the profiling session" ,
)
add_parser_bool_argument (
post_processing_options ,
"-D" ,
"--summary-per-domain" ,
help = "Output summary for each tracing domain at the conclusion of the profiling session" ,
)
post_processing_options . add_argument (
"--summary-groups" ,
help = "Output a summary for each set of domains matching the regular expression, e.g. 'KERNEL_DISPATCH|MEMORY_COPY' will generate a summary from all the tracing data in the KERNEL_DISPATCH and MEMORY_COPY domains; '*._API' will generate a summary from all the tracing data in the HIP_API, HSA_API, and MARKER_API domains" ,
nargs = "+" ,
default = None ,
type = str ,
metavar = "REGULAR_EXPRESSION" ,
)
summary_options = parser . add_argument_group ( "Summary options" )
summary_options . add_argument (
"--summary-output-file" ,
help = "Output summary to a file, stdout, or stderr (default: stderr)" ,
default = None ,
type = str ,
)
summary_options . add_argument (
"-u" ,
"--summary-units" ,
help = "Timing units for output summary" ,
default = None ,
type = str ,
choices = ( "sec" , "msec" , "usec" , "nsec" ),
)
kernel_naming_options = parser . add_argument_group ( "Kernel naming options" )
add_parser_bool_argument (
kernel_naming_options ,
2024-05-29 15:35:10 +05:30
"-M" ,
"--mangled-kernels" ,
help = "Do not demangle the kernel names" ,
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
kernel_naming_options ,
2024-05-29 15:35:10 +05:30
"-T" ,
"--truncate-kernels" ,
help = "Truncate the demangled kernel names" ,
)
2024-07-26 21:46:53 -05:00
add_parser_bool_argument (
2024-09-09 11:20:55 -05:00
kernel_naming_options ,
2024-07-29 14:33:50 -05:00
"--kernel-rename" ,
help = "Use region names defined by roctxRangePush/roctxRangePop regions to rename the kernels" ,
)
2024-09-09 11:20:55 -05:00
filter_options = parser . add_argument_group ( "Filtering options" )
filter_options . add_argument (
2024-07-26 21:46:53 -05:00
"--kernel-include-regex" ,
2024-09-09 11:20:55 -05:00
help = "Include the kernels matching this filter from counter-collection and thread-trace data (non-matching kernels will be excluded)" ,
2024-05-29 15:35:10 +05:30
default = None ,
type = str ,
2024-07-26 21:46:53 -05:00
metavar = "REGULAR_EXPRESSION" ,
)
2024-09-09 11:20:55 -05:00
filter_options . add_argument (
2024-07-26 21:46:53 -05:00
"--kernel-exclude-regex" ,
2024-09-09 11:20:55 -05:00
help = "Exclude the kernels matching this filter from counter-collection and thread-trace data (applied after --kernel-include-regex option)" ,
2024-07-26 21:46:53 -05:00
default = None ,
type = str ,
metavar = "REGULAR_EXPRESSION" ,
)
2024-09-09 11:20:55 -05:00
filter_options . add_argument (
2024-07-26 21:46:53 -05:00
"--kernel-iteration-range" ,
help = "Iteration range" ,
2024-05-29 15:35:10 +05:30
nargs = "+" ,
2024-07-26 21:46:53 -05:00
default = None ,
type = str ,
2024-05-29 15:35:10 +05:30
)
2024-09-09 11:20:55 -05:00
perfetto_options = parser . add_argument_group ( "Perfetto-specific options" )
perfetto_options . add_argument (
2024-07-29 14:33:50 -05:00
"--perfetto-backend" ,
help = "Perfetto data collection backend. 'system' mode requires starting traced and perfetto daemons" ,
default = None ,
type = str ,
nargs = 1 ,
choices = ( "inprocess" , "system" ),
)
2024-09-09 11:20:55 -05:00
perfetto_options . add_argument (
2024-07-29 14:33:50 -05:00
"--perfetto-buffer-size" ,
help = "Size of buffer for perfetto output in KB. default: 1 GB" ,
default = None ,
type = int ,
metavar = "KB" ,
)
2024-09-09 11:20:55 -05:00
perfetto_options . add_argument (
2024-07-29 14:33:50 -05:00
"--perfetto-buffer-fill-policy" ,
help = "Policy for handling new records when perfetto has reached the buffer limit" ,
default = None ,
type = str ,
choices = ( "discard" , "ring_buffer" ),
)
2024-09-09 11:20:55 -05:00
perfetto_options . add_argument (
2024-07-29 14:33:50 -05:00
"--perfetto-shmem-size-hint" ,
help = "Perfetto shared memory size hint in KB. default: 64 KB" ,
default = None ,
type = int ,
metavar = "KB" ,
)
2024-05-29 15:35:10 +05:30
2024-09-09 11:20:55 -05:00
display_options = parser . add_argument_group ( "Display options" )
add_parser_bool_argument (
display_options ,
"-L" ,
"--list-metrics" ,
help = "List metrics for counter collection" ,
)
advanced_options = parser . add_argument_group ( "Advanced options" )
advanced_options . add_argument (
"--preload" ,
help = "Libraries to prepend to LD_PRELOAD (useful for sanitizer libraries)" ,
default = os . environ . get ( "ROCPROF_PRELOAD" , "" ) . split ( ":" ),
nargs = "*" ,
)
2024-09-11 15:27:35 -05:00
# below is available for CI because LD_PRELOADing a library linked to a sanitizer library
# causes issues in apps where HIP is part of shared library.
add_parser_bool_argument (
advanced_options ,
"--suppress-marker-preload" ,
help = argparse . SUPPRESS ,
)
2024-09-09 11:20:55 -05:00
2024-05-29 15:35:10 +05:30
if args is None :
args = sys . argv [ 1 :]
rocp_args = args [:]
2024-07-26 21:46:53 -05:00
2024-05-29 15:35:10 +05:30
app_args = []
for idx , itr in enumerate ( args ):
if itr == "--" :
rocp_args = args [ 0 : idx ]
app_args = args [( idx + 1 ) :]
break
return ( parser . parse_args ( rocp_args ), app_args )
def parse_yaml ( yaml_file ):
try :
import yaml
except ImportError as e :
fatal_error (
f " { e } \n\n YAML package is not installed. Run ' { sys . executable } -m pip install pyyaml' or use JSON or text format"
)
try :
2024-07-26 21:46:53 -05:00
lst = []
2024-05-29 15:35:10 +05:30
with open ( yaml_file , "r" ) as file :
data = yaml . safe_load ( file )
2024-07-26 21:46:53 -05:00
for itr in data [ "jobs" ]:
# TODO: support naming jobs
# if isinstance(itr, str):
# itr = data["jobs"][itr]
itr [ "sub_directory" ] = "pass_"
lst . append ( itr )
return [ dotdict ( itr ) for itr in lst ]
2024-05-29 15:35:10 +05:30
except yaml . YAMLError as exc :
fatal_error ( f " { exc } " )
return None
def parse_json ( json_file ):
import json
try :
2024-07-26 21:46:53 -05:00
lst = []
2024-05-29 15:35:10 +05:30
with open ( json_file , "r" ) as file :
data = json . load ( file )
2024-07-26 21:46:53 -05:00
for itr in data [ "jobs" ]:
itr [ "sub_directory" ] = "pass_"
lst . append ( itr )
return [ dotdict ( itr ) for itr in lst ]
2024-05-29 15:35:10 +05:30
except Exception as e :
fatal_error ( f " { e } " )
return None
def parse_text ( text_file ):
def process_line ( line ):
if "pmc:" not in line :
return ""
line = line . strip ()
pos = line . find ( "#" )
if pos >= 0 :
line = line [ 0 : pos ]
def _dedup ( _line , _sep ):
for itr in _sep :
_line = " " . join ( _line . split ( itr ))
2024-07-26 21:46:53 -05:00
return _line . strip ()
2024-05-29 15:35:10 +05:30
# remove tabs and duplicate spaces
2024-07-26 21:46:53 -05:00
return _dedup ( line . replace ( "pmc:" , "" ), [ " \n " , " \t " , " " ]) . split ( " " )
2024-05-29 15:35:10 +05:30
try :
with open ( text_file , "r" ) as file :
return [
litr
for litr in [ process_line ( itr ) for itr in file . readlines ()]
if len ( litr ) > 0
]
except Exception as e :
fatal_error ( f " { e } " )
return None
def parse_input ( input_file ):
2024-07-26 21:46:53 -05:00
2024-05-29 15:35:10 +05:30
_ , extension = os . path . splitext ( input_file )
if extension == ".txt" :
2024-07-26 21:46:53 -05:00
text_input = parse_text ( input_file )
text_input_lst = [{ "pmc" : itr , "sub_directory" : "pmc_" } for itr in text_input ]
return [ dotdict ( itr ) for itr in text_input_lst ]
2024-05-29 15:35:10 +05:30
elif extension in ( ".yaml" , ".yml" ):
2024-07-26 21:46:53 -05:00
return parse_yaml ( input_file )
2024-05-29 15:35:10 +05:30
elif extension == ".json" :
2024-07-26 21:46:53 -05:00
return parse_json ( input_file )
2024-05-29 15:35:10 +05:30
else :
fatal_error (
f "Input file ' { input_file } ' does not have a recognized extension (.txt, .json, .yaml, .yml) \n "
)
2024-07-26 21:46:53 -05:00
return None
2024-05-29 15:35:10 +05:30
2024-07-26 21:46:53 -05:00
def has_set_attr ( obj , key ):
if obj and hasattr ( obj , key ) and getattr ( obj , key ) is not None :
return True
else :
return False
def patch_args ( data ):
"""Used to handle certain fields which might be specified as a string instead of an array or vice-versa"""
if hasattr ( data , "kernel_iteration_range" ) and isinstance (
data . kernel_iteration_range , str
):
data . kernel_iteration_range = [ data . kernel_iteration_range ]
return data
def get_args ( cmd_args , inp_args ):
def ensure_type ( name , var , type_id ):
if not isinstance ( var , type_id ):
raise TypeError (
f " { name } is of type { type ( var ) . __name__ } , expected { type ( type_id ) . __name__ } "
)
ensure_type ( "cmd_args" , cmd_args , argparse . Namespace )
ensure_type ( "inp_args" , inp_args , dotdict )
cmd_keys = list ( cmd_args . __dict__ . keys ())
inp_keys = list ( inp_args . keys ())
data = {}
def get_attr ( key ):
if has_set_attr ( cmd_args , key ):
return getattr ( cmd_args , key )
elif has_set_attr ( inp_args , key ):
return getattr ( inp_args , key )
return None
for itr in set ( cmd_keys + inp_keys ):
if (
has_set_attr ( cmd_args , itr )
and has_set_attr ( inp_args , itr )
and getattr ( cmd_args , itr ) != getattr ( inp_args , itr )
):
raise RuntimeError ( f "conflicting value for { itr } " )
else :
data [ itr ] = get_attr ( itr )
return patch_args ( dotdict ( data ))
def run ( app_args , args , ** kwargs ):
2024-05-29 15:35:10 +05:30
app_env = dict ( os . environ )
2024-07-26 21:46:53 -05:00
use_execv = kwargs . get ( "use_execv" , True )
app_pass = kwargs . get ( "pass_id" , None )
2024-05-29 15:35:10 +05:30
def update_env ( env_var , env_val , ** kwargs ):
"""Local function for updating application environment which supports
various options for dealing with existing environment variables
"""
_overwrite = kwargs . get ( "overwrite" , True )
_prepend = kwargs . get ( "prepend" , False )
_append = kwargs . get ( "append" , False )
_join_char = kwargs . get ( "join_char" , ":" )
# only overwrite if env_val evaluates as true
_overwrite_if_true = kwargs . get ( "overwrite_if_true" , False )
# only overwrite if env_val evaluates as false
_overwrite_if_false = kwargs . get ( "overwrite_if_false" , False )
_formatter = kwargs . get (
"formatter" ,
lambda x : f " { x } " if not isinstance ( x , bool ) else "1" if x else "0" ,
)
for itr in kwargs . keys ():
if itr not in (
"overwrite" ,
"prepend" ,
"append" ,
"join_char" ,
"overwrite_if_true" ,
"overwrite_if_false" ,
"formatter" ,
):
fatal_error (
f "Internal error in update_env(' { env_var } ', { env_val } , { itr } = { kwargs [ itr ] } ). Invalid key: { itr } "
)
if env_val is None :
return app_env . get ( env_var , None )
_val = _formatter ( env_val )
_curr_val = app_env . get ( env_var , None )
def _write_env_value ():
if _overwrite_if_true :
if bool ( env_val ) is True :
app_env [ env_var ] = _val
elif _overwrite_if_false :
if bool ( env_val ) is False :
app_env [ env_var ] = _val
else :
app_env [ env_var ] = _val
if _curr_val is not None :
if not _overwrite :
pass
elif _prepend :
2024-09-09 11:20:55 -05:00
app_env [ env_var ] = (
" {}{}{} " . format ( _val , _join_char , _curr_val ) if _val else _curr_val
2024-09-11 15:27:35 -05:00
) . strip ( ":" )
2024-05-29 15:35:10 +05:30
elif _append :
2024-09-09 11:20:55 -05:00
app_env [ env_var ] = (
" {}{}{} " . format ( _curr_val , _join_char , _val ) if _val else _curr_val
2024-09-11 15:27:35 -05:00
) . strip ( ":" )
2024-05-29 15:35:10 +05:30
elif _overwrite :
_write_env_value ()
else :
_write_env_value ()
return app_env . get ( env_var , None )
update_env ( "ROCPROFILER_LIBRARY_CTOR" , True )
ROCPROFV3_DIR = os . path . dirname ( os . path . realpath ( __file__ ))
ROCM_DIR = os . path . dirname ( ROCPROFV3_DIR )
ROCPROF_TOOL_LIBRARY = f " { ROCM_DIR } /lib/rocprofiler-sdk/librocprofiler-sdk-tool.so"
ROCPROF_SDK_LIBRARY = f " { ROCM_DIR } /lib/librocprofiler-sdk.so"
2024-09-09 11:20:55 -05:00
ROCPROF_ROCTX_LIBRARY = f " { ROCM_DIR } /lib/librocprofiler-sdk-roctx.so"
2024-09-12 00:46:07 -05:00
ROCPROF_KOKKOSP_LIBRARY = (
f " { ROCM_DIR } /lib/rocprofiler-sdk/librocprofiler-sdk-tool-kokkosp.so"
)
2024-05-29 15:35:10 +05:30
2024-09-09 11:20:55 -05:00
prepend_preload = [ itr for itr in args . preload if itr ]
append_preload = [ ROCPROF_TOOL_LIBRARY , ROCPROF_SDK_LIBRARY ]
2024-05-29 15:35:10 +05:30
2024-09-09 11:20:55 -05:00
update_env ( "LD_PRELOAD" , ":" . join ( prepend_preload ), prepend = True )
update_env ( "LD_PRELOAD" , ":" . join ( append_preload ), append = True )
2024-07-26 21:46:53 -05:00
2024-05-29 15:35:10 +05:30
update_env (
"ROCP_TOOL_LIBRARIES" ,
f " { ROCPROF_TOOL_LIBRARY } " ,
append = True ,
)
update_env (
"LD_LIBRARY_PATH" ,
f " { ROCM_DIR } /lib" ,
append = True ,
)
_output_file = args . output_file
_output_path = (
args . output_directory if args . output_directory is not None else os . getcwd ()
)
update_env ( "ROCPROF_OUTPUT_FILE_NAME" , _output_file )
update_env ( "ROCPROF_OUTPUT_PATH" , _output_path )
2024-07-26 21:46:53 -05:00
if app_pass is not None :
app_env [ "ROCPROF_OUTPUT_PATH" ] = os . path . join (
f " { _output_path } " , f " { args . sub_directory }{ app_pass } "
)
2024-05-29 15:35:10 +05:30
if args . output_file is not None or args . output_directory is not None :
update_env ( "ROCPROF_OUTPUT_LIST_METRICS_FILE" , True )
2024-07-26 21:46:53 -05:00
if not args . output_format :
args . output_format = [ "csv" ]
2024-05-29 15:35:10 +05:30
update_env (
"ROCPROF_OUTPUT_FORMAT" , "," . join ( args . output_format ), append = True , join_char = ","
)
2024-09-12 00:46:07 -05:00
if args . kokkos_trace :
update_env ( "KOKKOS_TOOLS_LIBS" , ROCPROF_KOKKOSP_LIBRARY , append = True )
for itr in (
"marker_trace" ,
"kernel_rename" ,
):
setattr ( args , itr , True )
2024-05-29 15:35:10 +05:30
if args . sys_trace :
for itr in (
"hip_trace" ,
"hsa_trace" ,
"marker_trace" ,
"kernel_trace" ,
"memory_copy_trace" ,
"scratch_memory_trace" ,
2024-09-11 22:42:58 -07:00
"rccl_trace" ,
2024-05-29 15:35:10 +05:30
):
setattr ( args , itr , True )
2024-09-09 11:20:55 -05:00
if args . runtime_trace :
for itr in (
"hip_runtime_trace" ,
"marker_trace" ,
"kernel_trace" ,
"memory_copy_trace" ,
"scratch_memory_trace" ,
2024-09-11 22:42:58 -07:00
"rccl_trace" ,
2024-09-09 11:20:55 -05:00
):
setattr ( args , itr , True )
2024-05-29 15:35:10 +05:30
if args . hip_trace :
for itr in ( "compiler" , "runtime" ):
setattr ( args , f "hip_ { itr } _trace" , True )
if args . hsa_trace :
for itr in ( "core" , "amd" , "image" , "finalizer" ):
setattr ( args , f "hsa_ { itr } _trace" , True )
trace_count = 0
trace_opts = [ "--hip-trace" , "--hsa-trace" ]
for opt , env_val in dict (
[
[ "hip_compiler_trace" , "HIP_COMPILER_API_TRACE" ],
[ "hip_runtime_trace" , "HIP_RUNTIME_API_TRACE" ],
[ "hsa_core_trace" , "HSA_CORE_API_TRACE" ],
[ "hsa_amd_trace" , "HSA_AMD_EXT_API_TRACE" ],
[ "hsa_image_trace" , "HSA_IMAGE_EXT_API_TRACE" ],
[ "hsa_finalizer_trace" , "HSA_FINALIZER_EXT_API_TRACE" ],
[ "marker_trace" , "MARKER_API_TRACE" ],
2024-09-11 22:42:58 -07:00
[ "rccl_trace" , "RCCL_API_TRACE" ],
2024-05-29 15:35:10 +05:30
[ "kernel_trace" , "KERNEL_TRACE" ],
[ "memory_copy_trace" , "MEMORY_COPY_TRACE" ],
[ "scratch_memory_trace" , "SCRATCH_MEMORY_TRACE" ],
]
) . items ():
val = getattr ( args , f " { opt } " )
update_env ( f "ROCPROF_ { env_val } " , val , overwrite_if_true = True )
trace_count += 1 if val else 0
trace_opts += [ "-- {} " . format ( opt . replace ( "_" , "-" ))]
2024-09-09 11:20:55 -05:00
# if marker tracing was requested, LD_PRELOAD the rocprofiler-sdk-roctx library
# to override the roctx symbols of an app linked to the old roctracer roctx
2024-09-11 15:27:35 -05:00
if args . marker_trace and not args . suppress_marker_preload :
update_env ( "LD_PRELOAD" , ROCPROF_ROCTX_LIBRARY , append = True )
2024-09-09 11:20:55 -05:00
if trace_count == 0 :
# if no tracing was enabled but the options below were enabled, raise an error
for oitr in [
"stats" ,
"summary" ,
"summary-per-domain" ,
"summary-groups" ,
"summary-output-file" ,
"summary-units" ,
]:
_attr = oitr . replace ( "-" , "_" )
if not hasattr ( args , _attr ):
fatal_error (
f "Internal error. parser does not support -- { oitr } argument (i.e. args. { _attr } )"
)
elif getattr ( args , _attr ):
_len = max ([ len ( f " { key } " ) for key in args . keys ()])
_args = " \n\t " . join (
sorted ([ f " { key : < { _len }} = { val } " for key , val in args . items ()])
)
fatal_error (
"No tracing options were enabled for -- {} option. \n Configuration argument values: \n\t {} \n Tracing options: \n\t {} " . format (
oitr , f " { _args } " , " \n\t " . join ( trace_opts )
)
)
_summary_groups = "##@@##" . join ( args . summary_groups ) if args . summary_groups else None
_summary_output_fname = args . summary_output_file
if _summary_output_fname is None :
_summary_output_fname = "stderr"
elif _summary_output_fname . lower () in ( "stdout" , "stderr" ):
_summary_output_fname = _summary_output_fname . lower ()
2024-05-29 15:35:10 +05:30
update_env ( "ROCPROF_STATS" , args . stats , overwrite_if_true = True )
2024-09-09 11:20:55 -05:00
update_env ( "ROCPROF_STATS_SUMMARY" , args . summary , overwrite_if_true = True )
update_env ( "ROCPROF_STATS_SUMMARY_UNITS" , args . summary_units , overwrite = True )
update_env ( "ROCPROF_STATS_SUMMARY_OUTPUT" , _summary_output_fname , overwrite = True )
update_env ( "ROCPROF_STATS_SUMMARY_GROUPS" , _summary_groups , overwrite = True )
update_env (
"ROCPROF_STATS_SUMMARY_PER_DOMAIN" ,
args . summary_per_domain ,
overwrite_if_true = True ,
)
2024-05-29 15:35:10 +05:30
update_env (
2024-07-26 21:46:53 -05:00
"ROCPROF_DEMANGLE_KERNELS" ,
not args . mangled_kernels ,
overwrite_if_false = True ,
2024-05-29 15:35:10 +05:30
)
update_env (
"ROCPROF_TRUNCATE_KERNELS" ,
args . truncate_kernels ,
overwrite_if_true = True ,
)
update_env (
"ROCPROF_LIST_METRICS" ,
args . list_metrics ,
overwrite_if_true = True ,
)
2024-07-26 21:46:53 -05:00
if args . log_level and args . log_level not in ( "env" ):
for itr in ( "ROCPROF" , "ROCPROFILER" , "ROCTX" ):
update_env (
f " { itr } _LOG_LEVEL" ,
args . log_level ,
)
2024-05-29 15:35:10 +05:30
2024-07-29 14:33:50 -05:00
for opt , env_val in dict (
[
[ "kernel_rename" , "KERNEL_RENAME" ],
]
) . items ():
val = getattr ( args , f " { opt } " )
if val is not None :
update_env ( f "ROCPROF_ { env_val } " , val , overwrite_if_true = True )
for opt , env_val in dict (
[
[ "perfetto_buffer_size" , "PERFETTO_BUFFER_SIZE_KB" ],
[ "perfetto_shmem_size_hint" , "PERFETTO_SHMEM_SIZE_HINT_KB" ],
[ "perfetto_fill_policy" , "PERFETTO_BUFFER_FILL_POLICY" ],
[ "perfetto_backend" , "PERFETTO_BACKEND" ],
]
) . items ():
val = getattr ( args , f " { opt } " )
if val is not None :
if isinstance ( val , ( list , tuple , set )):
val = ", " . join ( val )
update_env ( f "ROCPROF_ { env_val } " , val , overwrite = True )
2024-05-29 15:35:10 +05:30
def log_config ( _env ):
existing_env = dict ( os . environ )
2024-07-26 21:46:53 -05:00
init_message = " \n - rocprofv3 configuration {} : \n " . format (
"" if app_pass is None else f " (pass { app_pass } )"
)
2024-05-29 15:35:10 +05:30
for key , itr in _env . items ():
if key not in existing_env . keys ():
if init_message :
sys . stderr . write ( init_message )
init_message = None
sys . stderr . write ( f " \t - { key } = { itr } \n " )
2024-07-26 21:46:53 -05:00
if init_message is None :
sys . stderr . write ( " \n " )
2024-05-29 15:35:10 +05:30
sys . stderr . flush ()
if args . list_metrics :
app_args = [ f " { ROCM_DIR } /lib/rocprofiler-sdk/rocprofv3-trigger-list-metrics" ]
2024-07-26 21:46:53 -05:00
2024-05-29 15:35:10 +05:30
elif not app_args :
log_config ( app_env )
fatal_error ( "No application provided" )
2024-07-26 21:46:53 -05:00
if args . kernel_include_regex :
update_env (
"ROCPROF_KERNEL_FILTER_INCLUDE_REGEX" ,
args . kernel_include_regex ,
)
2024-05-29 15:35:10 +05:30
2024-07-26 21:46:53 -05:00
if args . kernel_exclude_regex :
update_env (
"ROCPROF_KERNEL_FILTER_EXCLUDE_REGEX" ,
args . kernel_exclude_regex ,
)
2024-05-29 15:35:10 +05:30
2024-07-26 21:46:53 -05:00
if args . kernel_iteration_range :
update_env ( "ROCPROF_KERNEL_FILTER_RANGE" , ", " . join ( args . kernel_iteration_range ))
2024-05-29 15:35:10 +05:30
2024-07-26 21:46:53 -05:00
if args . pmc :
update_env ( "ROCPROF_COUNTER_COLLECTION" , True , overwrite = True )
update_env (
"ROCPROF_COUNTERS" , "pmc: {} " . format ( " " . join ( args . pmc )), overwrite = True
)
else :
update_env ( "ROCPROF_COUNTER_COLLECTION" , False , overwrite = True )
2024-05-29 15:35:10 +05:30
2024-07-26 21:46:53 -05:00
if args . log_level in ( "info" , "trace" , "env" ):
log_config ( app_env )
2024-05-29 15:35:10 +05:30
2024-07-26 21:46:53 -05:00
if use_execv :
2024-05-29 15:35:10 +05:30
# does not return
os . execvpe ( app_args [ 0 ], app_args , env = app_env )
2024-07-26 21:46:53 -05:00
else :
try :
exit_code = subprocess . check_call ( app_args , env = app_env )
if exit_code != 0 :
fatal_error ( "Application exited with non-zero exit code" , exit_code )
except Exception as e :
fatal_error ( f " { e } \n " )
return exit_code
def main ( argv = None ):
cmd_args , app_args = parse_arguments ( argv )
inp_args = (
parse_input ( cmd_args . input ) if getattr ( cmd_args , "input" ) else [ dotdict ({})]
)
if len ( inp_args ) == 1 :
args = get_args ( cmd_args , inp_args [ 0 ])
pass_idx = None
if hasattr ( args , "pmc" ) and args . pmc is not None and len ( args . pmc ) > 0 :
pass_idx = 1
run ( app_args , args , pass_id = pass_idx )
else :
for idx , itr in enumerate ( inp_args ):
args = get_args ( cmd_args , itr )
run (
app_args ,
args ,
pass_id = ( idx + 1 ),
use_execv = False ,
)
2024-05-29 15:35:10 +05:30
if __name__ == "__main__" :
ec = main ( sys . argv [ 1 :])
sys . exit ( ec )