intel/tools: add eop timestamp to intel_measure
Adds end of pipe to end of pipe timestamp parsing. Does not require inserting stall between events to get accurate values but events will sometimes be running in parallel. Reviewed-by: Casey Bowman <casey.g.bowman@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37983>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Optional
|
||||
|
||||
import argparse
|
||||
import re
|
||||
@@ -10,14 +11,31 @@ def error(msg, err_code=1):
|
||||
print('ERROR: ' + msg)
|
||||
sys.exit(err_code)
|
||||
|
||||
class Line:
|
||||
def __init__(self, line_str: str):
|
||||
self.valid = False
|
||||
if line_str.count(',') < 4:
|
||||
return
|
||||
(frame, cmd_buf, timestamp, self.name, self.args) = line_str.strip().split(',', 4)
|
||||
if self.name.count('_') < 2:
|
||||
return
|
||||
(self.intel, begin_or_end, self.func) = self.name.split('_', 2)
|
||||
|
||||
self.frame: int = int(frame)
|
||||
self.cmd_buf: int = int(cmd_buf)
|
||||
self.timestamp: float = float(timestamp)
|
||||
self.is_begin: bool = begin_or_end == 'begin'
|
||||
self.valid: bool = True
|
||||
|
||||
class Utrace_Parser:
|
||||
def __init__(self, cl_args: argparse.Namespace):
|
||||
self.cl_args = cl_args
|
||||
self.events: Dict[str, float] = {}
|
||||
self.events: dict[str, float] = {}
|
||||
self.renderpass: int = 0
|
||||
self.next_renderpass: int = 1
|
||||
self.idx: int = 0
|
||||
self.prev_end_ts_ns: float = 0
|
||||
self.last_eop: float = 0
|
||||
|
||||
self.func: str
|
||||
self.args: str
|
||||
@@ -26,9 +44,15 @@ class Utrace_Parser:
|
||||
self.cs: str
|
||||
|
||||
def get_header(self) -> str:
|
||||
if self.cl_args.verbose:
|
||||
return 'start_ts,end_ts,frame,cmdbuf,rp,idx,event,count,vs,fs,cs,gap_us,time_us,details'
|
||||
return 'frame,cmdbuf,rp,idx,event,count,vs,fs,cs,gap_us,time_us'
|
||||
if self.cl_args.mode == 'top':
|
||||
if self.cl_args.verbose:
|
||||
return 'start_ts,end_ts,frame,cmdbuf,rp,idx,event,count,vs,fs,cs,gap_us,time_us,details'
|
||||
return 'frame,cmdbuf,rp,idx,event,count,vs,fs,cs,gap_us,time_us'
|
||||
elif self.cl_args.mode == 'eop':
|
||||
if self.cl_args.verbose:
|
||||
return 'end_ts,frame,cmdbuf,rp,idx,event,count,vs,fs,cs,time_us,details'
|
||||
return 'frame,cmdbuf,rp,idx,event,count,vs,fs,cs,time_us'
|
||||
raise RuntimeError('invalid mode')
|
||||
|
||||
def extract_count(self) -> None:
|
||||
if 'count' in self.args:
|
||||
@@ -68,18 +92,16 @@ class Utrace_Parser:
|
||||
self.func = match.group(2).lower()
|
||||
self.args = match.group(1) + match.group(3)
|
||||
|
||||
def parse_line(self, line) -> str:
|
||||
if line.count(',') < 4:
|
||||
def parse_line(self, line_str: str) -> Optional[str]:
|
||||
line = Line(line_str)
|
||||
if not line.valid:
|
||||
return None
|
||||
(frame, cmd_buf, timestamp, name, args) = line.strip().split(',', 4)
|
||||
|
||||
if name.count('_') < 2:
|
||||
return None
|
||||
(intel, begin_or_end, self.func) = name.split('_', 2)
|
||||
self.func = line.func
|
||||
|
||||
if self.func == 'render_pass':
|
||||
if begin_or_end == 'begin':
|
||||
if line.is_begin:
|
||||
self.renderpass = self.next_renderpass
|
||||
self.last_eop = line.timestamp
|
||||
return
|
||||
self.next_renderpass = self.renderpass + 1
|
||||
self.renderpass = 0
|
||||
@@ -88,41 +110,51 @@ class Utrace_Parser:
|
||||
ignore_funcs = {'frame': True, 'cmd_buffer': True}
|
||||
if ignore_funcs.get(self.func, None):
|
||||
if self.prev_end_ts_ns == 0:
|
||||
self.prev_end_ts_ns = float(timestamp)
|
||||
self.prev_end_ts_ns = line.timestamp
|
||||
self.last_eop = line.timestamp
|
||||
return None
|
||||
|
||||
if begin_or_end == 'begin':
|
||||
self.events[self.func] = float(timestamp)
|
||||
return None
|
||||
|
||||
# end event
|
||||
begin_ts_ns = self.events.pop(self.func, 0)
|
||||
end_ts_ns = float(timestamp)
|
||||
gap_ts_us = (begin_ts_ns - self.prev_end_ts_ns) / 1000
|
||||
delta_ts_us = (end_ts_ns - begin_ts_ns) / 1000
|
||||
|
||||
self.count = 0
|
||||
self.vs = ''
|
||||
self.fs = ''
|
||||
self.cs = ''
|
||||
self.args = args.replace(',', ';').strip(';')
|
||||
self.args = line.args.replace(',', ';').strip(';')
|
||||
|
||||
if self.cl_args.mode == 'top':
|
||||
result = self.parse_top(line)
|
||||
elif self.cl_args.mode == 'eop':
|
||||
result = self.parse_eop(line)
|
||||
else:
|
||||
raise RuntimeError('invalid mode')
|
||||
return result
|
||||
|
||||
def parse_top(self, line: Line) -> Optional[str]:
|
||||
if line.is_begin:
|
||||
self.events[self.func] = line.timestamp
|
||||
return None
|
||||
|
||||
# end event
|
||||
begin_ts_ns = self.events.pop(self.func, 0)
|
||||
end_ts_ns = line.timestamp
|
||||
gap_ts_us = (begin_ts_ns - self.prev_end_ts_ns) / 1000
|
||||
delta_ts_us = (end_ts_ns - begin_ts_ns) / 1000
|
||||
|
||||
self.extract_count()
|
||||
if 'draw' in name or 'compute' in name:
|
||||
if 'draw' in line.name or 'compute' in line.name:
|
||||
self.extract_shaders()
|
||||
self.idx += 1
|
||||
elif 'blorp' in name:
|
||||
elif 'blorp' in line.name:
|
||||
self.extract_blorp_op()
|
||||
self.idx += 1
|
||||
self.args = self.args.strip().lstrip('+')
|
||||
|
||||
if self.cl_args.verbose:
|
||||
out = [f'{begin_ts_ns:.0f}', f'{end_ts_ns:.0f}', int(frame),
|
||||
int(cmd_buf), self.renderpass, self.idx, self.func,
|
||||
out = [f'{begin_ts_ns:.0f}', f'{end_ts_ns:.0f}', line.frame,
|
||||
line.cmd_buf, self.renderpass, self.idx, self.func,
|
||||
self.count, self.vs, self.fs, self.cs,
|
||||
f'{gap_ts_us:.3f}', f'{delta_ts_us:.3f}', self.args]
|
||||
else:
|
||||
out = [int(frame), int(cmd_buf), self.renderpass, self.idx,
|
||||
out = [line.frame, line.cmd_buf, self.renderpass, self.idx,
|
||||
self.func, self.count, self.vs, self.fs, self.cs,
|
||||
f'{gap_ts_us:.3f}', f'{delta_ts_us:.3f}']
|
||||
|
||||
@@ -130,14 +162,53 @@ class Utrace_Parser:
|
||||
result = ','.join(v if isinstance(v, str) else str(v) for v in out)
|
||||
return result
|
||||
|
||||
def parse_eop(self, line: Line) -> Optional[str]:
|
||||
if line.is_begin:
|
||||
return None
|
||||
|
||||
# end event
|
||||
start_ts_ns = self.last_eop
|
||||
end_ts_ns = line.timestamp
|
||||
delta_ts_us = max(0, (end_ts_ns - start_ts_ns) / 1000)
|
||||
|
||||
self.extract_count()
|
||||
if 'draw' in line.name or 'compute' in line.name:
|
||||
self.extract_shaders()
|
||||
self.idx += 1
|
||||
elif 'blorp' in line.name:
|
||||
self.extract_blorp_op()
|
||||
self.idx += 1
|
||||
self.args = self.args.strip().lstrip('+')
|
||||
|
||||
if self.cl_args.verbose:
|
||||
out = [f'{end_ts_ns:.0f}', line.frame,
|
||||
line.cmd_buf, self.renderpass, self.idx, self.func,
|
||||
self.count, self.vs, self.fs, self.cs,
|
||||
f'{delta_ts_us:.3f}', self.args]
|
||||
else:
|
||||
out = [line.frame, line.cmd_buf, self.renderpass, self.idx,
|
||||
self.func, self.count, self.vs, self.fs, self.cs,
|
||||
f'{delta_ts_us:.3f}']
|
||||
|
||||
self.last_eop = line.timestamp
|
||||
result = ','.join(v if isinstance(v, str) else str(v) for v in out)
|
||||
return result
|
||||
|
||||
class CustomArgumentParser(argparse.ArgumentParser):
|
||||
examples = """
|
||||
Examples
|
||||
========
|
||||
> Generate csv of gpu events while running <cmd>. Use stalls to avoid overlapping events:
|
||||
> Generate csv of EndToEndOfPipe gpu events while running <cmd>. Events running
|
||||
> in parallel.
|
||||
|
||||
MESA_GPU_TRACES=print_csv MESA_GPU_TRACEFILE=/tmp/ut.csv <cmd>
|
||||
intel_measure.py --eop /tmp/ut.csv > im.csv
|
||||
|
||||
> Generate csv of TopToEndOfPipe gpu events while running <cmd>. Use stalls to
|
||||
> avoid overlapping events:
|
||||
|
||||
MESA_GPU_TRACES=print_csv MESA_GPU_TRACEFILE=/tmp/ut.csv INTEL_DEBUG=stall <cmd>
|
||||
intel_measure.py /tmp/ut.csv > im.csv
|
||||
intel_measure.py --top /tmp/ut.csv > im.csv
|
||||
|
||||
"""
|
||||
def format_help(self):
|
||||
@@ -148,6 +219,9 @@ def main():
|
||||
cl_parser.add_argument('utrace_log', type=str, help='path to utrace log to parse')
|
||||
cl_parser.add_argument('-v', '--verbose', default=False, action='store_true', help='dump all fields to output')
|
||||
cl_parser.add_argument('-f', '--file', type=str, default=None, help='save results to file')
|
||||
cl_parser.add_argument( '--eop', action='store_const', const='eop', dest='mode', help='use end-to-end-of-pipe gpu measurements (default)')
|
||||
cl_parser.add_argument( '--top', action='store_const', const='top', dest='mode', help='use top-to-end-of-pipe gpu measurements')
|
||||
cl_parser.set_defaults(mode='top')
|
||||
|
||||
cl_args = cl_parser.parse_args()
|
||||
parser = Utrace_Parser(cl_args)
|
||||
|
||||
Reference in New Issue
Block a user