Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance by for pid stats (cgroups1) re-using readuint #291

Merged
merged 1 commit into from
Jun 2, 2023

Conversation

manugupt1
Copy link
Contributor

cc @kolyshkin @dcantah

I re-used the optimized readuint in cgroups to improve performance. This should not change the behavior for max as readuint returns 0 and when a file is not present; an error is still returned.

PTAL

Benchstat results:

➜  cgroups git:(main) ✗ benchstat old.txt new.txt
goos: linux
goarch: amd64
pkg: github.com/containerd/cgroups/v3/cgroup1
cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
           │   old.txt   │              new.txt               │
           │   sec/op    │   sec/op     vs base               │
TestPids-8   19.32µ ± 4%   17.39µ ± 2%  -9.97% (p=0.000 n=10)

           │   old.txt   │              new.txt               │
           │    B/op     │    B/op     vs base                │
TestPids-8   1344.0 ± 0%   624.0 ± 0%  -53.57% (p=0.000 n=10)

           │  old.txt   │              new.txt               │
           │ allocs/op  │ allocs/op   vs base                │
TestPids-8   13.00 ± 0%   11.00 ± 0%  -15.38% (p=0.000 n=10)
➜  cgroups git:(main) ✗

@manugupt1 manugupt1 force-pushed the improve-perf branch 2 times, most recently from b6a34e0 to bd48e06 Compare April 28, 2023 05:09
@manugupt1 manugupt1 changed the title Improve performance by re-using readuint Improve performance by for pid stats (cgroups1) re-using readuint Apr 28, 2023
cgroup1/utils.go Outdated Show resolved Hide resolved
cgroup1/pids_test.go Outdated Show resolved Hide resolved
@@ -67,16 +66,10 @@ func (p *pidsController) Stat(path string, stats *v1.Metrics) error {
if err != nil {
return err
}
var max uint64
maxData, err := os.ReadFile(filepath.Join(p.Path(path), "pids.max"))
max, err := readUint(filepath.Join(p.Path(path), "pids.max"))
Copy link
Member

@dcantah dcantah Apr 28, 2023

Choose a reason for hiding this comment

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

Isn't the behavior different here? readUint should fail if "max" exists in the file as it only knows how to parse integers, so we'd bail on line 71. Before we'd carry on to filling in the stats, granted the max variable will be left as 0 it seems if "max" was in pids.max, but point being this method would still succeed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right; I changed readUint to return MaxUint64 now. The behavior is still different but it is consistent with cgroups2. I think this change should be fine now.

Copy link
Member

Choose a reason for hiding this comment

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

Yea it is odd to me how we returned 0 here before.. would need to see if any users relied on this behavior with a github search maybe..

Copy link
Member

@dcantah dcantah Apr 28, 2023

Choose a reason for hiding this comment

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

(I think returning MaxUint64 makes sense, but.. did anyone rely on this? It being 0 I mean, might wanna stay safe)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it makes sense at least for v3; v1 is imported by so many packages that I am not confident.

  1. https://pkg.go.dev/github.com/containerd/cgroups?tab=importedby
  2. https://pkg.go.dev/github.com/containerd/cgroups/v3@v3.0.1?tab=importedby

Thinking of reverting back to 0 and adding a comment to say that we preserve it for backward compatibility.
What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

I'd err on the side of staying safe, so your reasoning seems sane and I agree (also sorry for the radio silence here 🫠)

Copy link
Member

Choose a reason for hiding this comment

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

I suppose 0 could be interpreted as no limit, so that might've been the rationale

Copy link
Contributor

Choose a reason for hiding this comment

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

Zero wouldn't be a valid value anyway as zero, so that's a fair rationale.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dcantah No worries! thanks for the review! this was a really fun exercise :)
thanks @mmerkes for the review and helping building understanding

@manugupt1 manugupt1 force-pushed the improve-perf branch 6 times, most recently from 466bd86 to 83e12f7 Compare May 2, 2023 04:23
Benchstat results

➜  cgroups git:(main) ✗ benchstat old.txt new.txt
goos: linux
goarch: amd64
pkg: github.com/containerd/cgroups/v3/cgroup1
cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
           │   old.txt   │              new.txt               │
           │   sec/op    │   sec/op     vs base               │
TestPids-8   19.32µ ± 4%   17.39µ ± 2%  -9.97% (p=0.000 n=10)

           │   old.txt   │              new.txt               │
           │    B/op     │    B/op     vs base                │
TestPids-8   1344.0 ± 0%   624.0 ± 0%  -53.57% (p=0.000 n=10)

           │  old.txt   │              new.txt               │
           │ allocs/op  │ allocs/op   vs base                │
TestPids-8   13.00 ± 0%   11.00 ± 0%  -15.38% (p=0.000 n=10)
➜  cgroups git:(main) ✗

Signed-off-by: Manu Gupta <manugupt1@gmail.com>
Comment on lines +141 to +142
// We should only need 20 bytes for the max uint64, but for a nice power of 2
// lets use 32.
Copy link
Contributor

Choose a reason for hiding this comment

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

Per the original comment, is it realistic that this might have leading/trailing whitespace? Seems unlikely, but anyone who does would start breaking if they had a lot of it.

Copy link
Member

Choose a reason for hiding this comment

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

It seems the files simply have one line feed.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess trailing whitespace isn't actually an issue because it will only read len(b) bytes and stop anyway, so the only way to break this would be to have a bunch of leading whitespace, which seems unlikely in this case.

Copy link
Member

Choose a reason for hiding this comment

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

Right, it's mostly irrelevant if we only read a fixed size of bytes that will always be larger than a uint64's length. The string gets trimmed and all that's left is what we care about.

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.

5 participants