- 
                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
libcontainer/intelrdt: add support for Schemata field #4830
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() | 
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!
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
| 1.4 backport: #4915 | 
Implement support for the
linux.intelRdt.schematafield of the spec. This allows management of the "schemata" file in the resctrl group in a generic way.Refs: opencontainers/runtime-spec#1230