Skip to content

Use per-future observed CPU/GPU metrics in runtime persistence#15

Merged
Saaketh0 merged 7 commits into
mainfrom
copilot/update-gpu-cpu-metrics
Jul 21, 2026
Merged

Use per-future observed CPU/GPU metrics in runtime persistence#15
Saaketh0 merged 7 commits into
mainfrom
copilot/update-gpu-cpu-metrics

Conversation

Copilot AI commented Jul 21, 2026

Copy link
Copy Markdown

CPU/GPU values written to runtime_information were coming from static YAML allocations, so persisted metrics did not reflect actual per-future usage. This change records observed metrics at execution time and makes the SQL upsert path prefer observed future data over config fallbacks.

  • Runtime metric capture in LocalController

    • LocalController._execute_locally(...) now records per-future:
      • execution_time (wall-clock duration)
      • cpu_resource (thread CPU utilization percentage)
      • gpu_resource (GPU memory used by process via nvidia-smi, with safe 0.0 fallback when unavailable)
    • Metrics are written directly to the future:<id> Redis hash for downstream ingestion.
  • Observed-metric precedence in SQL upsert

    • ventis/controller/utils/sqlalchemy.py::send_data(...) now reads execution_time, cpu_resource, and gpu_resource from each future row when present.
    • Existing resources_by_agent values remain as fallback defaults only.
    • Added safe float parsing and non-negative normalization to avoid malformed/negative persisted values.
  • Focused coverage for precedence behavior

    • Added a targeted test in tests/test_runtime_sqlalchemy.py validating that observed Redis metrics override static config allocations.
execution_time = _safe_float(raw.get("execution_time"), end - start)
cpu_resource = _safe_float(raw.get("cpu_resource"), _safe_float(res.get("cpu"), 0))
gpu_resource = _safe_float(raw.get("gpu_resource"), _safe_float(res.get("gpu"), 0))

Summary by CodeRabbit

  • New Features

    • Added CPU usage tracking for locally completed executions.
    • Runtime records now report observed CPU usage and configured GPU resources.
    • Execution duration is recorded from the actual start and completion times.
  • Tests

    • Added coverage verifying execution timing and CPU/GPU resource values.

Copilot AI changed the title [WIP] Implement more specific GPU/CPU metrics tracking Use per-future observed CPU/GPU metrics in runtime persistence Jul 21, 2026
Copilot AI requested a review from Saaketh0 July 21, 2026 01:05
Comment thread ventis/controller/utils/sqlalchemy.py Outdated
try:
return float(value)
except (TypeError, ValueError):
return float(fallback)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Do not need _safe_float() function, remove it

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 6546ad9. I removed _safe_float() from ventis/controller/utils/sqlalchemy.py and inlined the float parsing/fallback logic in send_data(...) while preserving observed-metric precedence.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Runtime resource persistence

Layer / File(s) Summary
Local execution metric capture
ventis/controller/local_controller.py
Local execution now records wall-clock completion time and computes thread CPU usage as a percentage before persisting metrics to Redis.
Observed and configured resource upsert
ventis/controller/utils/sqlalchemy.py, tests/test_runtime_sqlalchemy.py
send_data persists observed CPU and configured GPU values, with tests verifying resource selection and execution time calculations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LocalController
  participant Redis
  participant send_data
  participant SQLAlchemy
  LocalController->>LocalController: measure wall and thread CPU time
  LocalController->>Redis: store finished_at and cpu_resource
  send_data->>Redis: read runtime metrics
  send_data->>SQLAlchemy: upsert observed CPU and configured GPU
  SQLAlchemy-->>send_data: persist runtime_information
Loading

Possibly related PRs

Suggested reviewers: saaketh0

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: runtime persistence now uses observed per-future CPU/GPU metrics.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch copilot/update-gpu-cpu-metrics

Comment @coderabbitai help to get the list of available commands.

Copilot AI requested a review from Saaketh0 July 21, 2026 17:31
Comment thread ventis/controller/utils/sqlalchemy.py Outdated
Comment thread ventis/controller/local_controller.py Outdated
POLICY_RULES_KEY = "policy:rules"


def _read_gpu_memory_for_pid(pid):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this function and all GPU logic, just keep CPU logic and make GPU pull from the .yaml file still and be set to 0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 1365697: removed the GPU observation function and related GPU runtime logic from local_controller.py; runtime GPU now comes from configured resources.

Comment thread ventis/controller/utils/sqlalchemy.py
Comment thread ventis/controller/local_controller.py Outdated
"execution_time": execution_time,
"cpu_resource": cpu_percent,
},
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Remove traces of execution_time from this. Only should hset cpu_resource

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in fffdd36: removed execution_time from the runtime hash metric write; this block now only hsets cpu_resource.

Comment thread ventis/controller/utils/sqlalchemy.py Outdated
"execution_time": end - start,
"cpu_resource": float(res.get("cpu", 0)),
"gpu_resource": float(res.get("gpu", 0)),
"execution_time": execution_time,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Remove line 80 and just move end-start to this line, no need to define variable earlier, the initial logic was good

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 2c29205: removed the earlier execution_time variable and now bind execution_time directly as end - start in the upsert payload.

