Files
rocm-systems/bin/tblextr.py
T
Ammar ELWazir fd4767d954 SWDEV-329261: Fix for Post-Processing HSA Memcopy Async Activities
The Post-Processing script was depending HSA API call for async mem copies to correlate it with the HSA Async Memcpy Activity, now if user decided to include input file with filtering HSA Api calls without adding HSA Memcpy, then all the correlation data will be dropped and the Async activity will be reported with the information given from the HSA async activity result file

Change-Id: I5123a5acab9b35a4c25793e7953fdfb74929c999
2022-03-24 10:22:52 -04:00

893 строки
32 KiB
Python
Исполняемый файл

################################################################################
# Copyright (c) 2018 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.
################################################################################
import os, sys, re, subprocess
from sqlitedb import SQLiteDB
from mem_manager import MemManager
import dform
mcopy_data_enabled = 1 if 'ROCP_MCOPY_DATA' in os.environ else 0
EXT_PID = 0
COPY_PID = 1
HIP_PID = 2
HSA_PID = 3
OPS_PID = 5
GPU_BASE_PID = 6
NONE_PID = -1
max_gpu_id = -1
START_NS = 0
hsa_activity_found = 0
# dependencies dictionary
dep_dict = {}
kern_dep_list = []
last_hip_api_map = {}
hip_streams = []
from_ids = {}
# stream ID map
stream_counter = 0
stream_id_map = {}
def get_stream_index(stream_id):
global stream_counter
stream_ind = 0
if stream_id.lower() != 'nil':
if not stream_id in stream_id_map:
stream_counter += 1
stream_ind = stream_counter
stream_id_map[stream_id] = stream_ind
else:
stream_ind = stream_id_map[stream_id]
return stream_ind
# patching activity records
def activity_record_patching(db, ops_table_name, kernel_found, kernel_name, stream_found, stream_ind, select_expr):
if kernel_found != 0:
db.change_rec_fld(ops_table_name, 'Name = "' + kernel_name + '"', select_expr)
if stream_found != 0:
db.change_rec_fld(ops_table_name, 'tid = ' + str(stream_ind), select_expr)
# global vars
table_descr = [
['Index', 'KernelName'],
{'Index': 'INTEGER', 'KernelName': 'TEXT'}
]
var_list = table_descr[0]
var_table = {}
#############################################################
def fatal(msg):
sys.stderr.write(sys.argv[0] + ": " + msg + "\n");
sys.exit(1)
dbglog_count = 0
def dbglog(msg):
global dbglog_count
dbglog_count += 1
sys.stderr.write(sys.argv[0] + ": " + msg + "\n");
fatal("error")
#############################################################
# Dumping sysinfo
sysinfo_begin = 1
def metadata_gen(sysinfo_file, sysinfo_cmd):
global sysinfo_begin
if not re.search(r'\.txt$', sysinfo_file):
raise Exception('wrong output file type: "' + sysinfo_file + '"' )
if sysinfo_begin == 1:
sysinfo_begin = 0
with open(sysinfo_file, mode='w') as fd: fd.write('')
with open(sysinfo_file, mode='a') as fd: fd.write('CMD: ' + sysinfo_cmd + '\n')
status = subprocess.call(sysinfo_cmd + ' >> ' + sysinfo_file,
stderr=subprocess.STDOUT,
shell=True)
if status != 0:
raise Exception('Could not run command: "' + sysinfo_cmd + '"')
# parse results method
def parse_res(infile):
global max_gpu_id
if not os.path.isfile(infile): return
inp = open(infile, 'r')
beg_pattern = re.compile("^dispatch\[(\d*)\], (.*) kernel-name\(\"([^\"]*)\"\)")
prop_pattern = re.compile("([\w-]+)\((\w+)\)");
ts_pattern = re.compile(", time\((\d*),(\d*),(\d*),(\d*)\)")
# var pattern below matches a variable name and a variable value from a one
# line text in the format of for example "WRITE_SIZE (0.2500000000)" or
# "GRBM_GUI_ACTIVE (27867)" or "TA_TA_BUSY[0]"
var_pattern = re.compile("^\s*([a-zA-Z0-9_]+(?:\[\d+\])?)\s+\((\d+(?:\.\d+)?)\)")
pid_pattern = re.compile("pid\((\d*)\)")
dispatch_number = 0
disp_pid = -1
for line in inp.readlines():
record = line[:-1]
m = pid_pattern.search(record)
if m: disp_pid = int(m.group(1))
m = var_pattern.match(record)
if m:
if not (disp_pid, dispatch_number) in var_table: fatal("Error: dispatch number not found '" + str(dispatch_number) + "'")
var = m.group(1)
val = m.group(2)
var_table[(disp_pid, dispatch_number)][var] = val
if not var in var_list: var_list.append(var)
m = beg_pattern.match(record)
if m:
dispatch_number = m.group(1)
if not (disp_pid, dispatch_number) in var_table:
var_table[(disp_pid, dispatch_number)] = {
'Index': dispatch_number,
'KernelName': "\"" + m.group(3) + "\""
}
gpu_id = 0
queue_id = 0
disp_tid = 0
kernel_properties = m.group(2)
for prop in kernel_properties.split(', '):
m = prop_pattern.match(prop)
if m:
var = m.group(1)
val = m.group(2)
var_table[(disp_pid, dispatch_number)][var] = val
if not var in var_list: var_list.append(var);
if var == 'gpu-id':
gpu_id = int(val)
if (gpu_id > max_gpu_id): max_gpu_id = gpu_id
if var == 'queue-id': queue_id = int(val)
if var == 'pid': disp_pid = int(val)
if var == 'tid': disp_tid = int(val)
else: fatal('wrong kernel property "' + prop + '" in "'+ kernel_properties + '"')
m = ts_pattern.search(record)
if m:
var_table[(disp_pid, dispatch_number)]['DispatchNs'] = m.group(1)
var_table[(disp_pid, dispatch_number)]['BeginNs'] = m.group(2)
var_table[(disp_pid, dispatch_number)]['EndNs'] = m.group(3)
var_table[(disp_pid, dispatch_number)]['CompleteNs'] = m.group(4)
## filling dependenciws
from_ns = int(m.group(1))
to_ns = int(m.group(2))
from_us = int((from_ns - START_NS) / 1000)
to_us = int((to_ns - START_NS) / 1000)
kern_dep_list.append((from_ns, disp_pid, disp_tid))
gpu_pid = GPU_BASE_PID + int(gpu_id)
if not disp_pid in dep_dict: dep_dict[disp_pid] = {}
dep_proc = dep_dict[disp_pid]
if not gpu_pid in dep_proc: dep_proc[gpu_pid] = { 'pid': HSA_PID, 'from': [], 'to': {}, 'id': [] }
dep_str = dep_proc[gpu_pid]
to_id = len(dep_str['from'])
dep_str['from'].append((from_us, disp_tid, disp_tid))
dep_str['to'][to_id] = to_us
##
inp.close()
#############################################################
# Comparator to sort a dictionary of tuples. This comparator will convert
# the second element of tuple to an int and return the new tuple. Then
# the dictionary can use the default comparison i.e sort by first element,
# then sort by second element.
def tuple_comparator(tupleElem) :
return tupleElem[0], int(tupleElem[1])
# merge results table
def merge_table():
global var_list
keys = sorted(var_table.keys(), key=tuple_comparator)
fields = set(var_table[keys[0]])
if 'DispatchNs' in fields:
var_list.append('DispatchNs')
var_list.append('BeginNs')
var_list.append('EndNs')
var_list.append('CompleteNs')
var_list = [x for x in var_list if x in fields]
#############################################################
# dump CSV results
def dump_csv(file_name):
global var_list
keys = sorted(var_table.keys(), key=tuple_comparator)
with open(file_name, mode='w') as fd:
fd.write(','.join(var_list) + '\n');
for pid, ind in keys:
entry = var_table[(pid, ind)]
dispatch_number = entry['Index']
if ind != dispatch_number: fatal("Dispatch #" + ind + " index mismatch (" + dispatch_number + ")\n")
val_list = [entry[var] for var in var_list]
fd.write(','.join(val_list) + '\n');
print("File '" + file_name + "' is generating")
#############################################################
# fill kernels DB
def fill_kernel_db(table_name, db):
global var_list
keys = sorted(var_table.keys(), key=tuple_comparator)
for var in set(var_list).difference(set(table_descr[1])):
table_descr[1][var] = 'INTEGER'
table_descr[0] = var_list;
table_handle = db.add_table(table_name, table_descr)
for pid, ind in keys:
entry = var_table[(pid, ind)]
dispatch_number = entry['Index']
if ind != dispatch_number: fatal("Dispatch #" + ind + " index mismatch (" + dispatch_number + ")\n")
val_list = [entry[var] for var in var_list]
db.insert_entry(table_handle, val_list)
#############################################################
# Fill Ext DB
ext_table_descr = [
['BeginNs', 'EndNs', 'pid', 'tid', 'Name', 'Index', '__section', '__lane'],
{'BeginNs':'INTEGER', 'EndNs':'INTEGER', 'pid':'INTEGER', 'tid':'INTEGER', 'Name':'TEXT', 'Index':'INTEGER', '__section':'INTEGER', '__lane':'INTEGER'}
]
def fill_ext_db(table_name, db, indir, trace_name, api_pid):
file_name = indir + '/' + trace_name + '_trace.txt'
# tms pid:tid cid:rid:'.....'
ptrn_val = re.compile(r'(\d+) (\d+):(\d+) (\d+):(\d+):(.*)$')
if not os.path.isfile(file_name): return 0
range_stack = {}
range_map = {}
record_id = 0
table_handle = db.add_table(table_name, ext_table_descr)
with open(file_name, mode='r') as fd:
for line in fd.readlines():
record = line[:-1]
m = ptrn_val.match(record)
if m:
tms = int(m.group(1))
pid = m.group(2)
tid = m.group(3)
cid = int(m.group(4))
rid = int(m.group(5))
msg = m.group(6)
rec_vals = []
if cid != 2:
rec_vals.append(tms)
rec_vals.append(tms + 1)
rec_vals.append(pid)
rec_vals.append(tid)
rec_vals.append(msg)
rec_vals.append(record_id)
rec_vals.append(api_pid) # __section
rec_vals.append(tid) # __lane
if cid == 1:
if not pid in range_stack: range_stack[pid] = {}
pid_stack = range_stack[pid]
if not tid in pid_stack: pid_stack[tid] = []
rec_stack = pid_stack[tid]
rec_stack.append(rec_vals)
continue
if cid == 2:
if not pid in range_stack: fatal("ROCTX range begin not found, pid(" + pid + ")");
pid_stack = range_stack[pid]
if not tid in pid_stack: fatal("ROCTX range begin not found, tid(" + tid + ")");
rec_stack = pid_stack[tid]
rec_vals = rec_stack.pop()
rec_vals[1] = tms
# range start
if cid == 3:
range_map[rid] = (tms, msg)
continue
# range stop
if cid == 4:
if rid in range_map:
(tms, msg) = range_map[rid] # querying start timestamp if rid exists
del range_map[rid]
else: fatal("range id(" + str(rid) + ") is not found")
rec_vals[0] = tms # begin timestamp
rec_vals[4] = msg # range message
rec_vals[7] = 0 # 0 lane for ranges
db.insert_entry(table_handle, rec_vals)
record_id += 1
return 1
#############################################################
# arguments manipulation routines
def get_field(args, field):
ptrn1_field = re.compile(r'^.* ' + field + '\(');
ptrn2_field = re.compile(r'\) .*$');
ptrn3_field = re.compile(r'\)\)$');
(field_name, n) = ptrn1_field.subn('', args, count=1);
if n != 0:
(field_name, n) = ptrn2_field.subn('', field_name, count=1)
if n == 0:
(field_name, n) = ptrn3_field.subn('', field_name, count=1)
return (field_name, n)
def set_field(args, field, val):
return re.subn(field + '\(\w+\)([ \)])', field + '(' + str(val) + ')\\1', args, count=1)
hsa_patch_data = {}
ops_patch_data = {}
# Fill API DB
api_table_descr = [
['BeginNs', 'EndNs', 'pid', 'tid', 'Name', 'args', 'Index', 'Data', '__section', '__lane'],
{'BeginNs':'INTEGER', 'EndNs':'INTEGER', 'pid':'INTEGER', 'tid':'INTEGER', 'Name':'TEXT', 'args':'TEXT', 'Index':'INTEGER', 'Data':'TEXT', '__section':'INTEGER', '__lane':'INTEGER'}
]
# Filling API records DB table
# table_name - created DB table name
# db - DB handle
# indir - input directory
# api_name - traced API name
# api_pid - assigned JSON PID
# dep_pid - PID of dependet domain
# dep_list - list of dependet dospatch events
# dep_filtr - registered dependencies by record ID
def fill_api_db(table_name, db, indir, api_name, api_pid, dep_pid, dep_list, dep_filtr, expl_id):
global hsa_activity_found
global memory_manager
copy_csv = ''
copy_index = 0
ptrn_val = re.compile(r'(\d+):(\d+) (\d+):(\d+) ([^\(]+)(\(.*)$')
hip_mcopy_ptrn = re.compile(r'hipMemcpy|hipMemset')
hip_wait_event_ptrn = re.compile(r'WaitEvent')
hip_sync_event_ptrn = re.compile(r'hipStreamSynchronize')
hip_sync_dev_event_ptrn = re.compile(r'hipDeviceSynchronize')
wait_event_ptrn = re.compile(r'WaitEvent|hipStreamSynchronize|hipDeviceSynchronize')
hip_stream_wait_write_ptrn = re.compile(r'hipStreamWaitValue64|hipStreamWriteValue64|hipStreamWaitValue32|hipStreamWriteValue32')
prop_pattern = re.compile("([\w-]+)\((\w+)\)");
beg_pattern = re.compile("^dispatch\[(\d*)\], (.*) kernel-name\(\"([^\"]*)\"\)")
hip_strm_cr_event_ptrn = re.compile(r'hipStreamCreate')
hsa_mcopy_ptrn = re.compile(r'hsa_amd_memory_async_copy')
ptrn_fixformat = re.compile(r'(\d+:\d+ \d+:\d+ \w+)\(\s*(.*)\)$')
ptrn_fixkernel = re.compile(r'\s+kernel=(.*)$')
ptrn_multi_kernel = re.compile(r'(.*):(\d+)$')
ptrn_corr_id = re.compile(r'\ :(\d*)$')
file_name = indir + '/' + api_name + '_api_trace.txt'
if not os.path.isfile(file_name): return 0
hsa_copy_file_name = indir + '/' + 'async_copy_trace.txt'
hsa_copy_file_name_present = 1 if os.path.isfile(file_name) else 0
hsa_copy_deps = 1 if (api_pid == HSA_PID and hsa_copy_file_name_present == 1) else 0
print("hsa_copy_deps: " + str(hsa_copy_deps))
# parsing an input trace file and creating a DB table
record_id_dict = {}
table_handle = db.add_table(table_name, api_table_descr)
with open(file_name, mode='r') as fd:
file_lines = fd.readlines()
total_lines = len(file_lines)
line_index = 0
for line in file_lines:
if (line_index == total_lines - 1) or (line_index % 100 == 0):
sys.stdout.write( \
"\rscan " + api_name + " API data " + str(line_index) + ":" + str(total_lines) + " "*100 \
)
line_index += 1
record = line[:-1]
corr_id = 0
m = ptrn_corr_id.search(record)
if m:
corr_id = int(m.group(1))
record = ptrn_corr_id.sub('', record)
kernel_arg = ''
m = ptrn_fixkernel.search(record)
if m:
kernel_arg = 'kernel(' + m.group(1) + ') '
record = ptrn_fixkernel.sub('', record)
mfixformat = ptrn_fixformat.match(record)
if mfixformat: #replace '=' in args with parentheses
reformated_args = kernel_arg + mfixformat.group(2).replace('=','(').replace(',',')')+')'
record = mfixformat.group(1) + '( ' + reformated_args + ')'
m = ptrn_val.match(record)
if not m: fatal(api_name + " bad record: '" + record + "'")
else:
rec_vals = []
rec_len = len(api_table_descr[0]) - 3
for ind in range(1, rec_len):
rec_vals.append(m.group(ind))
proc_id = int(rec_vals[2])
thread_id = int(rec_vals[3])
record_name = rec_vals[4]
record_args = rec_vals[5]
# incrementing per-process record id/correlation id
if not proc_id in record_id_dict: record_id_dict[proc_id] = 0
record_id_dict[proc_id] += 1
record_id = record_id_dict[proc_id]
# setting correlationid to record id if correlation id is not defined
if corr_id == 0: corr_id = record_id
rec_vals.append(corr_id)
# extracting/converting stream id
(stream_id, stream_found) = get_field(record_args, 'stream')
if stream_found == 0:
stream_id = 0
else:
stream_id = get_stream_index(stream_id)
(rec_vals[5], found) = set_field(record_args, 'stream', stream_id)
if found == 0: fatal('set_field() failed for "stream", args: "' + record_args + '"')
if hip_strm_cr_event_ptrn.match(record_name):
hip_streams.append(stream_id)
if hip_sync_event_ptrn.match(record_name):
if (proc_id,stream_id) in last_hip_api_map:
(last_hip_api_corr_id, last_hip_api_from_pid) = last_hip_api_map[(proc_id,stream_id)][-1]
sync_api_beg_us = int((int(rec_vals[0]) - START_NS) / 1000)
if HIP_PID not in dep_dict[proc_id]:
dep_dict[proc_id][HIP_PID] = { 'pid': last_hip_api_from_pid, 'from': [], 'to': {}, 'id': [] }
dep_dict[proc_id][HIP_PID]['from'].append((-1, stream_id, thread_id))
dep_dict[proc_id][HIP_PID]['id'].append(last_hip_api_corr_id)
dep_dict[proc_id][HIP_PID]['to'][last_hip_api_corr_id] = sync_api_beg_us
from_ids[(last_hip_api_corr_id, proc_id)] = len(dep_dict[proc_id][HIP_PID]['from']) - 1
m = beg_pattern.match(record)
gpu_id = 0
if m:
kernel_properties = m.group(2)
for prop in kernel_properties.split(', '):
m = prop_pattern.match(prop)
if m:
val = m.group(2)
var = m.group(1)
if var == 'gpu-id':
gpu_id = int(val)
if hsa_mcopy_ptrn.match(record_name) or hip_mcopy_ptrn.match(record_name):
ops_section_id = COPY_PID
else:
ops_section_id = GPU_BASE_PID + int(gpu_id)
if (proc_id,stream_id) not in last_hip_api_map:
last_hip_api_map[(proc_id,stream_id)] = []
last_hip_api_map[(proc_id, stream_id)].append((corr_id, ops_section_id))
# asyncronous opeartion API found
op_found = 0
mcopy_found = 0
# extract kernel name string
(kernel_str, kernel_found) = get_field(record_args, 'kernel')
if kernel_found == 0: kernel_str = ''
else: op_found = 1
if hip_mcopy_ptrn.match(record_name):
mcopy_found = 1
op_found = 1
# HIP WaitEvent API
if wait_event_ptrn.search(record_name):
op_found = 1
if hip_stream_wait_write_ptrn.search(record_name):
op_found = 1
# HSA memcopy API
if hsa_mcopy_ptrn.match(record_name):
mcopy_found = 1
op_found = 1
stream_id = thread_id
hsa_patch_data[(copy_index, proc_id)] = thread_id
copy_index += 1
if op_found:
ops_patch_data[(corr_id, proc_id)] = (thread_id, stream_id, kernel_str)
if op_found:
op_found = 0
beg_ns = int(rec_vals[0])
end_ns = int(rec_vals[1])
dur_us = int((end_ns - beg_ns) / 1000)
from_us = int((beg_ns - START_NS) / 1000) + dur_us
if api_pid == HIP_PID or hsa_copy_deps == 1:
if not proc_id in dep_dict: dep_dict[proc_id] = {}
dep_proc = dep_dict[proc_id]
if not dep_pid in dep_proc:
if api_pid == 'HIP_PID': dep_proc[dep_pid] = { 'pid': api_pid, 'from': [], 'id': [] }
else: dep_proc[dep_pid] = { 'pid': api_pid, 'from': [], 'id': [], 'to': {} }
dep_str = dep_proc[dep_pid]
dep_str['from'].append((from_us, stream_id, thread_id))
if expl_id: dep_str['id'].append(corr_id)
# memcopy registering
api_data = memory_manager.register_api(rec_vals) if mcopy_data_enabled else ''
rec_vals.append(api_data)
# setting section and lane
rec_vals.append(api_pid) # __section
rec_vals.append(thread_id) # __lane
# inserting an API record to DB
db.insert_entry(table_handle, rec_vals)
# inserting of dispatch events correlated to the dependent dispatches
for (from_ns, proc_id, thread_id) in dep_list:
if not proc_id in record_id_dict: record_id_dict[proc_id] = 0
record_id_dict[proc_id] += 1
corr_id = record_id_dict[proc_id]
db.insert_entry(table_handle, [from_ns, from_ns, proc_id, thread_id, 'hsa_dispatch', '', corr_id, '', api_pid, thread_id])
# generating memcopy CSV
if copy_csv != '':
file_name = os.environ['PWD'] + '/results_mcopy.csv'
with open(file_name, mode='w') as fd:
print("File '" + file_name + "' is generating")
fd.write(copy_csv)
return 1
#############################################################
# fill COPY DB
copy_table_descr = [
['BeginNs', 'EndNs', 'Name', 'pid', 'tid', 'Index', 'Data', '__section', '__lane'],
{'Index':'INTEGER', 'Name':'TEXT', 'args':'TEXT', 'BeginNs':'INTEGER', 'EndNs':'INTEGER', 'pid':'INTEGER', 'tid':'INTEGER', 'Data':'TEXT', '__section':'INTEGER', '__lane':'INTEGER'}
]
def fill_copy_db(table_name, db, indir):
sect_id = COPY_PID
file_name = indir + '/' + 'async_copy_trace.txt'
ptrn_val = re.compile(r'^(\d+):(\d+) (async-copy):(\d+):(\d+)$')
if not os.path.isfile(file_name): return 0
table_handle = db.add_table(table_name, copy_table_descr)
with open(file_name, mode='r') as fd:
for line in fd.readlines():
record = line[:-1]
m = ptrn_val.match(record)
if not m: fatal("bad async-copy entry '" + record + "'")
else:
rec_vals = []
for ind in range(1,4): rec_vals.append(m.group(ind))
corr_id = int(m.group(4))
proc_id = int(m.group(5))
# querying tid value
if (corr_id, proc_id) in hsa_patch_data:
thread_id = hsa_patch_data[(corr_id, proc_id)]
else:
thread_id = -1
# completing record
rec_vals.append(proc_id) # tid
rec_vals.append(thread_id) # tid
rec_vals.append(corr_id) # Index
# registering memcopy information
activity_data = memory_manager.register_copy(rec_vals) if mcopy_data_enabled else ''
rec_vals.append(activity_data)
# appending straem ID and section ID
rec_vals.append(COPY_PID) # __section
rec_vals.append(thread_id) # __lane
# inserting DB activity entry
db.insert_entry(table_handle, rec_vals)
# filling dependencies
to_ns = int(rec_vals[0])
to_us = int((to_ns - START_NS) / 1000)
if thread_id != -1:
#if not proc_id in dep_dict: dep_dict[proc_id] = {}
dep_proc = dep_dict[proc_id]
#if not pid in dep_proc: dep_proc[pid] = { 'pid': HSA_PID, 'from': [], 'to': {}, 'id': [] }
dep_str = dep_proc[sect_id]
dep_str['to'][corr_id] = to_us
return 1
#############################################################
# fill HCC ops DB
ops_table_descr = [
['BeginNs', 'EndNs', 'dev-id', 'queue-id', 'Name', 'pid', 'tid', 'stream-id', 'Index', 'Data', '__section', '__lane'],
{'Index':'INTEGER', 'Name':'TEXT', 'args':'TEXT', 'BeginNs':'INTEGER', 'EndNs':'INTEGER', 'dev-id':'INTEGER', 'queue-id':'INTEGER', 'pid':'INTEGER', 'tid':'INTEGER', 'Data':'TEXT', 'stream-id':'INTEGER', '__section':'INTEGER', '__lane':'INTEGER'}
]
def fill_ops_db(kernel_table_name, mcopy_table_name, db, indir):
global max_gpu_id
file_name = indir + '/' + 'hcc_ops_trace.txt'
ptrn_val = re.compile(r'(\d+):(\d+) (\d+):(\d+) (.*)$')
ptrn_id = re.compile(r'^([^:]+):(\d+):(\d+)$')
ptrn_mcopy = re.compile(r'(Memcpy|Copy|Fill)')
ptrn_barrier = re.compile(r'Marker')
if not os.path.isfile(file_name): return {}
filtr = {}
kernel_table_handle = db.add_table(kernel_table_name, ops_table_descr)
mcopy_table_handle = db.add_table(mcopy_table_name, ops_table_descr)
with open(file_name, mode='r') as fd:
file_lines = fd.readlines()
total_lines = len(file_lines)
line_index = 0
for line in file_lines:
if (line_index == total_lines - 1) or (line_index % 100 == 0):
sys.stdout.write( \
"\rscan ops data " + str(line_index) + ":" + str(total_lines) + " "*100 \
)
line_index += 1
record = line[:-1]
m = ptrn_val.match(record)
if m:
# parsing trace record
rec_vals = []
for ind in range(1,6): rec_vals.append(m.group(ind))
label = rec_vals[4] # record name
m = ptrn_id.match(label)
if not m: fatal("bad hcc ops entry '" + record + "'")
name = m.group(1)
corr_id = int(m.group(2))
proc_id = int(m.group(3))
# checking name for memcopy pattern
is_barrier = 0
if ptrn_mcopy.search(name):
rec_table_name = mcopy_table_name
table_handle = mcopy_table_handle
sect_id = COPY_PID;
else:
rec_table_name = kernel_table_name
table_handle = kernel_table_handle
gpu_id = int(rec_vals[2]);
if (gpu_id > max_gpu_id): max_gpu_id = gpu_id
sect_id = GPU_BASE_PID + int(gpu_id)
if ptrn_barrier.search(name):
name = '"<barrier packet>"'
is_barrier = 1
thread_id = 0
stream_id = 0
if (corr_id, proc_id) in ops_patch_data:
(thread_id, stream_id, name_patch) = ops_patch_data[(corr_id, proc_id)]
if name_patch != '': name = name_patch
else:
if is_barrier: continue
else: fatal("hcc ops data not found: '" + record + "', " + str(corr_id) + ", " + str(proc_id))
# activity record
rec_vals[4] = name # Name
rec_vals.append(proc_id) # pid
rec_vals.append(thread_id) # tid
rec_vals.append(stream_id) # StreamId
rec_vals.append(corr_id) # Index
# registering memcopy information
activity_data = memory_manager.register_activity(rec_vals) if mcopy_data_enabled else ''
rec_vals.append(activity_data)
# activity record data for stream ID and sction ID
rec_vals.append(sect_id) # __section
rec_vals.append(stream_id) # __lane
# inserting DB activity entry
db.insert_entry(table_handle, rec_vals)
# registering a dependency filtr
filtr[(corr_id, proc_id)] = rec_table_name
# filling a dependencies
to_ns = int(rec_vals[0])
to_us = int((to_ns - START_NS) / 1000)
end_ns = int(rec_vals[1])
dur_us = int((end_ns - to_ns) / 1000)
if (corr_id, proc_id) in from_ids:
depid = from_ids[(corr_id, proc_id)]
from_val = dep_dict[proc_id][HIP_PID]['from'][depid]
print("from_val" + str(from_val))
from_val_new = (to_us + dur_us, from_val[1], from_val[2])
dep_dict[proc_id][HIP_PID]['from'][depid] = from_val_new
if not proc_id in dep_dict: dep_dict[proc_id] = {}
dep_proc = dep_dict[proc_id]
if not sect_id in dep_proc: dep_proc[sect_id] = { 'bsp': OPS_PID, 'to': {} }
dep_str = dep_proc[sect_id]
dep_str['to'][corr_id] = to_us
else:
fatal("hcc ops bad record: '" + record + "'")
return filtr
#############################################################
# main
if (len(sys.argv) < 2): fatal("Usage: " + sys.argv[0] + " <output CSV file> <input result files list>")
outfile = sys.argv[1]
infiles = sys.argv[2:]
indir = re.sub(r'\/[^\/]*$', r'', infiles[0])
inext = re.sub(r'\s+$', r'', infiles[0])
inext = re.sub(r'^.*(\.[^\.]+)$', r'\1', inext)
dbfile = ''
csvfile = ''
if 'ROCP_JSON_REBASE' in os.environ and os.environ['ROCP_JSON_REBASE'] == 0:
begin_ts_file = indir + '/begin_ts_file.txt'
if os.path.isfile(begin_ts_file):
with open(begin_ts_file, mode='r') as fd:
ind = 0
for line in fd.readlines():
val = int(line)
if ind == 0 or val < START_NS: START_NS = val
ind += 1
print('START timestamp found (' + str(START_NS) + 'ns)')
if re.search(r'\.csv$', outfile):
csvfile = outfile
elif re.search(r'\.db$', outfile):
dbfile = outfile
csvfile = re.sub(r'\.db$', '.csv', outfile)
else:
fatal("Bad output file '" + outfile + "'")
if inext == '.txt':
for f in infiles: parse_res(f)
if len(var_table) != 0: merge_table()
if dbfile == '':
dump_csv(csvfile)
else:
statfile = re.sub(r'\.csv$', '.stats.csv', csvfile)
jsonfile = re.sub(r'\.csv$', '.json', csvfile)
hsa_statfile = re.sub(r'\.stats\.csv$', r'.hsa_stats.csv', statfile)
hip_statfile = re.sub(r'\.stats\.csv$', r'.hip_stats.csv', statfile)
ops_statfile = statfile
copy_statfile = re.sub(r'\.stats\.csv$', r'.copy_stats.csv', statfile)
memcopy_info_file = re.sub(r'\.stats\.csv$', r'.memcopy_info.csv', statfile)
sysinfo_file = re.sub(r'\.stats\.csv$', r'.sysinfo.txt', statfile)
metadata_gen(sysinfo_file, 'rocminfo')
with open(dbfile, mode='w') as fd: fd.truncate()
db = SQLiteDB(dbfile)
memory_manager = MemManager(db, indir)
ext_trace_found = fill_ext_db('rocTX', db, indir, 'roctx', EXT_PID)
hsa_trace_found = fill_api_db('HSA', db, indir, 'hsa', HSA_PID, COPY_PID, kern_dep_list, {}, 0)
hsa_activity_found = fill_copy_db('COPY', db, indir)
hip_trace_found = fill_api_db('HIP', db, indir, 'hip', HIP_PID, OPS_PID, [], {}, 1)
ops_filtr = fill_ops_db('OPS', 'COPY', db, indir)
fill_kernel_db('KERN', db)
any_trace_found = ext_trace_found | hsa_trace_found | hip_trace_found
copy_trace_found = 0
if hsa_activity_found or len(ops_filtr): copy_trace_found = 1
if any_trace_found:
db.open_json(jsonfile)
if ext_trace_found:
db.label_json(EXT_PID, "Markers and Ranges", jsonfile)
if hip_trace_found:
db.label_json(HIP_PID, "CPU HIP API", jsonfile)
if hsa_trace_found:
db.label_json(HSA_PID, "CPU HSA API", jsonfile)
db.label_json(COPY_PID, "COPY", jsonfile)
if any_trace_found and max_gpu_id >= 0:
for ind in range(0, int(max_gpu_id) + 1):
db.label_json(int(ind) + int(GPU_BASE_PID), "GPU" + str(ind), jsonfile)
if ext_trace_found:
dform.gen_ext_json_trace(db, 'rocTX', START_NS, jsonfile)
if len(var_table) != 0:
dform.post_process_data(db, 'KERN', csvfile)
dform.gen_table_bins(db, 'KERN', statfile, 'KernelName', 'DurationNs')
if hsa_trace_found and 'BeginNs' in var_list:
dform.gen_kernel_json_trace(db, 'KERN', GPU_BASE_PID, START_NS, jsonfile)
if hsa_trace_found:
dform.post_process_data(db, 'HSA')
dform.gen_table_bins(db, 'HSA', hsa_statfile, 'Name', 'DurationNs')
dform.gen_api_json_trace(db, 'HSA', START_NS, jsonfile)
if copy_trace_found:
dform.post_process_data(db, 'COPY')
dform.gen_table_bins(db, 'COPY', copy_statfile, 'Name', 'DurationNs')
dform.gen_api_json_trace(db, 'COPY', START_NS, jsonfile)
if hip_trace_found:
dform.post_process_data(db, 'HIP')
dform.gen_table_bins(db, 'HIP', hip_statfile, 'Name', 'DurationNs')
dform.gen_api_json_trace(db, 'HIP', START_NS, jsonfile)
if ops_filtr:
dform.post_process_data(db, 'OPS')
dform.gen_table_bins(db, 'OPS', ops_statfile, 'Name', 'DurationNs')
dform.gen_ops_json_trace(db, 'OPS', GPU_BASE_PID, START_NS, jsonfile)
if any_trace_found:
dep_id = 0
for (proc_id, dep_proc) in dep_dict.items():
for (to_pid, dep_str) in dep_proc.items():
if 'bsp' in dep_str:
bspid = dep_str['bsp']
base_str = dep_proc[bspid]
for v in ('pid', 'from', 'id'):
dep_str[v] = base_str[v]
base_str['inv'] = 1
for (to_pid, dep_str) in dep_proc.items():
if 'inv' in dep_str: continue
if not 'to' in dep_str: continue
from_pid = dep_str['pid']
from_us_list = dep_str['from']
to_us_dict = dep_str['to']
corr_id_list = dep_str['id']
db.flow_json(dep_id, from_pid, from_us_list, to_pid, to_us_dict, corr_id_list, jsonfile)
dep_id += len(from_us_list)
if any_trace_found:
db.metadata_json(jsonfile, sysinfo_file)
db.close_json(jsonfile);
if mcopy_data_enabled:
memory_manager.dump_data('MM', memcopy_info_file)
db.close()
sys.exit(0)
#############################################################