Skip to content

Optimize ML prediction hot path: circular buffer and reduce allocations#22042

Open
stelfrag wants to merge 16 commits intonetdata:masterfrom
stelfrag:0_improve_ml
Open

Optimize ML prediction hot path: circular buffer and reduce allocations#22042
stelfrag wants to merge 16 commits intonetdata:masterfrom
stelfrag:0_improve_ml

Conversation

@stelfrag
Copy link
Copy Markdown
Collaborator

@stelfrag stelfrag commented Mar 25, 2026

Summary
  • Replace std::rotate with a circular buffer for collected samples, change the per-dimension feature vector from heap-allocated std::vector to an inline DSample, and add a dedicated prediction preprocessing path that skips training-only logic.
  • Change preprocessed_features from reference to nullable pointer so the prediction path avoids constructing a throwaway vector on every tick.

Summary by cubic

Speeds up the ML prediction hot path with a ring buffer, unified prediction preprocessing, and simpler APIs to reduce allocations. Adds strict input validation and normalizes smoothing to keep state consistent and accurate.

  • Refactors

    • Replace rotating vectors with a ring buffer for dim->cns; linearize from cns_head; rebuild (clear and reset head) when the effective smoothing window changes or wrapped state is incompatible; use fatal_assert for static buffer checks.
    • Unify feature preprocessing/APIs: add ml_features_preprocess_predict that fills a single DSample; training uses ml_features_preprocess(features, out) and ml_kmeans_train(kmeans, out); store one DSample on ml_dimension_t; compute per-dimension windows via ml_dimension_smoothing_window.
    • Validate inputs in preprocessing/prediction to enforce buffer sizes and minimum samples using the effective smoothing window.
  • Bug Fixes

    • Compare against the newest sample in the ring buffer to classify constant vs variable correctly; unit test added.
    • Normalize smooth_n=0 to behave like smooth_n=1 across preprocessing and prediction; unit test ensures consistency.
    • Reset cns/cns_head on missing values and host stop to avoid stale indexing.
    • Ensure build compatibility with -std=gnu++14.

Written for commit 69045e4. Summary will update on new commits.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 6 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant API as ML API (ml.cc)
    participant Dim as ml_dimension_t (State)
    participant Feat as ML Features (Preprocessing)
    participant KM as ML KMeans (Model)
    participant Worker as ML Worker (Training Cache)

    alt Prediction Flow (Hot Path)
        API->>Dim: NEW: Update circular buffer at cns_head
        Dim->>Dim: Increment cns_head (wrap around)
        
        API->>API: Reconstruct contiguous cns array from ring buffer
        
        API->>Feat: NEW: ml_features_preprocess_predict()
        Feat->>Feat: ml_features_diff()
        Feat->>Feat: ml_features_smooth()
        Feat-->>Dim: NEW: Fill inline DSample (dim->feature)
        Note right of Feat: Skips lag step & heap allocations
        
        loop for each KMeans context
            API->>KM: ml_kmeans_anomaly_score(dim->feature)
            KM-->>API: anomaly_score
        end
    else Training Flow
        API->>Worker: Access training_samples scratchpad
        
        API->>Feat: CHANGED: ml_features_preprocess()
        Note right of API: Passes &worker->training_samples (Pointer)
        
        Feat->>Feat: ml_features_diff()
        Feat->>Feat: ml_features_smooth()
        Feat->>Feat: CHANGED: ml_features_lag()
        Feat-->>Worker: Populate training_samples vector
        
        API->>KM: CHANGED: ml_kmeans_train()
        Note right of KM: Dereferences preprocessed_features pointer
        KM->>Worker: Read training samples
        KM-->>Dim: Update KMeans model
    end

    opt Missing Data
        API->>Dim: NEW: Reset cns_head = 0
        API->>Dim: Clear cns buffer
    end
Loading

@github-actions github-actions bot added the area/ml Machine Learning Related Issues label Mar 25, 2026
…ar buffer, optimize feature preprocessing, and improve memory management.
@stelfrag stelfrag marked this pull request as ready for review March 26, 2026 07:54
@stelfrag stelfrag requested a review from vkalintiris as a code owner March 26, 2026 07:54
Copilot AI review requested due to automatic review settings March 26, 2026 07:54
@stelfrag stelfrag marked this pull request as draft March 26, 2026 07:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Optimizes the ML prediction hot path by switching from std::rotate to a circular buffer, inlining the per-dimension feature sample, and adding a prediction-specific preprocessing function to avoid per-tick allocations and training-only work.

Changes:

  • Replace rotating sample history with a ring buffer (cns_head) and reconstruct contiguous arrays for preprocessing.
  • Add ml_features_preprocess_predict() to build a single DSample for prediction without creating a std::vector<DSample>.
  • Change ml_features_t.preprocessed_features from a reference to a nullable pointer so prediction can pass nullptr.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/ml/ml_public.cc Resets cns_head on host stop to keep the ring buffer consistent.
