containerd/integration-test/bundle_utils_test.go
Anusha Ragunathan 24144682a0 Micro benchmarks for containerd. (#244)
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>
2016-05-27 10:35:42 -07:00

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)
}