Skip to content

Commit d0f5644

Browse files
committed
Add support for assigning cpu group on creation
In recent builds of Windows there was support added to the HCS to allow assigning a cpugroup at creation time of the VM instead of afterwards. The current approach in this repo of adding a vm after start was only a workaround as this wasn't supported at the time. The current approach isn;t ideal due to some wonky behavior on machines with multiple NUMA nodes as we can suffer performance penalties because of remote memory access on machines with > 1 node when adding a VM after start. Signed-off-by: Daniel Canter <dcanter@microsoft.com>
1 parent 141e8c0 commit d0f5644

File tree

8 files changed

+48
-24
lines changed

8 files changed

+48
-24
lines changed

internal/cpugroup/cpugroup.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ package cpugroup
33
import (
44
"context"
55
"encoding/json"
6-
"errors"
76
"fmt"
87
"strings"
98

109
"github.com/Microsoft/hcsshim/internal/hcs"
1110
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
11+
"github.com/pkg/errors"
1212
)
1313

1414
const NullGroupID = "00000000-0000-0000-0000-000000000000"
@@ -48,7 +48,7 @@ func Create(ctx context.Context, id string, logicalProcessors []uint32) error {
4848
LogicalProcessorCount: uint32(len(logicalProcessors)),
4949
}
5050
if err := modifyCPUGroupRequest(ctx, operation, details); err != nil {
51-
return fmt.Errorf("failed to make cpugroups CreateGroup request for details %+v with: %s", details, err)
51+
return errors.Wrapf(err, "failed to make cpugroups CreateGroup request for details %+v", details)
5252
}
5353
return nil
5454
}
@@ -65,7 +65,7 @@ func getCPUGroupConfig(ctx context.Context, id string) (*hcsschema.CpuGroupConfi
6565
}
6666
groupConfigs := &hcsschema.CpuGroupConfigurations{}
6767
if err := json.Unmarshal(cpuGroupsPresent.Properties[0], groupConfigs); err != nil {
68-
return nil, fmt.Errorf("failed to unmarshal host cpugroups: %v", err)
68+
return nil, errors.Wrap(err, "failed to unmarshal host cpugroups")
6969
}
7070