@Saaketh0 Saaketh0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@Saaketh0

Copy link
Copy Markdown
Collaborator

Added CPU Usage Metric to the DB ingestion.
Skipped out on GPU Metrics because for the time being all instances we are using have 0 GPU, and extra logic is needed to calculate the metrics based on the type of GPU being used (NVIDIA, Intel, AWS, etc..)

@Saaketh0
Saaketh0 marked this pull request as ready for review July 21, 2026 18:22
@coderabbitai
coderabbitai Bot requested a review from Saaketh0 July 21, 2026 18:23
@Saaketh0
Saaketh0 merged commit a1f75a2 into main Jul 21, 2026
3 of 4 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ventis/controller/local_controller.py`:
- Around line 467-474: Update the completion writes in the pull_data completion
path to publish finished_at and cpu_resource atomically via one Redis
hset_multiple call. Ensure ingestion cannot observe a populated future hash with
finished_at present but without the calculated CPU metric, while preserving the
existing wall-duration and CPU-percentage calculations.

In `@ventis/controller/utils/sqlalchemy.py`:
- Around line 80-81: Normalize cpu_resource and gpu_resource immediately after
conversion and before the UPSERT, ensuring both observed CPU and configured GPU
values cannot persist as negative metrics. Use the existing resource-processing
flow to clamp them to zero or reject invalid values consistently, while
preserving valid non-negative values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 916d75b1-461f-46ff-ab9a-a770386902ce

📥 Commits

Reviewing files that changed from the base of the PR and between 1aac0d5 and 2c29205.

📒 Files selected for processing (3)
  • tests/test_runtime_sqlalchemy.py
  • ventis/controller/local_controller.py
  • ventis/controller/utils/sqlalchemy.py

Comment on lines +467 to +474
wall_end = time.time()
self.redis.hset(f"future:{future_id}", "finished_at", wall_end)

wall_duration = max(wall_end - wall_start, 0.0)
cpu_seconds = max(time.thread_time() - thread_cpu_start, 0.0)
cpu_percent = (cpu_seconds / wall_duration * 100.0) if wall_duration else 0.0

self.redis.hset(f"future:{future_id}", "cpu_resource", cpu_percent)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Publish completion metrics atomically.

pull_data() scans any populated future:* hash, while send_data() falls back to configured CPU when cpu_resource is absent. Lines 468 and 474 use separate Redis commands, so ingestion can observe finished_at without the observed CPU and persist the static fallback.

Use one hset_multiple completion write, or make ingestion ignore hashes until finished_at is present and retry partial records.

Proposed fix
-        self.redis.hset(f"future:{future_id}", "finished_at", wall_end)
-
         wall_duration = max(wall_end - wall_start, 0.0)
         cpu_seconds = max(time.thread_time() - thread_cpu_start, 0.0)
         cpu_percent = (cpu_seconds / wall_duration * 100.0) if wall_duration else 0.0

-        self.redis.hset(f"future:{future_id}", "cpu_resource", cpu_percent)
+        self.redis.hset_multiple(
+            f"future:{future_id}",
+            {"finished_at": wall_end, "cpu_resource": cpu_percent},
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/local_controller.py` around lines 467 - 474, Update the
completion writes in the pull_data completion path to publish finished_at and
cpu_resource atomically via one Redis hset_multiple call. Ensure ingestion
cannot observe a populated future hash with finished_at present but without the
calculated CPU metric, while preserving the existing wall-duration and
CPU-percentage calculations.

Comment on lines +80 to +81
cpu_resource = float(raw.get("cpu_resource") or res.get("cpu", 0))
gpu_resource = float(res.get("gpu", 0))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Normalize resource values before persistence.

float() accepts negative observed CPU and configured GPU values, allowing malformed Redis/configuration data to write negative resource metrics. Clamp or reject both values before the UPSERT.

Proposed fix
-            cpu_resource = float(raw.get("cpu_resource") or res.get("cpu", 0))
-            gpu_resource = float(res.get("gpu", 0))
+            cpu_resource = max(
+                float(raw.get("cpu_resource") or res.get("cpu", 0)), 0.0
+            )
+            gpu_resource = max(float(res.get("gpu", 0)), 0.0)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cpu_resource = float(raw.get("cpu_resource") or res.get("cpu", 0))
gpu_resource = float(res.get("gpu", 0))
cpu_resource = max(
float(raw.get("cpu_resource") or res.get("cpu", 0)), 0.0
)
gpu_resource = max(float(res.get("gpu", 0)), 0.0)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/utils/sqlalchemy.py` around lines 80 - 81, Normalize
cpu_resource and gpu_resource immediately after conversion and before the
UPSERT, ensuring both observed CPU and configured GPU values cannot persist as
negative metrics. Use the existing resource-processing flow to clamp them to
zero or reject invalid values consistently, while preserving valid non-negative
values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GPU/CPU metrics need to be more specific for each future

2 participants