Skip to content

Commit

Permalink
Added GCS tests and benchmarks
Browse files Browse the repository at this point in the history
Added testing suite that can built and run directly on the Linux uVM
by sharing or adding it to the rootfs.
It primarily focuses on container (standalone and CRI) management.

Signed-off-by: Hamza El-Saawy <hamzaelsaawy@microsoft.com>
  • Loading branch information
helsaawy committed Apr 13, 2022
1 parent 13ceffd commit 4054748
Show file tree
Hide file tree
Showing 10 changed files with 1,739 additions and 2 deletions.
12 changes: 10 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ service/pkg/
*.img
*.vhd
*.tar.gz
*.tar

# Make stuff
.rootfs-done
Expand All @@ -32,9 +33,16 @@ rootfs/*
rootfs-conv/*
*.o
/build/

deps/*
out/*

# test results
test/results

# ninja build
.ninja_log
build.ninja

# go workspaces
go.work
go.work.sum
go.work.sum
222 changes: 222 additions & 0 deletions test/gcs/container_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
//go:build linux

package gcs

import (
"context"
"testing"

"github.com/Microsoft/hcsshim/internal/guest/prot"
"github.com/Microsoft/hcsshim/internal/guest/runtime/hcsv2"
"github.com/Microsoft/hcsshim/internal/guest/stdio"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci"
cri_util "github.com/containerd/containerd/pkg/cri/util"

testoci "github.com/Microsoft/hcsshim/test/internal/oci"
)

func BenchmarkContainerCreate(b *testing.B) {
requireFeatures(b, featureStandalone)
ctx := namespaces.WithNamespace(context.Background(), testoci.DefaultNamespace)
host, _ := getTestState(ctx, b)

b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
id := b.Name() + cri_util.GenerateID()
scratch, rootfs := mountRootfs(ctx, b, host, id)

s := testoci.CreateLinuxSpec(ctx, b, id,
testoci.DefaultLinuxSpecOpts(id,
oci.WithRootFSPath(rootfs),
oci.WithProcessArgs("/bin/sh", "-c", tailNull),
)...,
)
r := &prot.VMHostedContainerSettingsV2{
OCIBundlePath: scratch,
OCISpecification: s,
}

b.StartTimer()
c := createContainer(ctx, b, host, id, r)
b.StopTimer()

// create launches background go-routines
// so kill container to end those and avoid future perf hits
killContainer(ctx, b, c)
deleteContainer(ctx, b, c)
removeContainer(ctx, b, host, id)
unmountRootfs(ctx, b, scratch)
}
}

func BenchmarkContainerStart(b *testing.B) {
requireFeatures(b, featureStandalone)
ctx := context.Background()
host, _ := getTestState(ctx, b)

b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
id, r, cleanup := _standaloneContainerRequest(ctx, b, host)

c := createContainer(ctx, b, host, id, r)

b.StartTimer()
p := startContainer(ctx, b, c, stdio.ConnectionSettings{})
b.StopTimer()

killContainer(ctx, b, c)
waitContainer(ctx, b, c, p, true)
cleanupContainer(ctx, b, host, c)
cleanup()
}
}

func BenchmarkContainerKill(b *testing.B) {
requireFeatures(b, featureStandalone)
ctx := context.Background()
host, _ := getTestState(ctx, b)

b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
id, r, cleanup := _standaloneContainerRequest(ctx, b, host)
c := createContainer(ctx, b, host, id, r)
p := startContainer(ctx, b, c, stdio.ConnectionSettings{})

b.StartTimer()
killContainer(ctx, b, c)
_, n := waitContainerRaw(c, p)
b.StopTimer()

switch n {
case prot.NtForcedExit:
default:
b.Fatalf("container exit was %s", n)
}

cleanupContainer(ctx, b, host, c)
cleanup()
}
}

// container create through till wait and exit
func BenchmarkContainerCompleteExit(b *testing.B) {
requireFeatures(b, featureStandalone)
ctx := context.Background()
host, _ := getTestState(ctx, b)

b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
id, r, cleanup := _standaloneContainerRequest(ctx, b, host, oci.WithProcessArgs("/bin/sh", "-c", "true"))

b.StartTimer()
c := createContainer(ctx, b, host, id, r)
p := startContainer(ctx, b, c, stdio.ConnectionSettings{})
e, n := waitContainerRaw(c, p)
b.StopTimer()

switch n {
case prot.NtGracefulExit, prot.NtUnexpectedExit:
default:
b.Fatalf("container exit was %s", n)
}

if e != 0 {
b.Fatalf("container exit code was %d", e)
}

killContainer(ctx, b, c)
c.Wait()
cleanupContainer(ctx, b, host, c)
cleanup()
}
}

func BenchmarkContainerCompleteKill(b *testing.B) {
requireFeatures(b, featureStandalone)
ctx := context.Background()
host, _ := getTestState(ctx, b)

b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
id, r, cleanup := _standaloneContainerRequest(ctx, b, host)

b.StartTimer()
c := createContainer(ctx, b, host, id, r)
p := startContainer(ctx, b, c, stdio.ConnectionSettings{})
killContainer(ctx, b, c)
_, n := waitContainerRaw(c, p)
b.StopTimer()

switch n {
case prot.NtForcedExit:
default:
b.Fatalf("container exit was %s", n)
}

cleanupContainer(ctx, b, host, c)
cleanup()
}
}

func BenchmarkContainerExec(b *testing.B) {
requireFeatures(b, featureStandalone)
ctx := namespaces.WithNamespace(context.Background(), testoci.DefaultNamespace)
host, _ := getTestState(ctx, b)

id := b.Name()
c := createStandaloneContainer(ctx, b, host, id)
ip := startContainer(ctx, b, c, stdio.ConnectionSettings{})

b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
ps := testoci.CreateLinuxSpec(ctx, b, id,
// oci.WithTTY,
oci.WithDefaultPathEnv,
oci.WithProcessArgs("/bin/sh", "-c", "true"),
).Process

b.StartTimer()
p := execProcess(ctx, b, c, ps, stdio.ConnectionSettings{})
exch, dch := p.Wait()
if e := <-exch; e != 0 {
b.Errorf("process exited with error code %d", e)
}
b.StopTimer()

dch <- true
close(dch)
}

killContainer(ctx, b, c)
waitContainer(ctx, b, c, ip, true)
cleanupContainer(ctx, b, host, c)
}

func _standaloneContainerRequest(ctx context.Context, t testing.TB, host *hcsv2.Host, extra ...oci.SpecOpts) (string, *prot.VMHostedContainerSettingsV2, func()) {
ctx = namespaces.WithNamespace(ctx, testoci.DefaultNamespace)
id := t.Name() + cri_util.GenerateID()
scratch, rootfs := mountRootfs(ctx, t, host, id)

opts := testoci.DefaultLinuxSpecOpts(id,
oci.WithRootFSPath(rootfs),
oci.WithProcessArgs("/bin/sh", "-c", tailNull),
)
opts = append(opts, extra...)
s := testoci.CreateLinuxSpec(ctx, t, id, opts...)
r := &prot.VMHostedContainerSettingsV2{
OCIBundlePath: scratch,
OCISpecification: s,
}
f := func() {
unmountRootfs(ctx, t, scratch)
}

return id, r, f
}
Loading

0 comments on commit 4054748

Please sign in to comment.