# scope_profiler.diff

*module*

CLI entry point for ``scope-profiler diff``: compare two profiling files.

Aligns region statistics between two merged HDF5 profiling files by region
name and reports the change in one metric (default: total duration), so a
regression - or an improvement - between two runs (two commits, two
configs, two job sizes) shows up as a single table instead of two separate
``inspect`` runs a human has to cross-reference by eye.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L1-L1)

## scope_profiler.diff.METRICS

*attribute* · *module attribute*

```python
METRICS = ('gpu_total', 'gpu_avg', 'total', 'avg', 'min', 'max', 'p50', 'p95', 'p99', 'imbalance', 'calls')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L23-L35)

## scope_profiler.diff.SORT_KEYS

*attribute* · *module attribute*

```python
SORT_KEYS = ('delta', 'pct', 'name')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L46-L46)

## scope_profiler.diff.build_check_parser

*function*

```python
def build_check_parser() -> argparse.ArgumentParser
```

Build the parser for ``scope-profiler check``.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L424-L448)

## scope_profiler.diff.build_parser

*function*

```python
def build_parser() -> argparse.ArgumentParser
```

Build the argument parser for ``scope-profiler diff``.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L380-L421)

## scope_profiler.diff.check_files

*function*

```python
def check_files(file_a, file_b, max_regression: float = 0.0, include=None, exclude=None, ranks=None, metric: str = 'total', fail_on_new: bool = False, stream=None) -> int
```

Print a CI regression report and return 0 for pass, 1 for failure.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L315-L377)

## scope_profiler.diff.check_main

*function*

```python
def check_main(argv: list | None = None)
```

Entry point for ``scope-profiler check``.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L475-L493)

## scope_profiler.diff.check_rows

*function*

```python
def check_rows(results_a: ProfilingResults, results_b: ProfilingResults, max_regression: float = 0.0, include=None, exclude=None, ranks=None, metric: str = 'total', fail_on_new: bool = False) -> list
```

Return rows that violate a performance regression budget.

``max_regression`` is a percentage. New regions have no meaningful
percentage baseline and are only failures when ``fail_on_new`` is true.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L281-L312)

## scope_profiler.diff.diff_files

*function*

```python
def diff_files(file_a, file_b, include=None, exclude=None, ranks=None, metric: str = 'total', sort: str = 'delta', threshold: float | None = None, stream=None) -> None
```

Print a region-by-region comparison of two profiling HDF5 files.

Parameters
----------
file_a, file_b : str or Path
    The "before" and "after" merged profiling files.
include, exclude, ranks, metric, sort, threshold
    See :func:`diff_rows`.
stream : file-like, optional
    Where to write (default: stdout).

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L219-L278)

## scope_profiler.diff.diff_rows

*function*

```python
def diff_rows(results_a: ProfilingResults, results_b: ProfilingResults, include=None, exclude=None, ranks=None, metric: str = 'total', sort: str = 'delta', threshold: float | None = None) -> list
```

Build one comparison row per region present in either result set.

Parameters
----------
results_a, results_b : ProfilingResults
    The "before" (``a``) and "after" (``b``) runs.
include, exclude : list of str or str, optional
    Regex patterns selecting which regions to compare, matched as in
    :func:`~scope_profiler.summary.region_rows`.
ranks : list of int, optional
    Restrict the statistics to these ranks (default: all).
metric : str, optional
    Which per-region statistic to compare: one of :data:`METRICS`
    (default: ``total``).
sort : str, optional
    One of :data:`SORT_KEYS`: ``delta`` and ``pct`` sort by descending
    magnitude of change (default: ``delta``), ``name`` alphabetically.
threshold : float, optional
    Drop regions whose absolute percent change is below this many
    percent. Regions that only appear in one file always pass, since
    there is no baseline to compute a percentage against.

Returns
-------
list of dict
    Each entry has ``name``, ``a``, ``b`` (the metric's value in each
    file, or None when the region is missing - or timed no calls on the
    selected ranks - there), ``delta`` (``b - a``, treating a missing
    side as 0) and ``pct`` (percent change, or None when ``a`` is None or
    0).

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L63-L147)

## scope_profiler.diff.main

*function*

```python
def main(argv: list | None = None)
```

Entry point for ``scope-profiler diff``.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L451-L472)

## scope_profiler.diff.print_diff_table

*function*

```python
def print_diff_table(rows, metric: str = 'total', title=None, stream=None) -> None
```

Print the aligned region comparison table built by :func:`diff_rows`.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/diff.py#L173-L216)
