diff --git a/bin/dform.py b/bin/dform.py index ff688f3ebc..7122a51c76 100644 --- a/bin/dform.py +++ b/bin/dform.py @@ -1,11 +1,11 @@ #!/usr/bin/python from sqlitedb import SQLiteDB -def post_process_data(db, table_name, outfile = ''): +def post_process_data(db, table_name, start_ns, outfile = ''): # db.add_data_column('A', 'DispDurNs', 'INTEGER', 'BeginNs - DispatchNs') # db.add_data_column('A', 'ComplDurNs', 'INTEGER', 'CompleteNs - EndNs') # db.add_data_column('A', 'TotalDurNs', 'INTEGER', 'CompleteNs - DispatchNs') -# db.add_data_column('A', 'TimeNs', 'INTEGER', 'BeginNs - (select BeginNs from A limit 1)') +# db.add_data_column(table_name, 'TimeNs', 'INTEGER', 'BeginNs - %d' % start_ns) db.add_data_column(table_name, 'DurationNs', 'INTEGER', 'EndNs - BeginNs') if outfile != '': db.dump_csv(table_name, outfile) @@ -19,13 +19,13 @@ def gen_table_bins(db, table, outfile, name_var, dur_ns_var): gen_data_bins(db, outfile) db.execute('DROP VIEW B') -def gen_api_json_trace(db, table, outfile): - db.execute('create view B as select Name as name, (BeginNs/1000) as ts, (DurationNs/1000) as dur from %s order by ts asc;' % table); +def gen_api_json_trace(db, table, start_ns, outfile): + db.execute('create view B as select "Index", Name as name, pid, tid, (BeginNs/1000 - %d/1000) as ts, (DurationNs/1000) as dur from %s order by ts asc;' % (start_ns, table)); db.dump_json('B', table, outfile) db.execute('DROP VIEW B') -def gen_kernel_json_trace(db, table, outfile): - db.execute('create view B as select (KernelName) as name, ("gpu-id") as pid, (0) as tid, (BeginNs/1000) as ts, (DurationNs/1000) as dur from %s order by ts asc;' % table); +def gen_kernel_json_trace(db, table, base_pid, start_ns, outfile): + db.execute('create view B as select "Index", KernelName as name, ("gpu-id" + %d) as pid, (0) as tid, (BeginNs/1000 - %d/1000) as ts, (DurationNs/1000) as dur from %s order by ts asc;' % (base_pid, start_ns, table)); db.dump_json('B', table, outfile) db.execute('DROP VIEW B') ############################################################################################## diff --git a/bin/sqlitedb.py b/bin/sqlitedb.py index 94e6d0c9af..f3fb69001c 100644 --- a/bin/sqlitedb.py +++ b/bin/sqlitedb.py @@ -71,6 +71,12 @@ class SQLiteDB: def _get_raws(self, table_name): cursor = self.connection.execute('SELECT * FROM ' + table_name) return cursor.fetchall() + def _get_raw_by_id(self, table_name, req_id): + cursor = self.connection.execute('SELECT * FROM ' + table_name + ' WHERE "Index"=?', (req_id,)) + raws = cursor.fetchall() + if len(raws) != 1: + raise Exception('Index is not unique, table "' + table_name + '"') + return list(raws[0]) # dump CSV table def dump_csv(self, table_name, file_name): @@ -78,12 +84,10 @@ class SQLiteDB: raise Exception('wrong output file type: "' + file_name + '"' ) fields = self._get_fields(table_name) - stm = 'select ' + ','.join(fields) + ' from ' + table_name - with open(file_name, mode='w') as fd: fd.write(','.join(fields) + '\n') - for values in self.connection.execute(stm): - fd.write(reduce(lambda a, b: str(a) + ',' + str(b), values) + '\n') + for raw in self._get_raws(table_name): + fd.write(reduce(lambda a, b: str(a) + ',' + str(b), raw) + '\n') # dump JSON trace def open_json(self, file_name): @@ -104,15 +108,17 @@ class SQLiteDB: with open(file_name, mode='a') as fd: fd.write(',{"args":{"name":"%s"},"ph":"M","pid":%s,"name":"process_name"}\n' %(label, pid)); - def flow_json(self, from_pid, from_list, to_pid, to_dict, file_name): + def flow_json(self, base_id, from_pid, from_tid, from_us_list, to_pid, to_us_dict, start_us, file_name): if not re.search(r'\.json$', file_name): raise Exception('wrong output file type: "' + file_name + '"' ) with open(file_name, mode='a') as fd: - for ind in range(len(from_list)): - from_ts = from_list[ind] - to_ts = to_dict[str(ind)] - fd.write(',{"ts":%s,"ph":"s","cat":"DataFlow","id":%s,"pid":%s,"tid":0,"name":"dep"}\n' % (from_ts, str(ind), str(from_pid))) - fd.write(',{"ts":%s,"ph":"t","cat":"DataFlow","id":%s,"pid":%s,"tid":0,"name":"dep"}\n' % (to_ts, str(ind), str(to_pid))) + dep_id = base_id + for ind in range(len(from_tid)): + from_ts = from_us_list[ind] - start_us + to_ts = to_us_dict[ind] - start_us + fd.write(',{"ts":%d,"ph":"s","cat":"DataFlow","id":%d,"pid":%s,"tid":%d,"name":"dep"}\n' % (from_ts, dep_id, str(from_pid), from_tid[ind])) + fd.write(',{"ts":%d,"ph":"t","cat":"DataFlow","id":%d,"pid":%s,"tid":0,"name":"dep"}\n' % (to_ts, dep_id, str(to_pid))) + dep_id += 1 def dump_json(self, table_name, data_name, file_name): if not re.search(r'\.json$', file_name): @@ -124,20 +130,20 @@ class SQLiteDB: table_fields = self._get_fields(table_name) table_raws = self._get_raws(table_name) data_fields = self._get_fields(data_name) - data_raws = self._get_raws(data_name) with open(file_name, mode='a') as fd: for raw_index in range(len(table_raws)): values = list(table_raws[raw_index]) - data = list(data_raws[raw_index]) - vals_list = [] + raw_id = 0; for value_index in range(len(values)): label = table_fields[value_index] value = values[value_index] if name_ptrn.search(label): value = sub_ptrn.sub(r'', value) - vals_list.append('%s:"%s"' % (label, value)) + if label == '"Index"': raw_id = value + else: vals_list.append('%s:"%s"' % (label, value)) + data = self._get_raw_by_id(data_name, raw_id) args_list = [] for value_index in range(len(data)): label = data_fields[value_index] diff --git a/bin/tblextr.py b/bin/tblextr.py index f929e619b0..93147cb632 100644 --- a/bin/tblextr.py +++ b/bin/tblextr.py @@ -36,8 +36,11 @@ COPY_PID = 0 HSA_PID = 1 GPU_BASE_PID = 2 max_gpu_id = 0 -dep_from_list = [] -dep_to_dict = {} +START_NS = 0 + +# dependencies dictionary +dep_dict = {} +kern_dep_list = [] # global vars table_descr = [ @@ -84,6 +87,10 @@ def parse_res(infile): 'Index': dispatch_number, 'KernelName': "\"" + m.group(3) + "\"" } + + gpu_id = 0 + disp_tid = 0 + kernel_properties = m.group(2) for prop in kernel_properties.split(', '): m = prop_pattern.match(prop) @@ -92,8 +99,10 @@ def parse_res(infile): val = m.group(2) var_table[dispatch_number][var] = val if not var in var_list: var_list.append(var); - if re.search(r'gpu-id', var): + if var == 'gpu-id': if (val > max_gpu_id): max_gpu_id = val + gpu_id = val + if var == 'tid': disp_tid = int(val) else: fatal('wrong kernel property "' + prop + '" in "'+ kernel_properties + '"') m = ts_pattern.search(record) if m: @@ -101,6 +110,21 @@ def parse_res(infile): var_table[dispatch_number]['BeginNs'] = m.group(2) var_table[dispatch_number]['EndNs'] = m.group(3) var_table[dispatch_number]['CompleteNs'] = m.group(4) + else: fatal('bad kernel record "' + record + '"') + + gpu_pid = GPU_BASE_PID + int(gpu_id) + if not gpu_pid in dep_dict: dep_dict[gpu_pid] = {} + dep_str = dep_dict[gpu_pid] + if not 'tid' in dep_str: dep_str['tid'] = [] + if not 'from' in dep_str: dep_str['from'] = [] + if not 'to' in dep_str: dep_str['to'] = {} + to_id = len(dep_str['tid']) + from_us = int(m.group(1)) / 1000 + to_us = int(m.group(2)) / 1000 + dep_str['to'][to_id] = to_us + dep_str['from'].append(from_us) + dep_str['tid'].append(disp_tid) + kern_dep_list.append((disp_tid, from_us)) inp.close() ############################################################# @@ -155,14 +179,27 @@ def fill_kernel_db(table_name, db): # fill HSA DB hsa_table_descr = [ - ['BeginNs', 'EndNs', 'pid', 'tid', 'Name', 'args'], - {'Name':'TEXT', 'args':'TEXT', 'BeginNs':'INTEGER', 'EndNs':'INTEGER', 'pid':'INTEGER', 'tid':'INTEGER'} + ['BeginNs', 'EndNs', 'pid', 'tid', 'Name', 'args', 'Index'], + {'Index':'INTEGER', 'Name':'TEXT', 'args':'TEXT', 'BeginNs':'INTEGER', 'EndNs':'INTEGER', 'pid':'INTEGER', 'tid':'INTEGER'} ] def fill_hsa_db(table_name, db, indir): + global START_NS file_name = indir + '/' + 'hsa_api_trace.txt' ptrn_val = re.compile(r'(\d+):(\d+) (\d+):(\d+) ([^\(]+)(\(.*)$') ptrn_ac = re.compile(r'hsa_amd_memory_async_copy') + if not COPY_PID in dep_dict: dep_dict[COPY_PID] = {} + dep_tid_list = [] + dep_from_us_list = [] + + with open(file_name, mode='r') as fd: + line = fd.readline() + record = line[:-1] + m = ptrn_val.match(record) + if m: START_NS = int(m.group(1)) + START_NS = 0 + + record_id = 0 table_handle = db.add_table(table_name, hsa_table_descr) with open(file_name, mode='r') as fd: for line in fd.readlines(): @@ -171,24 +208,40 @@ def fill_hsa_db(table_name, db, indir): if m: rec_vals = [] for ind in range(1,7): - if hsa_table_descr[0][ind - 1] == 'pid': - rec_vals.append(HSA_PID) - else: - rec_vals.append(m.group(ind)) + rec_vals.append(m.group(ind)) + rec_vals[2] = HSA_PID + rec_vals.append(record_id) db.insert_entry(table_handle, rec_vals) - if ptrn_ac.search(rec_vals[4]): dep_from_list.append(rec_vals[1]) + if ptrn_ac.search(rec_vals[4]): + beg_ns = int(rec_vals[0]) + end_ns = int(rec_vals[1]) + from_us = (beg_ns / 1000) + ((end_ns - beg_ns) / 1000) + dep_from_us_list.append(from_us) + dep_tid_list.append(int(rec_vals[3])) + record_id += 1 + else: fatal("hsa bad record") + + for (tid, from_us) in kern_dep_list: + db.insert_entry(table_handle, [((from_us - 1) * 1000), from_us * 1000, HSA_PID, tid, 'hsa_dispatch', '', record_id]) + record_id += 1 + + dep_dict[COPY_PID]['tid'] = dep_tid_list + dep_dict[COPY_PID]['from'] = dep_from_us_list ############################################################# # fill COPY DB copy_table_descr = [ - ['BeginNs', 'EndNs', 'Name', 'pid', 'tid'], - {'Name':'TEXT', 'args':'TEXT', 'BeginNs':'INTEGER', 'EndNs':'INTEGER', 'pid':'INTEGER', 'tid':'INTEGER'} + ['BeginNs', 'EndNs', 'Name', 'pid', 'tid', 'Index'], + {'Index':'INTEGER', 'Name':'TEXT', 'args':'TEXT', 'BeginNs':'INTEGER', 'EndNs':'INTEGER', 'pid':'INTEGER', 'tid':'INTEGER'} ] def fill_copy_db(table_name, db, indir): file_name = indir + '/' + 'async_copy_trace.txt' ptrn_val = re.compile(r'(\d+):(\d+) (.*)$') ptrn_id = re.compile(r'^async-copy(\d+)$') + if not COPY_PID in dep_dict: dep_dict[COPY_PID] = {} + dep_to_us_dict = {} + table_handle = db.add_table(table_name, copy_table_descr) with open(file_name, mode='r') as fd: for line in fd.readlines(): @@ -199,11 +252,14 @@ def fill_copy_db(table_name, db, indir): for ind in range(1,4): rec_vals.append(m.group(ind)) rec_vals.append(COPY_PID) rec_vals.append(0) - db.insert_entry(table_handle, rec_vals) m = ptrn_id.match(rec_vals[2]) - if m: dep_to_dict[m.group(1)] = rec_vals[0] + if m: dep_to_us_dict[int(m.group(1))] = int(rec_vals[0]) / 1000 else: fatal("async-copy bad name") + rec_vals.append(m.group(1)) + db.insert_entry(table_handle, rec_vals) else: fatal("async-copy bad record") + + dep_dict[COPY_PID]['to'] = dep_to_us_dict ############################################################# # main if (len(sys.argv) < 3): fatal("Usage: " + sys.argv[0] + " ") @@ -247,21 +303,27 @@ else: for ind in range(0, int(max_gpu_id) + 1): db.label_json(int(ind) + int(GPU_BASE_PID), "GPU" + str(ind), jsonfile) if 'BeginNs' in var_list: - dform.post_process_data(db, 'A', csvfile) + dform.post_process_data(db, 'A', START_NS, csvfile) dform.gen_table_bins(db, 'A', statfile, 'KernelName', 'DurationNs') - dform.gen_kernel_json_trace(db, 'A', jsonfile) + dform.gen_kernel_json_trace(db, 'A', GPU_BASE_PID, START_NS, jsonfile) else: db.dump_csv('A', csvfile) statfile = re.sub(r'stats', r'hsa_stats', statfile) - dform.post_process_data(db, 'HSA') + dform.post_process_data(db, 'HSA', START_NS) dform.gen_table_bins(db, 'HSA', statfile, 'Name', 'DurationNs') - dform.gen_api_json_trace(db, 'HSA', jsonfile) + dform.gen_api_json_trace(db, 'HSA', START_NS, jsonfile) - dform.post_process_data(db, 'COPY') - dform.gen_api_json_trace(db, 'COPY', jsonfile) + dform.post_process_data(db, 'COPY', START_NS) + dform.gen_api_json_trace(db, 'COPY', START_NS, jsonfile) - db.flow_json(HSA_PID, dep_from_list, COPY_PID, dep_to_dict, jsonfile) + dep_id = 0 + for (to_pid, dep_str) in dep_dict.items(): + tid_list = dep_str['tid'] + from_us_list = dep_str['from'] + to_us_dict = dep_str['to'] + db.flow_json(dep_id, HSA_PID, tid_list, from_us_list, to_pid, to_us_dict, (START_NS / 1000), jsonfile) + dep_id += len(tid_list) db.close_json(jsonfile); db.close()