Skip to content

perf(loki.source.file): Reduce allocations during file reading#5405

Merged
kalleep merged 3 commits intomainfrom
kalleep/perf-file-tailing
Feb 2, 2026
Merged

perf(loki.source.file): Reduce allocations during file reading#5405
kalleep merged 3 commits intomainfrom
kalleep/perf-file-tailing

Conversation

@kalleep
Copy link
Contributor

@kalleep kalleep commented Jan 30, 2026

Pull Request Details

There is a lot of allocations being performed while reading files. I can clearly see this being a hot spot in our internal clusters.

Two of the biggest issues are:

  1. We allocate a new pending buffer as soon as we have completed a line
  2. We use ReadBytes api causing new allocation for every call that we just move to pending

Instead we can use ReadSlice, this api will not allocate but return a slice pointing to the internal buffer while still advancing read position. We copy it into pending so this is fine and we remove the intermediate allocation done by ReadBytes.

We can also reset length of pending and this buffer. This is fine because we never read past newline boundary.

Issue(s) fixed by this Pull Request

Notes to the Reviewer

PR Checklist

  • Documentation added
  • Tests updated
  • Config converters updated

@kalleep kalleep requested a review from a team as a code owner January 30, 2026 15:47
@kalleep
Copy link
Contributor Author

kalleep commented Jan 30, 2026

Benchmark diff against main

goos: linux
goarch: amd64
pkg: github.com/grafana/alloy/internal/component/loki/source/file/internal/tail
cpu: AMD Ryzen 7 8845HS w/ Radeon 780M Graphics
        │ bench_old.txt │            bench_new.txt             │
        │    sec/op     │    sec/op     vs base                │
File-16   1287.0µ ± 19%   410.5µ ± 57%  -68.10% (p=0.000 n=10)

        │ bench_old.txt │            bench_new.txt             │
        │     B/op      │     B/op      vs base                │
File-16   5057.0Ki ± 0%   557.0Ki ± 0%  -88.99% (p=0.000 n=10)

        │ bench_old.txt │            bench_new.txt            │
        │   allocs/op   │  allocs/op   vs base                │
File-16     4.022k ± 0%   2.022k ± 0%  -49.73% (p=0.000 n=10)

@kalleep kalleep added publish-dev:linux builds and deploys an image to grafana/alloy-dev container repository and removed publish-dev:linux builds and deploys an image to grafana/alloy-dev container repository labels Jan 30, 2026
@kalleep kalleep force-pushed the kalleep/perf-file-tailing branch from d264307 to b013c1b Compare February 1, 2026 20:02
@kalleep kalleep added publish-dev:linux builds and deploys an image to grafana/alloy-dev container repository and removed publish-dev:linux builds and deploys an image to grafana/alloy-dev container repository labels Feb 1, 2026
@kalleep kalleep requested a review from Copilot February 2, 2026 07:47
@kalleep kalleep force-pushed the kalleep/perf-file-tailing branch from b013c1b to e50714d Compare February 2, 2026 07:50
Copy link
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

Reduces allocation pressure in the Loki file tailer’s line-reading path by reusing buffers and avoiding per-read allocations from bufio.Reader.

Changes:

  • Switch line reading from ReadBytes to ReadSlice and adjust looping/error handling to reduce intermediate allocations.
  • Reuse the pending buffer by resetting length instead of allocating new slices on each consumed line/flush.
  • Update test helpers to accept testing.TB and add a benchmark to track allocations.

Reviewed changes

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

File Description
internal/component/loki/source/file/internal/tail/reader.go Uses ReadSlice and buffer resets to reduce allocations while reading/consuming lines; fixes an error-return bug in reset.
internal/component/loki/source/file/internal/tail/file_test.go Refactors helper signatures for TB compatibility and adds a benchmark for allocation tracking.

@kalleep kalleep added the backport/v1.13 Backport to release/v1.13 label Feb 2, 2026
@kalleep kalleep merged commit 899467a into main Feb 2, 2026
52 checks passed
@kalleep kalleep deleted the kalleep/perf-file-tailing branch February 2, 2026 10:32
@grafana-alloybot
Copy link
Contributor

⚠️ Automatic backport to release/v1.13 failed

The automatic backport for this PR failed, likely due to merge conflicts. Perform the backport manually:

git fetch origin main release/v1.13
git checkout release/v1.13
git pull
git checkout -b backport/pr-5405-to-v1.13
git cherry-pick -x 899467aefc97088471f79e03bcfc7a226e420cdd
# If conflicts exist, fix them, then:
git add .
git commit
# If no [more] conflicts, then:
git push -u origin backport/pr-5405-to-v1.13

Then create a PR from backport/pr-5405-to-v1.13 to release/v1.13 with the title:

perf(loki.source.file): Reduce allocations during file reading [backport]

@kalleep kalleep added backport/v1.13 Backport to release/v1.13 and removed backport/v1.13 Backport to release/v1.13 labels Feb 2, 2026
grafana-alloybot bot pushed a commit that referenced this pull request Feb 2, 2026
### Pull Request Details
There is a lot of allocations being performed while reading files. I can
clearly see this being a hot spot in our internal clusters.

Two of the biggest issues are:
1. We allocate a new pending buffer as soon as we have completed a line
2. We use ReadBytes api causing new allocation for every call that we
just move to pending

Instead we can use `ReadSlice`, this api will not allocate but return a
slice pointing to the internal buffer while still advancing read
position. We copy it into pending so this is fine and we remove the
intermediate allocation done by `ReadBytes`.

We can also reset length of `pending` and this buffer. This is fine
because we never read past newline boundary.

### Issue(s) fixed by this Pull Request

<!-- Fixes #issue_id -->

### Notes to the Reviewer

<!-- Add any relevant notes for the reviewers and testers of this PR.
-->

### PR Checklist

<!-- Remove items that do not apply. For completed items, change [ ] to
[x]. -->

- [ ] Documentation added
- [x] Tests updated
- [ ] Config converters updated

(cherry picked from commit 899467a)
kalleep added a commit that referenced this pull request Feb 2, 2026
…ort] (#5416)

## Backport of #5405

This PR backports #5405 to release/v1.13.

### Original PR Author
@kalleep

### Description
### Pull Request Details
There is a lot of allocations being performed while reading files. I can
clearly see this being a hot spot in our internal clusters.

Two of the biggest issues are:
1. We allocate a new pending buffer as soon as we have completed a line
2. We use ReadBytes api causing new allocation for every call that we
just move to pending

Instead we can use `ReadSlice`, this api will not allocate but return a
slice pointing to the internal buffer while still advancing read
position. We copy it into pending so this is fine and we remove the
intermediate allocation done by `ReadBytes`.

We can also reset length of `pending` and this buffer. This is fine
because we never read past newline boundary.

### Issue(s) fixed by this Pull Request

<!-- Fixes #issue_id -->

### Notes to the Reviewer

<!-- Add any relevant notes for the reviewers and testers of this PR.
-->

### PR Checklist

<!-- Remove items that do not apply. For completed items, change [ ] to
[x]. -->

- [ ] Documentation added
- [x] Tests updated
- [ ] Config converters updated


---
*This backport was created automatically.*

Co-authored-by: Karl Persson <23356117+kalleep@users.noreply.github.com>
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 17, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

backport/v1.13 Backport to release/v1.13 frozen-due-to-age publish-dev:linux builds and deploys an image to grafana/alloy-dev container repository

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants