kempnerpulse.present

KempnerPulse Layer 4 — Present.

The terminal UI and CSV export. This layer consumes ComputedRecord objects (canonical metric values plus the derived Real Utilization / classification / health signals) and renders them — it converts canonical fractions/SI to display units (percent, GB/s, …) itself and never reaches back into source vocabulary.

Public API

Rendering / interaction:

  • render_dashboard(records, history, *, console_width, console_height, controller, summary_context) -> Layout — assemble one dashboard frame.

  • SummaryContext — the per-frame context (system stats, source/poll labels, weight preset, hardware limits, job listing) the dashboard needs beyond the records. The lifecycle layer builds this.

  • CommandController / cbreak_stdin(enabled) — keyboard command state and the raw-terminal context manager.

  • HistoryStore / update_history(history, records) — the rolling per-GPU display-unit time-series store and its record→series adapter.

  • GpuProcess — a Job-View process row (built by the lifecycle layer).

CSV export:

  • resolve_columns(spec) -> [(name, extractor), ...] — resolve "default" / "all" / a comma-list to an ordered column set.

  • csv_header(columns) -> [str] and csv_row(record, timestamp, columns) -> [str] — emit the header and one row, with units/precision matching the documented export schema.

  • UnknownExportColumns — raised by resolve_columns on a bad spec.

kempnerpulse.present.render_dashboard(records, history, *, console_width, console_height, controller, summary_context)[source]

Assemble the full dashboard Layout for one frame.

Returns a Rich renderable (a Layout). Below the per-card minimum size it returns a ‘widen me’ gate instead of squeezed cards. View selection follows controller (plot / job / focus / fleet).

Parameters:
Return type:

Layout

class kempnerpulse.present.SummaryContext[source]

Bases: object

Everything the summary bar, footer, and view panels need besides the per-frame records/history/controller/dimensions.

The lifecycle layer builds one of these each frame (or reuses a mostly-static one and refreshes the volatile system fields). All fields have sensible defaults so a minimal caller can pass SummaryContext().

source: str = ''
poll: float = 1.0
selection_desc: str = 'all'
weights: Tuple[float, float, float, float] = (0.35, 0.35, 0.2, 0.1)
app_version: str = ''
cpu_info: Tuple[int | None, int | None, float | None, int | None] = (None, None, None, None)
ram_info: Tuple[float | None, float | None] = (None, None)
power_limits: Dict[str, float]
pcie_bw_limits: Dict[str, float]
pcie_info: str = ''
gpu_processes: Dict[str, List[GpuProcess]]
__init__(source='', poll=1.0, selection_desc='all', weights=(0.35, 0.35, 0.2, 0.1), app_version='', cpu_info=(None, None, None, None), ram_info=(None, None), power_limits=<factory>, nvlink_bw_limits=<factory>, pcie_bw_limits=<factory>, pcie_info='', gpu_processes=<factory>)
Parameters:
Return type:

None

class kempnerpulse.present.CommandController[source]

Bases: object

View-mode and input state shared between the input loop and the renderer.

__init__(initial_focus=None)[source]
Parameters:

initial_focus (str | None)

hint()[source]
Return type:

str

scroll_fleet(delta)[source]

Adjust the fleet scroll offset; the renderer clamps the upper bound.

Parameters:

delta (int)

Return type:

None

handle_input(available_gpu_ids)[source]

Drain any pending stdin and apply it; a no-op without a TTY.

Parameters:

available_gpu_ids (Set[str])

Return type:

None

kempnerpulse.present.cbreak_stdin(enabled)[source]

Put stdin into cbreak mode for single-keystroke input; no-op off-TTY.

Parameters:

enabled (bool)

class kempnerpulse.present.HistoryStore[source]

Bases: object

Fixed-capacity per-(gpu, key) ring buffers of floats.

__init__(maxlen=120)[source]
Parameters:

maxlen (int)

push(gpu_id, key, value)[source]

Append value to the (gpu_id, key) series (oldest drops out).

Parameters:
Return type:

None

get(gpu_id, key)[source]

Return the (gpu_id, key) series, or an empty deque if absent.

Parameters:
Return type:

Deque[float]

kempnerpulse.present.update_history(history, records)[source]

Push one batch of records’ display-unit series into history.

All conversions to display units happen here: percents come from canonical fractions ×100, NVLink GB/s from canonical bytes/second ÷1e9. A series is skipped (not zero-filled) whenever its canonical source is None.

Parameters:
Return type:

None

class kempnerpulse.present.GpuProcess[source]

Bases: object

A single compute process running on a GPU (for the Job View).

pid: int
user: str
gid: str
gpu_id: str
gpu_mem_mib: float | None
command: str
__init__(pid, user, gid, gpu_id, gpu_mem_mib, command)
Parameters:
Return type:

None

kempnerpulse.present.resolve_columns(spec)[source]

Resolve an export spec to an ordered list of (name, extractor).

spec is "default", "all", or a comma-separated list of column names. Unknown names raise UnknownExportColumns (the caller decides how to surface it — this layer does not exit the process).

Parameters:

spec (str)

Return type:

List[Tuple[str, Callable[[ComputedRecord, float], str]]]

kempnerpulse.present.csv_header(columns)[source]

The header row (column names) for a resolved column list.

Parameters:

columns (Sequence[Tuple[str, Callable[[ComputedRecord, float], str]]])

Return type:

List[str]

kempnerpulse.present.csv_row(record, timestamp, columns)[source]

One CSV row for record at timestamp over the resolved columns.

Parameters:
Return type:

List[str]

exception kempnerpulse.present.UnknownExportColumns[source]

Bases: ValueError

One or more requested export columns are not in the registry.

__init__(bad)[source]
Parameters:

bad (Sequence[str])

kempnerpulse.present.footer_panel(selection_desc, controller, source='', poll=1.0, weights=(0.35, 0.35, 0.2, 0.1), console_width=200)[source]
Parameters:
Return type:

Panel

Modules

controller

Keyboard command handling and the raw-terminal context manager.

csv_writer

CSV export — the column registry keyed to ComputedRecord/canonical.

format

Display formatting, styling, and canonical→display unit conversion.

history

Per-GPU rolling time-series store and the record→series adapter.

tui

Dashboard assembly: the footer, the render-context, and render_dashboard.

widgets

Rich panels and the line-plot renderable.