7171
for _, c := range groupConfigs.CpuGroups {

internal/cpugroup/cpugroup_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ func TestCPUGroupCreateWithIDAndDelete(t *testing.T) {
1414
lps := []uint32{0, 1}
1515
ctx, cancel := context.WithCancel(context.Background())
1616
defer cancel()
17+
1718
id, err := guid.NewV4()
1819
if err != nil {
1920
t.Fatalf("failed to create cpugroup guid with: %v", err)
2021
}
22+
2123
err = Create(ctx, id.String(), lps)
2224
if err != nil {
2325
t.Fatalf("failed to create cpugroup %s with: %v", id.String(), err)
2426
}
27+
2528
defer func() {
2629
if err := Delete(ctx, id.String()); err != nil {
2730
t.Fatalf("failed to delete cpugroup %s with: %v", id.String(), err)

internal/hcs/schema2/processor_2.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
55
*
6-
* API version: 2.1
6+
* API version: 2.5
77
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
88
*/
99

@@ -17,4 +17,7 @@ type Processor2 struct {
1717
Weight int32 `json:"Weight,omitempty"`
1818

1919
ExposeVirtualizationExtensions bool `json:"ExposeVirtualizationExtensions,omitempty"`
20+
21+
// An optional object that configures the CPU Group to which a Virtual Machine is going to bind to.
22+
CpuGroup *CpuGroup `json:"CpuGroup,omitempty"`
2023
}

internal/uvm/cpugroups.go renamed to internal/uvm/cpugroup.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import (
1010
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
1111
)
1212

13+
// Build that assigning a cpu group on creation of a vm is supported
14+
const cpuGroupCreateBuild = 20124
15+
16+
var cpuGroupCreateNotSupported = fmt.Errorf("cpu group assignment requires a build of %d or higher", cpuGroupCreateBuild)
17+
1318
// ReleaseCPUGroup unsets the cpugroup from the VM
1419
func (uvm *UtilityVM) ReleaseCPUGroup(ctx context.Context) error {
1520
groupID := uvm.cpuGroupID

internal/uvm/create.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,6 @@ func (uvm *UtilityVM) Close() (err error) {
244244
windows.Close(uvm.vmmemProcess)
245245

246246
if uvm.hcsSystem != nil {
247-
if err := uvm.ReleaseCPUGroup(ctx); err != nil {
248-
log.G(ctx).WithError(err).Warn("failed to release VM resource")
249-
}
250247
_ = uvm.hcsSystem.Terminate(ctx)
251248
_ = uvm.Wait()
252249
}

internal/uvm/create_lcow.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,19 @@ func CreateLCOW(ctx context.Context, opts *OptionsLCOW) (_ *UtilityVM, err error
204204
// Align the requested memory size.
205205
memorySizeInMB := uvm.normalizeMemorySize(ctx, opts.MemorySizeInMB)
206206

207+
processor := &hcsschema.Processor2{
208+
Count: uvm.processorCount,
209+
Limit: opts.ProcessorLimit,
210+
Weight: opts.ProcessorWeight,
211+
}
212+
// We can set a cpu group for the VM at creation time in recent builds.
213+
if opts.CPUGroupID != "" {
214+
if osversion.Build() < cpuGroupCreateBuild {
215+
return nil, cpuGroupCreateNotSupported
216+
}
217+
processor.CpuGroup = &hcsschema.CpuGroup{Id: opts.CPUGroupID}
218+
}
219+
207220
doc := &hcsschema.ComputeSystem{
208221
Owner: uvm.owner,
209222
SchemaVersion: schemaversion.SchemaV21(),
@@ -221,11 +234,7 @@ func CreateLCOW(ctx context.Context, opts *OptionsLCOW) (_ *UtilityVM, err error
221234
HighMMIOBaseInMB: opts.HighMMIOBaseInMB,
222235
HighMMIOGapInMB: opts.HighMMIOGapInMB,
223236
},
224-
Processor: &hcsschema.Processor2{
225-
Count: uvm.processorCount,
226-
Limit: opts.ProcessorLimit,
227-
Weight: opts.ProcessorWeight,
228-
},
237+
Processor: processor,
229238
},
230239
Devices: &hcsschema.Devices{
231240
HvSocket: &hcsschema.HvSocket2{
@@ -381,6 +390,8 @@ func CreateLCOW(ctx context.Context, opts *OptionsLCOW) (_ *UtilityVM, err error
381390
return nil, fmt.Errorf("error while creating the compute system: %s", err)
382391
}
383392

393+
uvm.cpuGroupID = opts.CPUGroupID
394+
384395
// Cerate a socket to inject entropy during boot.
385396
uvm.entropyListener, err = uvm.listenVsock(entropyVsockPort)
386397
if err != nil {

internal/uvm/create_wcow.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/Microsoft/hcsshim/internal/uvmfolder"
2020
"github.com/Microsoft/hcsshim/internal/wclayer"
2121
"github.com/Microsoft/hcsshim/internal/wcow"
22+
"github.com/Microsoft/hcsshim/osversion"
2223
"github.com/containerd/ttrpc"
2324
"github.com/pkg/errors"
2425
"go.opencensus.io/trace"
@@ -122,6 +123,19 @@ func prepareConfigDoc(ctx context.Context, uvm *UtilityVM, opts *OptionsWCOW, uv
122123
}
123124
}
124125

126+
processor := &hcsschema.Processor2{
127+
Count: uvm.processorCount,
128+
Limit: opts.ProcessorLimit,
129+
Weight: opts.ProcessorWeight,
130+
}
131+
// We can set a cpu group for the VM at creation time in recent builds.
132+
if opts.CPUGroupID != "" {
133+
if osversion.Build() < cpuGroupCreateBuild {
134+
return nil, cpuGroupCreateNotSupported
135+
}
136+
processor.CpuGroup = &hcsschema.CpuGroup{Id: opts.CPUGroupID}
137+
}
138+
125139
doc := &hcsschema.ComputeSystem{
126140
Owner: uvm.owner,
127141
SchemaVersion: schemaversion.SchemaV21(),
@@ -148,11 +162,7 @@ func prepareConfigDoc(ctx context.Context, uvm *UtilityVM, opts *OptionsWCOW, uv
148162
HighMMIOBaseInMB: opts.HighMMIOBaseInMB,
149163
HighMMIOGapInMB: opts.HighMMIOGapInMB,
150164
},
151-
Processor: &hcsschema.Processor2{
152-
Count: uvm.processorCount,
153-
Limit: opts.ProcessorLimit,
154-
Weight: opts.ProcessorWeight,
155-
},
165+
Processor: processor,
156166
},
157167
Devices: &hcsschema.Devices{
158168
HvSocket: &hcsschema.HvSocket2{
@@ -319,6 +329,8 @@ func CreateWCOW(ctx context.Context, opts *OptionsWCOW) (_ *UtilityVM, err error
319329
return nil, fmt.Errorf("error while creating the compute system: %s", err)
320330
}
321331

332+
uvm.cpuGroupID = opts.CPUGroupID
333+
322334
// All clones MUST use external gcs connection
323335
if opts.ExternalGuestConnection {
324336
if err = uvm.startExternalGcsListener(ctx); err != nil {

internal/uvm/start.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -205,13 +205,6 @@ func (uvm *UtilityVM) Start(ctx context.Context) (err error) {
205205
}
206206
}()
207207

208-
// assign the VM to the cpugroup specified, if any
209-
if uvm.cpuGroupID != "" {
210-
if err := uvm.SetCPUGroup(ctx, uvm.cpuGroupID); err != nil {
211-
return err
212-
}
213-
}
214-
215208
// Start waiting on the utility VM.
216209
uvm.exitCh = make(chan struct{})
217210
go func() {

0 commit comments

Comments
 (0)