src/ml/ml_kmeans.cc Updates k-means training to dereference preprocessed_features via pointer.
src/ml/ml_features.h Makes preprocessed_features nullable and adds ml_features_preprocess_predict().
src/ml/ml_features.cc Implements prediction-only preprocessing and updates lag preprocessing to use the pointer.
src/ml/ml_dimension.h Adds cns_head and inlines feature as a single DSample.
src/ml/ml.cc Switches prediction path to ring buffer + prediction preprocess + inline DSample.
src/ml/ml-unittest.cc Updates unit tests for the preprocessed_features pointer API.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Add null checks for `preprocessed_features` in preprocessing and k-means training.
- Avoid crashes in `ml_kmeans_train` when features are uninitialized.
- Fix logical error in value comparison during circular buffer update.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/ml/ml.cc">

<violation number="1" location="src/ml/ml.cc:780">
P2: Compare against the most recent sample, not the oldest element at cns_head. Using cns_head here misclassifies whether the incoming value matches the latest value.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@stelfrag stelfrag marked this pull request as ready for review March 26, 2026 08:41
- Resolve logical error in determining the newest index for value comparison during circular buffer updates.
@stelfrag stelfrag requested a review from Copilot March 26, 2026 09:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Compare incoming value against the newest sample instead of the oldest.
- Prevent misclassification of constant vs variable dimensions during training and statistics reporting.
- Ensure reliable detection of transitions in changing series.
@stelfrag stelfrag requested a review from Copilot March 26, 2026 09:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/ml/ml.cc:1

  • The stack buffers src_cns/dst_cns are sized to 128 elements, but the assert still uses n * (Cfg.lag_n + 1) <= 128. After switching prediction to ml_features_preprocess_predict() (which does not perform lag expansion), this check can now falsely fail for valid n (e.g., n=64, lag_n=2), preventing prediction even though the buffers would be sufficient. Update the assert to validate the actual buffers used (e.g., n <= 128) or size the arrays based on the asserted expression.
// SPDX-License-Identifier: GPL-3.0-or-later

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…d improve memory safety

- Remove redundant pointer-based management of preprocessed features, replacing it with `std::vector` references for cleaner and safer memory handling.
- Update `ml_features_preprocess` and `ml_kmeans_train` to use direct vector references.
- Adjust all related test cases and logic to align with the refactored interfaces.
- Add unit test to validate correct comparison of the newest sample in `ml_dimension_predict`.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/ml/ml.cc:803

  • The static-buffer guard uses n * (Cfg.lag_n + 1) <= 128, but this prediction path only stores n calculated_numbers into src_cns/dst_cns and ml_features_preprocess_predict() reads at most lag_n + 1 values. Using the product makes the constraint harder to reason about and could become unnecessarily restrictive if feature window sizing changes. Prefer asserting the actual requirements (e.g., n <= 128 and lag_n + 1 <= n) to match the current memory bounds.
    // Create the sample
    assert((n * (Cfg.lag_n + 1) <= 128) &&
           "Static buffers too small to perform prediction. "
           "This should not be possible with the default clamping of feature extraction options");

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…in ML preprocessing

- Introduced `ml_effective_smooth_n` to handle `smooth_n=0` as equivalent to `smooth_n=1`.
- Updated smoothing logic for consistency across preprocessing and prediction.
- Added comprehensive unit test `test_features_zero_smooth_matches_one` to validate feature consistency for `smooth_n=0` and `smooth_n=1`.
@stelfrag stelfrag requested a review from thiagoftsm March 26, 2026 11:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Treat `smooth_n=0` as equivalent to a smoothing window of 1 across all paths.
- Update signature of `ml_features_preprocess_predict` to use `DSample` references instead of pointers for improved safety.
- Adjust tests, comments, and logic to reflect updated `smooth_n=0` behavior and interface changes.
@stelfrag stelfrag requested a review from Copilot March 26, 2026 13:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Ensure buffer clears and resets when smoothing window changes to maintain state consistency.
- Replace `assert` with `fatal_assert` for static buffer size validation during prediction.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Add `cns_size` optimization to reduce redundant size checks.
- Clarify logic for detecting effective window changes and resetting buffer state.
- Improve comments for consistency in ring buffer handling.
@stelfrag stelfrag requested a review from Copilot March 26, 2026 14:52
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/ml/ml.cc">

<violation number="1" location="src/ml/ml.cc:791">
P2: Rebuild the ring buffer whenever the effective window changes, even if the buffer is currently smaller than the new size. The new `cns_size >= n` guard skips the reset on window growth, leaving `cns_head` tied to the old modulus and corrupting sample order once the buffer refills.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/ml/ml-unittest.cc:489

  • The new ml_features_preprocess_predict() behavior is only directly exercised in test_features_zero_smooth_matches_one() (and only for a single small input/parameter set). test_preprocess_predict_equivalence() still validates a “manual extraction” path rather than calling ml_features_preprocess_predict() itself. To better lock in correctness, update that test to call ml_features_preprocess_predict() across the existing parameter sets/patterns and compare its DSample output to pf[0] from ml_features_preprocess().
static void test_preprocess_predict_equivalence()

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…tion paths

- Replace manual feature extraction logic in unit tests with `ml_features_preprocess_predict`.
- Add input validation via `ml_validate_features_input` to both training and prediction paths.
- Ensure consistent buffer validation and minimum sample checks across preprocessing functions.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

thiagoftsm
thiagoftsm previously approved these changes Mar 26, 2026
Copy link
Copy Markdown
Contributor

@thiagoftsm thiagoftsm left a comment

Choose a reason for hiding this comment

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

PR is working as expected. LGTM!

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

Labels

area/ml Machine Learning Related Issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants