-
Notifications
You must be signed in to change notification settings - Fork 2.2k
libcontainer/intelrdt: add support for Schemata field #4830
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
base: main
Are you sure you want to change the base?
Conversation
d4ca2a1
to
9c2639e
Compare
9c2639e
to
9120253
Compare
Updated:
|
9120253
to
75e8dd9
Compare
Signed-off-by: Markus Lehtonen <[email protected]>
75e8dd9
to
a5d0f18
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
Signed-off-by: Markus Lehtonen <[email protected]>
Head branch was pushed to by a user without write access
a5d0f18
to
8082dfe
Compare
libcontainer/intelrdt/intelrdt.go
Outdated
if l3CacheSchema == "" && memBwSchema != "" { | ||
if err := writeFile(path, "schemata", memBwSchema); err != nil { | ||
// Write a single joint schema string to schemata file | ||
schemata := strings.Join(parts, "\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: perhaps you can use strings.Builder
instead? Something like this:
var schemata strings.Builder
for _, s := range []string{l3CacheSchema, memBwSchema, container.IntelRdt.Schemata...} {
if s != "" {
schemata.WriteString(s)
schemata.WriteString("\n")
}
}
if schemata.Len() > 0 {
if err := writeFile(path, "schemata", schemata); err != nil {
return err
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. I thought about it but I wasn't sure it was worth it. If others thought about it too, let's do it :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually realized that the implementation was not good. It's most robust to write each field in a separate writeFile() call. Case where intelRdt.Schemata
tried to overwrite something specified in the other schemata fields failed as kernel rejected the "mega write". The code now handles that scenario.
Still, out of curiosity, was there some benefit of using strings.Builder() or just a style/readability thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeap, see the pkg documentation:
A Builder is used to efficiently build a string using Builder.Write methods. It minimizes memory copying. The zero value is ready to use. Do not copy a non-zero Builder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few comments, overall lgtm
02bbcd9
to
bd15875
Compare
Update: code fixed and review comments addressed. EDIT: fixed unit tests. A separate commit so it's easier to review if that's acceptable |
7430bc2
to
f720d0e
Compare
eaadf2e
to
0cf91bc
Compare
libcontainer/intelrdt/intelrdt.go
Outdated
// Write a single joint schema string to schemata file | ||
if l3CacheSchema != "" && memBwSchema != "" { | ||
if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil { | ||
if r.L3CacheSchema != "" { | ||
if err := writeFile(path, "schemata", r.L3CacheSchema); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Write only L3 cache schema string to schemata file | ||
if l3CacheSchema != "" && memBwSchema == "" { | ||
if err := writeFile(path, "schemata", l3CacheSchema); err != nil { | ||
if r.MemBwSchema != "" { | ||
if err := writeFile(path, "schemata", r.MemBwSchema); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Write only memory bandwidth schema string to schemata file | ||
if l3CacheSchema == "" && memBwSchema != "" { | ||
if err := writeFile(path, "schemata", memBwSchema); err != nil { | ||
if len(r.Schemata) > 0 { | ||
if err := writeFile(path, "schemata", strings.Join(r.Schemata, "\n")); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it will be better to rewrite writeFile
to accept multiple data:
func writeFile(dir, file, data... string) error {
...
for _, d := range data {
if d == "" {
continue
}
err := f.WriteString(d)
...
}
...
}
and then use it like this here:
err := writeFile(path, "schemata", r.L3CacheSchema, r.MemBwSchema, r.Schemata...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. I did a bit more refactoring and ditched the whole writeFile()
function. The impl is now inline inside Set()
0cf91bc
to
034fdfb
Compare
libcontainer/intelrdt/intelrdt.go
Outdated
path := filepath.Join(m.GetPath(), "schemata") | ||
for _, line := range append([]string{r.L3CacheSchema, r.MemBwSchema}, r.Schemata...) { | ||
if line != "" { | ||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0o600) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you change this from the previous iteration using the string builder thingy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is also more robust to do one write per line. If we had L3CacheSchema: L3:0=...
and then "L3:0=..."
in the schemata
fields as well, kernel would reject the write if done in one write.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean more robust? Why is it better to have "partial" data written instead of all/nothing (atomic)? We will return an error anyways. Is it simpler to debug or what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you do all in one write (like Write("L3:0=f\nL3:0:ff\n")
. The write will fail. If you do two separate writes (like Write("L3:0=f\n"); Write("L3:0:ff\n")
), it does not fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it was just doing that: https://github.com/opencontainers/runc/pull/4830/files#diff-84ecbbd29a26d73ccc5bf64ce8ed27a1dcca405c3f605d51293b5b3a74dd8979L653
Why would it fail now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would fail if somebody put L3 in the memBwSchema field.
But there's the essential detail that's the gist of this PR. Add Schemata
field. The schemata field is allowed to contain anything. A corner case, yes, but it could override the stuff in the l3CacheSchema field
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'm missing something because from what you say, I believe not doing a write per line seems better.
If you write it one per line, then if schemata overrides the L3CacheSchema, then it will work just fine. However, if we write it all in one go, it will fail.
Failing seems way better, as if you wrote something on the L3CacheSchema, it's unlikely you want to overwrite it with the Schemata field (in that case you will leave it empty).
Am I missing something?
03d5d45
to
a3451ff
Compare
libcontainer/intelrdt/intelrdt.go
Outdated
path := filepath.Join(m.GetPath(), "schemata") | ||
for _, line := range append([]string{r.L3CacheSchema, r.MemBwSchema}, r.Schemata...) { | ||
if line != "" { | ||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0o600) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'm missing something because from what you say, I believe not doing a write per line seems better.
If you write it one per line, then if schemata overrides the L3CacheSchema, then it will work just fine. However, if we write it all in one go, it will fail.
Failing seems way better, as if you wrote something on the L3CacheSchema, it's unlikely you want to overwrite it with the Schemata field (in that case you will leave it empty).
Am I missing something?
Implement support for the linux.intelRdt.schemata field of the spec. This allows management of the "schemata" file in the resctrl group in a generic way. Signed-off-by: Markus Lehtonen <[email protected]>
Signed-off-by: Markus Lehtonen <[email protected]>
a3451ff
to
7be025f
Compare
@rata my thinking behind separate writes was that the But your standpoint is probably better justified. Especially with:
So I changed the implementation into one consolidated write, utilizing the strings.Builder() |
if schemata.Len() > 0 { | ||
path := filepath.Join(m.GetPath(), "schemata") | ||
if err := os.WriteFile(path, []byte(schemata.String()), 0o600); err != nil { | ||
return newLastCmdError(fmt.Errorf("intelrdt: unable to write %q: %w", schemata.String(), err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, this change is not 100% obvious to me.
Before we were not doing this, why do it now? Checking quickly, it seems like a different improvement, as the "info" file this ends up checking might have some more explanation on why it failed.
Am I reading this correctly?
A different commit doing this change, with its explanation, seems better IMHO. If that is too much of a hassle, then mention it in the commit you do this change. If this causes an issue in the future, it will seem like something not intentional when it really was intentional, that is very valuable information for future me :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is basically inlining the former writeFile() function (now dropped). I can create a separate commit about that if needed. @rata ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, the comment is on the return line. Before we returned err
, now we use this function. I was referring to that
Implement support for the
linux.intelRdt.schemata
field of the spec. This allows management of the "schemata" file in the resctrl group in a generic way.Refs: opencontainers/runtime-spec#1230