The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/1846

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===

From 130177131f8914e4a182fcf2482a59009ba91e32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Sun, 3 Apr 2016 03:00:33 -0400
Subject: [PATCH 1/2] Update bash completion to use --fast
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

That helps when dealing with hundreds of containers.

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 config/bash/lxd-client | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config/bash/lxd-client b/config/bash/lxd-client
index 97d46ef..631d7e8 100644
--- a/config/bash/lxd-client
+++ b/config/bash/lxd-client
@@ -4,7 +4,7 @@ _have lxc && {
     _lxd_names()
     {
       COMPREPLY=( $( compgen -W \
-        "$( lxc list | tail -n +4 | awk '{print $2}' | egrep -v '^(\||^$)' )" 
"$cur" )
+        "$( lxc list --fast | tail -n +4 | awk '{print $2}' | egrep -v 
'^(\||^$)' )" "$cur" )
       )
     }
 

From cb88ef949e3b4d81f50172fd09ef6a85ccfe5bfb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Sun, 3 Apr 2016 04:55:46 -0400
Subject: [PATCH 2/2] tests: Add benchmarking tool
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 test/lxd-benchmark/main.go | 311 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 311 insertions(+)
 create mode 100644 test/lxd-benchmark/main.go

diff --git a/test/lxd-benchmark/main.go b/test/lxd-benchmark/main.go
new file mode 100644
index 0000000..b3ce881
--- /dev/null
+++ b/test/lxd-benchmark/main.go
@@ -0,0 +1,311 @@
+package main
+
+import (
+       "fmt"
+       "io/ioutil"
+       "os"
+       "strings"
+       "sync"
+       "time"
+
+       "github.com/lxc/lxd"
+       "github.com/lxc/lxd/shared"
+       "github.com/lxc/lxd/shared/gnuflag"
+)
+
+var argCount = gnuflag.Int("count", 100, "Number of containers to create")
+var argImage = gnuflag.String("image", "ubuntu:", "Image to use for the test")
+var argPrivileged = gnuflag.Bool("privileged", false, "Use privileged 
containers")
+
+func main() {
+       err := run(os.Args)
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "error: %s\n", err)
+               os.Exit(1)
+       }
+
+       os.Exit(0)
+}
+
+func run(args []string) error {
+       // Parse command line
+       gnuflag.Parse(true)
+
+       if len(os.Args) == 1 || !shared.StringInSlice(os.Args[1], 
[]string{"spawn", "delete"}) {
+               fmt.Printf("Usage: %s spawn [--count=COUNT] [--image=IMAGE] 
[--privileged=BOOL]\n", os.Args[0])
+               fmt.Printf("       %s delete\n\n", os.Args[0])
+               gnuflag.Usage()
+               fmt.Printf("\n")
+               return fmt.Errorf("An action (spawn or delete) must be passed.")
+       }
+
+       // Connect to LXD
+       c, err := lxd.NewClient(&lxd.DefaultConfig, "local")
+       if err != nil {
+               return err
+       }
+
+       switch os.Args[1] {
+       case "spawn":
+               return spawnContainers(c, *argCount, *argImage, *argPrivileged)
+       case "delete":
+               return deleteContainers(c)
+       }
+
+       return nil
+}
+
+func logf(format string, args ...interface{}) {
+       fmt.Printf(fmt.Sprintf("[%s] %s\n", time.Now().Format(time.StampMilli), 
format), args...)
+}
+
+func spawnContainers(c *lxd.Client, count int, image string, privileged bool) 
error {
+       // Detect the number of parallel actions
+       cpus, err := ioutil.ReadDir("/sys/bus/cpu/devices")
+       if err != nil {
+               return err
+       }
+
+       batch := len(cpus)
+       batches := count / batch
+       remainder := count % batch
+
+       // Print the test header
+       st, err := c.ServerStatus()
+       if err != nil {
+               return err
+       }
+
+       privilegedStr := "unprivileged"
+       if privileged {
+               privilegedStr = "privileged"
+       }
+
+       fmt.Printf("Test environment:\n")
+       fmt.Printf("  Server backend: %s\n", st.Environment.Server)
+       fmt.Printf("  Server version: %s\n", st.Environment.ServerVersion)
+       fmt.Printf("  Kernel: %s\n", st.Environment.Kernel)
+       fmt.Printf("  Kernel architecture: %s\n", 
st.Environment.KernelArchitecture)
+       fmt.Printf("  Kernel version: %s\n", st.Environment.KernelVersion)
+       fmt.Printf("  Storage backend: %s\n", st.Environment.Storage)
+       fmt.Printf("  Storage version: %s\n", st.Environment.StorageVersion)
+       fmt.Printf("  Container backend: %s\n", st.Environment.Driver)
+       fmt.Printf("  Container version: %s\n", st.Environment.DriverVersion)
+       fmt.Printf("\n")
+       fmt.Printf("Test variables:\n")
+       fmt.Printf("  Container count: %d\n", count)
+       fmt.Printf("  Container mode: %s\n", privilegedStr)
+       fmt.Printf("  Image: %s\n", image)
+       fmt.Printf("  Batches: %d\n", batches)
+       fmt.Printf("  Batch size: %d\n", batch)
+       fmt.Printf("  Remainder: %d\n", remainder)
+       fmt.Printf("\n")
+
+       // Pre-load the image
+       var fingerprint string
+       if strings.Contains(image, ":") {
+               var remote string
+               remote, fingerprint = 
lxd.DefaultConfig.ParseRemoteAndContainer(image)
+
+               if fingerprint == "" {
+                       fingerprint = "default"
+               }
+
+               d, err := lxd.NewClient(&lxd.DefaultConfig, remote)
+               if err != nil {
+                       return err
+               }
+
+               target := d.GetAlias(fingerprint)
+               if target != "" {
+                       fingerprint = target
+               }
+
+               _, err = c.GetImageInfo(fingerprint)
+               if err != nil {
+                       logf("Importing image into local store: %s", 
fingerprint)
+                       err := d.CopyImage(fingerprint, c, false, nil, false, 
false, nil)
+                       if err != nil {
+                               return err
+                       }
+               } else {
+                       logf("Found image in local store: %s", fingerprint)
+               }
+       } else {
+               fingerprint = image
+               logf("Found image in local store: %s", fingerprint)
+       }
+
+       // Start the containers
+       spawnedCount := 0
+       nameFormat := "benchmark-%." + fmt.Sprintf("%d", len(fmt.Sprintf("%d", 
count))) + "d"
+       wgBatch := sync.WaitGroup{}
+       nextStat := batch
+
+       startContainer := func(name string) {
+               defer wgBatch.Done()
+
+               // Configure
+               config := map[string]string{}
+               if privileged {
+                       config["security.privileged"] = "true"
+               }
+               config["user.lxd-benchmark"] = "true"
+
+               // Create
+               resp, err := c.Init(name, "local", fingerprint, nil, config, 
false)
+               if err != nil {
+                       logf(fmt.Sprintf("Failed to spawn container '%s': %s", 
name, err))
+                       return
+               }
+
+               err = c.WaitForSuccess(resp.Operation)
+               if err != nil {
+                       logf(fmt.Sprintf("Failed to spawn container '%s': %s", 
name, err))
+                       return
+               }
+
+               // Start
+               resp, err = c.Action(name, "start", -1, false, false)
+               if err != nil {
+                       logf(fmt.Sprintf("Failed to spawn container '%s': %s", 
name, err))
+                       return
+               }
+
+               err = c.WaitForSuccess(resp.Operation)
+               if err != nil {
+                       logf(fmt.Sprintf("Failed to spawn container '%s': %s", 
name, err))
+                       return
+               }
+       }
+
+       logf("Starting the test")
+       timeStart := time.Now()
+
+       for i := 0; i < batches; i++ {
+               for j := 0; j < batch; j++ {
+                       spawnedCount = spawnedCount + 1
+                       name := fmt.Sprintf(nameFormat, spawnedCount)
+
+                       wgBatch.Add(1)
+                       go startContainer(name)
+               }
+               wgBatch.Wait()
+
+               if spawnedCount >= nextStat {
+                       interval := time.Since(timeStart).Seconds()
+                       logf("Started %d containers in %.3fs (%.3f/s)", 
spawnedCount, interval, float64(spawnedCount)/interval)
+                       nextStat = nextStat * 2
+               }
+       }
+
+       for k := 0; k < remainder; k++ {
+               spawnedCount = spawnedCount + 1
+               name := fmt.Sprintf(nameFormat, spawnedCount)
+
+               wgBatch.Add(1)
+               go startContainer(name)
+       }
+       wgBatch.Wait()
+
+       logf("Test completed in %.3fs", time.Since(timeStart).Seconds())
+
+       return nil
+}
+
+func deleteContainers(c *lxd.Client) error {
+       // Detect the number of parallel actions
+       cpus, err := ioutil.ReadDir("/sys/bus/cpu/devices")
+       if err != nil {
+               return err
+       }
+
+       // List all the containers
+       allContainers, err := c.ListContainers()
+       if err != nil {
+               return err
+       }
+
+       containers := []shared.ContainerInfo{}
+       for _, container := range allContainers {
+               if container.Config["user.lxd-benchmark"] != "true" {
+                       continue
+               }
+
+               containers = append(containers, container)
+       }
+
+       // Delete them all
+       count := len(containers)
+       logf("%d containers to delete", count)
+
+       batch := len(cpus)
+       batches := count / batch
+
+       deletedCount := 0
+       wgBatch := sync.WaitGroup{}
+       nextStat := batch
+
+       deleteContainer := func(ct shared.ContainerInfo) {
+               defer wgBatch.Done()
+
+               // Stop
+               if ct.IsActive() {
+                       resp, err := c.Action(ct.Name, "stop", -1, true, false)
+                       if err != nil {
+                               logf("Failed to delete container: %s", ct.Name)
+                               return
+                       }
+
+                       err = c.WaitForSuccess(resp.Operation)
+                       if err != nil {
+                               logf("Failed to delete container: %s", ct.Name)
+                               return
+                       }
+               }
+
+               // Delete
+               resp, err := c.Delete(ct.Name)
+               if err != nil {
+                       logf("Failed to delete container: %s", ct.Name)
+                       return
+               }
+
+               err = c.WaitForSuccess(resp.Operation)
+               if err != nil {
+                       logf("Failed to delete container: %s", ct.Name)
+                       return
+               }
+       }
+
+       logf("Starting the cleanup")
+       timeStart := time.Now()
+
+       for i := 0; i < batches; i++ {
+               for j := 0; j < batch; j++ {
+                       wgBatch.Add(1)
+                       go deleteContainer(containers[deletedCount])
+
+                       deletedCount = deletedCount + 1
+               }
+               wgBatch.Wait()
+
+               if deletedCount >= nextStat {
+                       interval := time.Since(timeStart).Seconds()
+                       logf("Deleted %d containers in %.3fs (%.3f/s)", 
deletedCount, interval, float64(deletedCount)/interval)
+                       nextStat = nextStat * 2
+               }
+       }
+
+       for k := deletedCount; k < count; k++ {
+               wgBatch.Add(1)
+               go deleteContainer(containers[deletedCount])
+
+               deletedCount = deletedCount + 1
+       }
+       wgBatch.Wait()
+
+       logf("Cleanup completed")
+
+       return nil
+}
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to