24144682a0
This is the first in a series of micro benchmarks for containerd. Performance measurement will use containerd objects and methods that are not dependent on the grpc API and dont require the daemon to the running. Test will require containerd-shim and runc. The motivation is to understand the baseline performance at the lowest containerd layer. A natural extension to this effort would be to write macro benchmarks which would include API and daemon. Note: - Currently measures only one workload (busybox sh) start times. Will add other bundles and args soon. - Can use integration-test utils for bundle processing. However, json marshal/unmarshal is currently timing out standard benchmark times. So going with default spec for now. Sample run: BenchmarkBusyboxSh-4 / # / # / # 2 576013841 ns/op ok github.com/docker/containerd/runtime 1.800s Signed-off-by: Anusha Ragunathan <anusha@docker.com>
111 lines
2.9 KiB
Go
111 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"reflect"
|
|
|
|
utils "github.com/docker/containerd/testutils"
|
|
ocs "github.com/opencontainers/runtime-spec/specs-go"
|
|
)
|
|
|
|
type OciProcessArgs struct {
|
|
Cmd string
|
|
Args []string
|
|
}
|
|
|
|
type Bundle struct {
|
|
Source string
|
|
Name string
|
|
Spec ocs.Spec
|
|
Path string
|
|
}
|
|
|
|
var bundleMap map[string]Bundle
|
|
|
|
// untarRootfs untars the given `source` tarPath into `destination/rootfs`
|
|
func untarRootfs(source string, destination string) error {
|
|
destination = filepath.Join(destination, "rootfs")
|
|
if err := os.MkdirAll(destination, 0755); err != nil {
|
|
return nil
|
|
}
|
|
tar := exec.Command("tar", "-C", destination, "-xf", source)
|
|
return tar.Run()
|
|
}
|
|
|
|
// CreateBundleWithFilter generate a new oci-bundle named `name` from
|
|
// the provide `source` rootfs. It starts from the default spec
|
|
// generated by `runc spec`, overrides the `spec.Process.Args` value
|
|
// with `args` and set `spec.Process.Terminal` to false. It then apply
|
|
// `filter()` to the resulting spec if it is provided.
|
|
func CreateBundleWithFilter(source, name string, args []string, filter func(spec *ocs.Spec)) error {
|
|
// Generate the spec
|
|
var spec ocs.Spec
|
|
if f, err := os.Open(utils.RefOciSpecsPath); err != nil {
|
|
return fmt.Errorf("Failed to open default spec: %v", err)
|
|
} else {
|
|
if err := json.NewDecoder(f).Decode(&spec); err != nil {
|
|
return fmt.Errorf("Failed to load default spec: %v", err)
|
|
}
|
|
f.Close()
|
|
}
|
|
|
|
spec.Process.Args = args
|
|
spec.Process.Terminal = false
|
|
if filter != nil {
|
|
filter(&spec)
|
|
}
|
|
|
|
bundlePath := filepath.Join(utils.BundlesRoot, name)
|
|
nb := Bundle{source, name, spec, bundlePath}
|
|
|
|
// Check that we don't already have such a bundle
|
|
if b, ok := bundleMap[name]; ok {
|
|
if reflect.DeepEqual(b, nb) == false {
|
|
return fmt.Errorf("A bundle name named '%s' already exist but with different properties! %#v != %#v",
|
|
name, b, nb)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Nothing should be there, but just in case
|
|
os.RemoveAll(bundlePath)
|
|
|
|
if err := untarRootfs(filepath.Join(utils.ArchivesDir, source+".tar"), bundlePath); err != nil {
|
|
return fmt.Errorf("Failed to untar %s.tar: %v", source, err)
|
|
}
|
|
|
|
// create a place for the io fifo
|
|
if err := os.Mkdir(filepath.Join(bundlePath, "io"), 0755); err != nil {
|
|
return fmt.Errorf("Failed to create bundle io directory: %v", err)
|
|
}
|
|
|
|
// Write the updated spec to the right location
|
|
config, e := os.Create(filepath.Join(bundlePath, "config.json"))
|
|
if e != nil {
|
|
return fmt.Errorf("Failed to create oci spec: %v", e)
|
|
}
|
|
defer config.Close()
|
|
|
|
if err := json.NewEncoder(config).Encode(&spec); err != nil {
|
|
return fmt.Errorf("Failed to encore oci spec: %v", e)
|
|
}
|
|
|
|
bundleMap[name] = nb
|
|
return nil
|
|
}
|
|
|
|
func GetBundle(name string) *Bundle {
|
|
bundle, ok := bundleMap[name]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return &bundle
|
|
}
|
|
|
|
func CreateBusyboxBundle(name string, args []string) error {
|
|
return CreateBundleWithFilter("busybox", name, args, nil)
|
|
}
|