mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-07-30 23:55:59 +00:00
chore(profiling): add append_profiling_history function for persistent profiling records
Adds two new functions to harness.py: - _current_git_ref(): Gets the current git short SHA - append_profiling_history(): Appends JSON line to profiling/results/history.jsonl This enables profiling numbers to persist across sessions/dates, with every run appended to an immutable timeline rather than overwriting per-stage snapshots. Also adds corresponding test to verify the function writes valid JSON lines. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
91647eecb5
commit
0506dcad05
@@ -1,8 +1,13 @@
|
||||
# profiling/harness.py
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Any
|
||||
from typing import Generic
|
||||
@@ -17,6 +22,8 @@ if TYPE_CHECKING:
|
||||
|
||||
from django.db.models import QuerySet
|
||||
|
||||
from profiling.seed import ScaleProfile
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
@@ -65,3 +72,52 @@ def capture_explain_analyze(queryset: QuerySet[Any]) -> str:
|
||||
with connection.cursor() as cur:
|
||||
cur.execute(f"EXPLAIN ANALYZE {sql}", params)
|
||||
return "\n".join(row[0] for row in cur.fetchall())
|
||||
|
||||
|
||||
def _current_git_ref() -> str:
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--short", "HEAD"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
return result.stdout.strip() or "unknown"
|
||||
|
||||
|
||||
def append_profiling_history(
|
||||
*,
|
||||
stage: str,
|
||||
scenario: str,
|
||||
best_seconds: float,
|
||||
query_count: int,
|
||||
scale: ScaleProfile,
|
||||
code_ref: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Append one line to profiling/results/history.jsonl -- an append-only,
|
||||
cross-session record of every profiling run. Unlike the per-stage
|
||||
before/after snapshot JSON files (which the next run of the same stage
|
||||
overwrites), this never gets clobbered, so a profiling effort picked
|
||||
back up days later has a full timeline to resume from instead of only
|
||||
the single most recent comparison.
|
||||
|
||||
``code_ref`` should identify the *production* code under test (a short
|
||||
SHA on the feature branch, not this `profiling` branch) -- pass it
|
||||
explicitly when known. Left as ``None``, it falls back to this repo's
|
||||
current ``git rev-parse --short HEAD``, which is only meaningful if
|
||||
you're actually running from a checkout where that reflects the code
|
||||
being measured.
|
||||
"""
|
||||
results_dir = Path(__file__).parent / "results"
|
||||
results_dir.mkdir(exist_ok=True)
|
||||
entry = {
|
||||
"timestamp": datetime.now(UTC).isoformat(),
|
||||
"code_ref": code_ref or _current_git_ref(),
|
||||
"stage": stage,
|
||||
"scenario": scenario,
|
||||
"scale": scale,
|
||||
"best_seconds": best_seconds,
|
||||
"query_count": query_count,
|
||||
}
|
||||
with (results_dir / "history.jsonl").open("a") as f:
|
||||
f.write(json.dumps(entry) + "\n")
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# profiling/test_harness_self_check.py
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from profiling.harness import append_profiling_history
|
||||
from profiling.harness import require_postgres
|
||||
from profiling.harness import run_profile
|
||||
from profiling.seed import seed_permission_dataset
|
||||
@@ -44,3 +48,27 @@ def test_run_profile_reports_query_count_and_timing() -> None:
|
||||
assert result.best_seconds >= 0
|
||||
assert len(result.all_seconds) == 3
|
||||
assert result.query_count >= 1
|
||||
|
||||
|
||||
def test_append_profiling_history_writes_a_valid_json_line() -> None:
|
||||
history_path = Path(__file__).parent / "results" / "history.jsonl"
|
||||
before_lines = (
|
||||
history_path.read_text().splitlines() if history_path.exists() else []
|
||||
)
|
||||
|
||||
append_profiling_history(
|
||||
stage="self-check",
|
||||
scenario="test_append_profiling_history_writes_a_valid_json_line",
|
||||
best_seconds=0.001,
|
||||
query_count=0,
|
||||
scale="medium",
|
||||
code_ref="test-run",
|
||||
)
|
||||
|
||||
after_lines = history_path.read_text().splitlines()
|
||||
assert len(after_lines) == len(before_lines) + 1
|
||||
entry = json.loads(after_lines[-1])
|
||||
assert entry["stage"] == "self-check"
|
||||
assert entry["code_ref"] == "test-run"
|
||||
assert entry["scale"] == "medium"
|
||||
assert "timestamp" in entry
|
||||
|
||||
Reference in New Issue
Block a user