diff --git a/op-summarizer/gcovreader.py b/op-summarizer/gcovreader.py index dc5a24c..097a777 100644 --- a/op-summarizer/gcovreader.py +++ b/op-summarizer/gcovreader.py @@ -8,7 +8,7 @@ from typing import Dict, List class GCovLine: line_number: int count: int - is_fallthrough: bool = False + branch_number: int = 0 class GCovFile: @@ -28,8 +28,11 @@ class GCovFile: for line in file["lines"]: if len(line["branches"]): + # GCov reports branches in reverse order to our parser. + branch_number = len(line["branches"]) for branch in line["branches"]: - lines.append(GCovLine(line["line_number"], branch["count"], branch["fallthrough"])) + lines.append(GCovLine(line["line_number"], branch["count"], branch_number)) + branch_number -= 1 else: lines.append(GCovLine(line["line_number"], line["count"])) diff --git a/op-summarizer/op-summarizer.py b/op-summarizer/op-summarizer.py index e17bab4..d0dcac7 100644 --- a/op-summarizer/op-summarizer.py +++ b/op-summarizer/op-summarizer.py @@ -1,25 +1,8 @@ from dataclasses import dataclass -from typing import Dict, List, Optional +from typing import Dict, List from gcovreader import GCovFile, GCovLine -from opfinderreader import OperationLogReader, OperationLog - - -@dataclass(frozen=True) -class UniqueOperation: - name: str - type_lhs: Optional[str] - type_rhs: Optional[str] - type_expr: Optional[str] - - @staticmethod - def from_operation_log(op_log: OperationLog) -> "UniqueOperation": - return UniqueOperation( - op_log.operation, - op_log.operand_lhs, - op_log.operand_rhs, - op_log.operand_result - ) +from opfinderreader import OperationLogReader, UniqueOperation if __name__ == "__main__": @@ -36,17 +19,15 @@ if __name__ == "__main__": print(f"Couldn't find {file_name} in op-finder output. Skipping.") continue - loop_stack: List[int] = [] - for gcov_line in gcov.files[file_name]: op_lines = ops.get_lines(file_name, gcov_line.line_number) - for opfinder_line in op_lines: + for op_log in op_lines: # TODO: revise this. Need a special case for for-loop clauses # or branching in general. - if opfinder_line.is_fallthrough != gcov_line.is_fallthrough: + if op_log.branch_number != gcov_line.branch_number: continue - unique_op = UniqueOperation.from_operation_log(opfinder_line) + unique_op = op_log.entry if unique_op in op_counter: op_counter[unique_op] += gcov_line.count diff --git a/op-summarizer/opfinderreader.py b/op-summarizer/opfinderreader.py index 53f6179..8f6d3dc 100644 --- a/op-summarizer/opfinderreader.py +++ b/op-summarizer/opfinderreader.py @@ -1,18 +1,48 @@ import json -from dataclasses import dataclass, field -from typing import Dict, List +from enum import Enum +from dataclasses import dataclass +from typing import Any, Dict, List, Union + + +class OperationType(Enum): + BASIC = "basic_operation" + FUNCTION_CALL = "function_call" + + +@dataclass(frozen=True) +class BasicOperation: + operation_name: str + type_lhs: str + type_rhs: str + type_result: str + + +@dataclass(frozen=True) +class FunctionCall: + function_name: str + call_result_type: str + + +UniqueOperation = Union[BasicOperation, FunctionCall] @dataclass class OperationLog: - operation: str line: int - operand_lhs: str - operand_rhs: str - operand_result: str - is_fallthrough: bool - current_for_loops: list[int] = field(default_factory=list) + branch_number: int + entry_type: OperationType + entry: UniqueOperation + + def __post_init__(self) -> None: + self.entry_type = OperationType(self.entry_type) + + if self.entry_type == OperationType.BASIC: + self.entry = BasicOperation(**self.entry) + elif self.entry_type == OperationType.FUNCTION_CALL: + self.entry = FunctionCall(**self.entry) + else: + assert False, "Unaccounted for operation type." class OperationLogReader: