Metadata-Version: 2.4
Name: pywattson
Version: 0.4.5
Summary: Scientifically rigorous delta-based energy profiling for Linux workloads
License-Expression: MIT
Keywords: energy,profiling,rapl,nvml,power,gpu
Requires-Python: >=3.12,<3.13
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Provides-Extra: torch
Requires-Dist: numpy (>=1.24)
Requires-Dist: psutil (>=5.9)
Requires-Dist: pynvml (>=11.5)
Requires-Dist: torch (>=2.0) ; extra == "torch"
Description-Content-Type: text/markdown

# pywattson

[![PyPI](https://img.shields.io/pypi/v/pywattson)](https://pypi.org/project/pywattson/)
[![Python 3.12+](https://img.shields.io/pypi/pyversions/pywattson)](https://pypi.org/project/pywattson/)
[![CI](https://github.com/YOUR_ORG/wattson/actions/workflows/ci.yml/badge.svg)](https://github.com/YOUR_ORG/wattson/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Scientifically rigorous, low-overhead, delta-based energy profiling for Linux
workloads — video codecs, ML inference, or anything else.

```bash
pip install pywattson
```

## Quick Start

### Context Manager (primary)

```python
from wattson import EnergyMonitor, BaselineStrategy

with EnergyMonitor(
    gpu_device_indices=0,
    metadata={"codec": "DCVC-RT", "qp": 42, "gop": 32},
    include_dram=True,
    baseline=BaselineStrategy.SEPARATE_SESSION,
) as monitor:
    run_codec_encode(...)

result = monitor.result
print(result.total_energy_j)
print(result.to_csv_row())
```

### Decorator

```python
from wattson import EnergyMonitor

@EnergyMonitor.profile(metadata={"codec": "x265"})
def encode():
    ...
```

### N-Repetition Research Driver

```python
from wattson import run_energy, BaselineStrategy

stats = run_energy(
    workload=encode,          # or command="python encode.py"
    n_repeats=15,
    n_warmup=2,
    gpu_device_indices=0,
    baseline=BaselineStrategy.SEPARATE_SESSION,
    metadata={"codec": "VVC"},
)

print(stats["stats"]["total_energy_j"]["median"])
print(stats["stats"]["total_energy_j"]["iqr"])
```

## Scientific Methodology

### Why Delta Counters, Not Power Sampling

Wattson reads hardware energy counters **before** and **after** a workload and
computes the difference.  This pure-delta approach avoids the sampling error
and timing jitter inherent in `power × time` integration.

### RAPL Domains

- **Package** — total socket energy (cores + uncore).
- **DRAM** — memory energy on its own power plane (not double-counted with
  package).
- Counters are 32-bit; overflow is corrected automatically:
  `corrected_delta = (max_uj − start_uj) + end_uj`.

### NVML Calibration

Some GPU drivers underreport or overreport the firmware energy counter.
Wattson's `calibrate()` method compares the counter against integrated
`nvmlDeviceGetPowerUsage()` and warns if they diverge by more than 20%.

### Thermal Bias & BaselineStrategy

Measuring idle **after** a workload gives a thermally elevated baseline.
Wattson defaults to `SEPARATE_SESSION` — idle is measured once in a cool state
**before** any workload runs.  Duration normalisation corrects for
`time.sleep()` scheduler overshoot.

### Multi-Tenant Caveat

RAPL counters are socket-wide.  If other processes share the CPU socket,
their energy is included.  For accurate measurements, use a dedicated machine
or account for background load.

## Versioning

This project uses [Conventional Commits](https://www.conventionalcommits.org/)
and [Release Please](https://github.com/googleapis/release-please) for
automated semantic versioning and changelogs.

- `fix:` → patch bump
- `feat:` → minor bump
- `feat!:` or `BREAKING CHANGE:` → major bump

## License

[MIT](LICENSE)

