From fb6eaa1960b7b2d7b70a608a4c4ef80a0d5e8cac Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Date: Mon, 28 Nov 2022 12:03:27 +0200 Subject: [PATCH] report-fossil: add anv support --- README.md | 8 +- anv-report-fossil.py | 187 ------------------------------------------- report-fossil.py | 31 ++++++- 3 files changed, 28 insertions(+), 198 deletions(-) delete mode 100755 anv-report-fossil.py diff --git a/README.md b/README.md index 85c3605..0933c37 100644 --- a/README.md +++ b/README.md @@ -124,13 +124,7 @@ Or you can use fossil_prune_replay.sh to replay a specific pipeline by hash: If you do not get a .csv file it likely means that a driver without `VK_KHR_pipeline_statistics`, such as a system installed driver. -You can then compare two different csv files using the anv-report-fossil.py or -radv-report-fossil.py scripts: - - $ anv-report-fossil.py baseline.csv development.csv - $ radv-report-fossil.py baseline.csv development.csv - -Or the report-fossil.py script, which guesses the driver used: +You can then compare two different csv files using the report-fossil.py script: $ report-fossil.py baseline.csv development.csv diff --git a/anv-report-fossil.py b/anv-report-fossil.py deleted file mode 100755 index 7996aaf..0000000 --- a/anv-report-fossil.py +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/env python3 -# Copyright © 2019 Intel Corporation - -# 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 argparse -import csv -import pathlib -import typing - -import attr - -if typing.TYPE_CHECKING: - import typing_extensions - - class DiffProtocol(typing_extensions.Protocol): - - old: int - new: int - - V = typing.TypeVar('V', int, float, str) - - -@attr.s(slots=True) -class Result: - - name: str = attr.ib() - instructions: typing.Optional[int] = attr.ib() - sends: typing.Optional[int] = attr.ib() - loops: typing.Optional[int] = attr.ib() - cycles: typing.Optional[int] = attr.ib() - spills: typing.Optional[int] = attr.ib() - fills: typing.Optional[int] = attr.ib() - - -@attr.s(slots=True) -class ResultFactory: - - lookups: typing.Dict[str, int] = attr.ib() - - def __call__(self, row: typing.List[str]) -> Result: - def get(name: str, type_: typing.Type['V']) -> typing.Optional['V']: - try: - v = row[self.lookups[name]] - except (KeyError, IndexError): - return None - return type_(v) - - shader_name = '/'.join([ - get('Database', str), - get('Pipeline hash', str), - get('Executable name', str), - ]) - - return Result( - name=shader_name, - instructions=get('Instruction Count', int), - sends=get('SEND Count', int), - loops=get('Loop Count', int), - cycles=get('Cycle Count', int), - spills=get('Spill Count', int), - fills=get('Fill Count', int), - ) - - -def calculate_percent(diff: 'DiffProtocol') -> str: - if diff.new and diff.old: - return '{:+.1%}'.format((diff.new / diff.old) - 1) - return '0.0%' - - -@attr.s(slots=True) -class ProgramDiff: - - name: str = attr.ib() - old: int = attr.ib() - new: int = attr.ib() - - -@attr.s(slots=True) -class Diff: - - name: str = attr.ib() - old: int = attr.ib(0) - new: int = attr.ib(0) - helped: typing.Dict[str, ProgramDiff] = attr.ib(factory=dict) - hurt: typing.Dict[str, ProgramDiff] = attr.ib(factory=dict) - - def generate(self) -> str: - result: typing.List[str] = [ - f'{self.name} in all programs: {self.old} -> {self.new} ({calculate_percent(self)})'] - result.extend( - [f'{self.name} helped {n}: {h.old} -> {h.new} ({calculate_percent(h)})' - for n, h in self.helped.items()]) - result.extend( - [f'{self.name} hurt {n}: {h.old} -> {h.new} ({calculate_percent(h)})' - for n, h in self.hurt.items()]) - - return '\n'.join(result) - - -@attr.s(slots=True) -class Report: - - instructions: Diff = attr.ib(factory=lambda: Diff('Instructions')) - sends: Diff = attr.ib(factory=lambda: Diff('SENDs')) - loops: Diff = attr.ib(factory=lambda: Diff('Loops')) - cycles: Diff = attr.ib(factory=lambda: Diff('Cycles')) - spills: Diff = attr.ib(factory=lambda: Diff('Spills')) - fills: Diff = attr.ib(factory=lambda: Diff('Fills')) - - def include(self, name: str, d0: Result, d1: Result) -> None: - for m in ['instructions', 'sends', 'loops', 'cycles', 'spills', 'fills']: - self._include(name, getattr(self, m), getattr(d0, m), getattr(d1, m)) - - def _include(self, name: str, member: Diff, d0: typing.Optional[int], - d1: typing.Optional[int]) -> None: - if d0 > d1: - member.helped[name] = ProgramDiff(name, d0, d1) - elif d0 < d1: - member.hurt[name] = ProgramDiff(name, d0, d1) - - member.old += d0 - member.new += d1 - - def _include_cycles(self, name: str, d0: Result, d1: Result) -> None: - pass - - def generate(self) -> str: - return '\n\n'.join(m.generate() for m in attr.astuple(self, recurse=False)) - - -def read_csv(csv_file: pathlib.Path) -> typing.Dict[str, Result]: - data: typing.Dict[str, Result] = {} - with csv_file.open('rt') as f: - reader = csv.reader(f) - for row in reader: - if 'Database' in row: - factory = ResultFactory({k: v for v, k in enumerate(row)}) - continue - shader = factory(row) - data[shader.name] = shader - return data - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('csv', nargs=2, type=pathlib.Path, help='Path to CSV files') - args = parser.parse_args() - - data0 = read_csv(args.csv[0]) - data1 = read_csv(args.csv[1]) - - names = set(list(data0.keys()) + list(data1.keys())) - - report = Report() - for name in names: - d0 = data0.get(name) - d1 = data1.get(name) - if not (d0 and d1): - # If a fossil is only in one run or another don't include it, - # otherwise we'll skew the overall results. - continue - report.include(name, d0, d1) - - print(report.generate()) - - -if __name__ == "__main__": - main() - diff --git a/report-fossil.py b/report-fossil.py index 025e728..e458025 100755 --- a/report-fossil.py +++ b/report-fossil.py @@ -124,6 +124,15 @@ statistics = [ Statistic(internal_name='spills', csv_names=['TMU Spills'], display_name='Spills'), Statistic(internal_name='fills', csv_names=['TMU Fills'], display_name='Fills'), Statistic(internal_name='read_stalls', csv_names=['Read Stalls'], display_name='Read Stalls'), + + # Anv statistics + Statistic(internal_name='subgroup_size', csv_names=['Subgroup size'], display_name='Subgroup size'), + Statistic(internal_name='send_count', csv_names=['SEND Count'], display_name='Send messages'), + Statistic(internal_name='loop_count', csv_names=['Loop Count'], display_name='Loop count'), + Statistic(internal_name='cycle_count', csv_names=['Cycle Count'], display_name='Cycle count'), + Statistic(internal_name='spill_count', csv_names=['Spill Count'], display_name='Spill count'), + Statistic(internal_name='fill_count', csv_names=['Fill Count'], display_name='Fill count'), + Statistic(internal_name='scratch_size', csv_names=['Scratch Memory Size'], display_name='Scratch Memory Size'), ] for n in range(8): @@ -162,6 +171,24 @@ executables = { 'FS (Render)' : 'fs', 'FS (Binning)' : 'binning_fs', 'CS (Render)' : 'cs', + + # Anv executable names + 'vertex' : 'vs', + 'geometry' : 'gs', + 'tessellation control': 'tcs', + 'tessellation evaluation': 'tes', + 'mesh': 'mesh', + 'task': 'task', + 'kernel': 'ks', + 'SIMD8 fragment': 'fs', + 'SIMD16 fragment': 'fs', + 'SIMD32 fragment': 'fs', + 'compute': 'cs', + 'raygen' : 'rgen', + 'any hit' : 'ahit', + 'miss' : 'miss', + 'closest hit' : 'chit', + 'intersection' : 'intersection', } @@ -587,10 +614,6 @@ def main(): driver = next(iter(drivers)) - if driver == 'anv': - importlib.import_module('anv-report-fossil').main() - return - parser = argparse.ArgumentParser() parser.add_argument('csv', nargs='+', type=pathlib.Path, help='Path to CSV files') stat_list_arg = {'nargs':'*', 'default':None, 'type':str, 'metavar':'STAT', -- GitLab