181 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package runtime
 | 
						|
 | 
						|
import (
 | 
						|
	"flag"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"path/filepath"
 | 
						|
	"syscall"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	utils "github.com/docker/containerd/testutils"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	devNull     = "/dev/null"
 | 
						|
	stdin       io.WriteCloser
 | 
						|
	runtimeTool = flag.String("runtime", "runc", "Runtime to use for this test")
 | 
						|
)
 | 
						|
 | 
						|
// Create containerd state and oci bundles directory
 | 
						|
func setup() error {
 | 
						|
	if err := os.MkdirAll(utils.StateDir, 0755); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if err := os.MkdirAll(utils.BundlesRoot, 0755); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Creates the bundleDir with rootfs, io fifo dir and a default spec.
 | 
						|
// On success, returns the bundlePath
 | 
						|
func setupBundle(bundleName string) (string, error) {
 | 
						|
	bundlePath := filepath.Join(utils.BundlesRoot, bundleName)
 | 
						|
	if err := os.MkdirAll(bundlePath, 0755); err != nil {
 | 
						|
		fmt.Println("Unable to create bundlePath due to ", err)
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	io := filepath.Join(bundlePath, "io")
 | 
						|
	if err := os.MkdirAll(io, 0755); err != nil {
 | 
						|
		fmt.Println("Unable to create io dir due to ", err)
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	if err := utils.GenerateReferenceSpecs(bundlePath); err != nil {
 | 
						|
		fmt.Println("Unable to generate OCI reference spec: ", err)
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	if err := utils.CreateBusyboxBundle(bundleName); err != nil {
 | 
						|
		fmt.Println("CreateBusyboxBundle error: ", err)
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	return bundlePath, nil
 | 
						|
}
 | 
						|
 | 
						|
func setupStdio(cwd string, bundlePath string, bundleName string) (Stdio, error) {
 | 
						|
	s := NewStdio(devNull, devNull, devNull)
 | 
						|
 | 
						|
	pid := "init"
 | 
						|
	for stdName, stdPath := range map[string]*string{
 | 
						|
		"stdin":  &s.Stdin,
 | 
						|
		"stdout": &s.Stdout,
 | 
						|
		"stderr": &s.Stderr,
 | 
						|
	} {
 | 
						|
		*stdPath = filepath.Join(cwd, bundlePath, "io", bundleName+"-"+pid+"-"+stdName)
 | 
						|
		if err := syscall.Mkfifo(*stdPath, 0755); err != nil && !os.IsExist(err) {
 | 
						|
			fmt.Println("Mkfifo error: ", err)
 | 
						|
			return s, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	err := attachStdio(s)
 | 
						|
	if err != nil {
 | 
						|
		fmt.Println("attachStdio error: ", err)
 | 
						|
		return s, err
 | 
						|
	}
 | 
						|
 | 
						|
	return s, nil
 | 
						|
}
 | 
						|
 | 
						|
func attachStdio(s Stdio) error {
 | 
						|
	stdinf, err := os.OpenFile(s.Stdin, syscall.O_RDWR, 0)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	stdin = stdinf
 | 
						|
	stdoutf, err := os.OpenFile(s.Stdout, syscall.O_RDWR, 0)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	go io.Copy(os.Stdout, stdoutf)
 | 
						|
	stderrf, err := os.OpenFile(s.Stderr, syscall.O_RDWR, 0)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	go io.Copy(os.Stderr, stderrf)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func teardownBundle(bundleName string) {
 | 
						|
	containerRoot := filepath.Join(utils.StateDir, bundleName)
 | 
						|
	os.RemoveAll(containerRoot)
 | 
						|
 | 
						|
	bundlePath := filepath.Join(utils.BundlesRoot, bundleName)
 | 
						|
	os.RemoveAll(bundlePath)
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Remove containerd state and oci bundles directory
 | 
						|
func teardown() {
 | 
						|
	os.RemoveAll(utils.StateDir)
 | 
						|
	os.RemoveAll(utils.BundlesRoot)
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkBusyboxSh(b *testing.B) {
 | 
						|
	bundleName := "busybox-sh"
 | 
						|
 | 
						|
	wd := utils.GetTestOutDir()
 | 
						|
	if err := os.Chdir(wd); err != nil {
 | 
						|
		b.Fatalf("Could not change working directory: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := setup(); err != nil {
 | 
						|
		b.Fatalf("Error setting up test: %v", err)
 | 
						|
	}
 | 
						|
	defer teardown()
 | 
						|
 | 
						|
	for n := 0; n < b.N; n++ {
 | 
						|
		bundlePath, err := setupBundle(bundleName)
 | 
						|
		if err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		s, err := setupStdio(wd, bundlePath, bundleName)
 | 
						|
		if err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		c, err := New(ContainerOpts{
 | 
						|
			Root:    utils.StateDir,
 | 
						|
			ID:      bundleName,
 | 
						|
			Bundle:  filepath.Join(wd, bundlePath),
 | 
						|
			Runtime: *runtimeTool,
 | 
						|
			Shim:    "containerd-shim",
 | 
						|
			Timeout: 15 * time.Second,
 | 
						|
		})
 | 
						|
 | 
						|
		if err != nil {
 | 
						|
			b.Fatalf("Error creating a New container: ", err)
 | 
						|
		}
 | 
						|
 | 
						|
		benchmarkStartContainer(b, c, s, bundleName)
 | 
						|
 | 
						|
		teardownBundle(bundleName)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func benchmarkStartContainer(b *testing.B, c Container, s Stdio, bundleName string) {
 | 
						|
	p, err := c.Start("", s)
 | 
						|
	if err != nil {
 | 
						|
		b.Fatalf("Error starting container %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	kill := exec.Command(c.Runtime(), "kill", bundleName, "KILL")
 | 
						|
	kill.Run()
 | 
						|
 | 
						|
	p.Wait()
 | 
						|
	c.Delete()
 | 
						|
 | 
						|
	// wait for kill to finish. selected wait time is arbitrary
 | 
						|
	time.Sleep(500 * time.Millisecond)
 | 
						|
 | 
						|
}
 |