[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH RFC 51/59] controller: Make and/or modify cpupools when possible



From: George Dunlap <george.dunlap@xxxxxxxxxx>

Make it possible for schedbench to modify cpupools in order to satisfy
run constraints.

Make a "RunConfig" option which contains the name of the pool, the
scheduler, and the number of cpus.  As with WorkerConfig, make these
automatically inherited from larger levels to smaller levels.  This
makes it straightforward to allow arbitrary pool configurations in the
same plan.

Modify sample.bench to have a RunConfig entry at the top level
(instead of the WorkerConfig option).  SimplePlan already sets
RunConfig.Scheduler, so the effect will be for each run to have all
three options set.  (Punt on SimplePlan generating more complex
options for now.)

Change BenchmarkRun.Ready() to BenchmarkRun.Prep(), which will cause
the configuration in RunConfig to become true if possible.  Empty
'Pool' element means the default pool (Pool-0).  Always create the
cpupool if it's non-pool-0, destroying the current one if it exists.

If it is pool 0, just check if it matches, and skip if not.

(We could in theory modify cpupool 0, but push that for future work.)

Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxx>
---
 benchmark.go |  17 +++++-
 run.go       | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 169 insertions(+), 24 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index aecb574..bd513fd 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -67,7 +67,6 @@ func (l *WorkerConfig) PropagateFrom(g WorkerConfig) {
        }
 }
 
-
 type WorkerSet struct {
        Params WorkerParams
        Config WorkerConfig
@@ -140,6 +139,21 @@ type BenchmarkRunData struct {
 
 type RunConfig struct {
        Scheduler string
+       Pool string
+       Cpus []int
+}
+
+// Propagate unset values from a higher level
+func (l *RunConfig) PropagateFrom(g RunConfig) {
+       if l.Pool == "" {
+               l.Pool = g.Pool
+       }
+       if l.Scheduler == "" {
+               l.Scheduler = g.Scheduler
+       }
+       if l.Cpus == nil {
+               l.Cpus = g.Cpus
+       }
 }
 
 type BenchmarkRun struct {
@@ -159,6 +173,7 @@ type BenchmarkPlan struct {
        // Global options for workers that will be over-ridden by Run
        // and WorkerSet config options
        WorkerConfig         `json:",omitempty"`
+       RunConfig RunConfig   `json:",omitempty"`
        Runs []BenchmarkRun  `json:",omitempty"`
 }
 
diff --git a/run.go b/run.go
index 1a753bc..2d0db01 100644
--- a/run.go
+++ b/run.go
@@ -156,34 +156,158 @@ func getCpuHz() (err error) {
        return
 }
 
-func (run *BenchmarkRun) Ready() (ready bool, why string) {
-       // FIXME: Check WorkerType
-       // Skip this run if it's not the scheduler we want
-       if run.RunConfig.Scheduler != "" {
-               var pool CpupoolInfo
-               if run.WorkerConfig.Pool != "" {
-                       var found bool
-                       pool, found = 
Ctx.CpupoolFindByName(run.WorkerConfig.Pool)
-                       if !found {
-                               why = "cpupool error"
-                               return
-                       }
-               } else {
-                       // xl defaults to cpupool 0
-                       plist := Ctx.ListCpupool()
-                       if len(plist) > 0 {
-                               pool = plist[0]
+// If the pool is specified, use that pool; otherwise assume pool 0.
+//
+// Unspecified schedulers match any pool; unspecifiend cpu lists match
+// any pool.
+//
+// If the pool exists and the scheduler and cpu lists match the pool,
+// carry on.  (This is running the VMs in a pre-configured pool.)
+//
+// If the pool exists and either the scheduler or the cpus don't match
+// the pool, and this is pool 0, skip.
+//
+// TODO: If the scheduler matches but the cpus don't, modify the pool
+// by adding or removing cpus.  (This can be done for Pool-0 as well.)
+//
+// If the pool is not Pool-0, and the scheduler doesn't match or the
+// pool doesn't exist, but there are no cpus, skip (because we don't
+// have enough information to create the pool).
+//
+// If the pool is not Pool-0, and either the scheduler or the cpus
+// don't match, and the cpus are specified, create the pool.
+func (run *BenchmarkRun) Prep() (ready bool, why string) {
+       var pool CpupoolInfo
+       poolPresent := false
+       
+       // Generate the requested cpumap
+       var Cpumap Bitmap
+       if run.RunConfig.Cpus != nil {
+               fmt.Print("Run.Prep: Cpus: ")
+               printed := false
+               for _, i := range run.RunConfig.Cpus {
+                       if printed {
+                               fmt.Printf(",%d", i)
                        } else {
-                               why = "cpupool error"
-                               return
+                               printed = true
+                               fmt.Printf("%d", i)
+                       }                               
+                       Cpumap.Set(i)
+               }
+               fmt.Print("\n")
+               if Cpumap.IsEmpty() {
+                       why = "Invalid (empty) cpumap"
+                       return
+               }
+       }
+       
+
+       if run.RunConfig.Pool == "" {
+               fmt.Printf("Run.Prep: No pool set, using 0\n")
+               pool = Ctx.CpupoolInfo(0)
+               poolPresent = true
+       } else {
+               pool, poolPresent = Ctx.CpupoolFindByName(run.RunConfig.Pool)
+               if poolPresent {
+                       fmt.Printf("Run.Prep: Pool %s found, Poolid %d\n",
+                               run.RunConfig.Pool, pool.Poolid)
+               } else {
+                       fmt.Printf("Run.Prep: Pool %s not found\n")
+               }
+       }
+
+       schedMatches := true
+       if run.RunConfig.Scheduler != "" &&
+               poolPresent &&
+               pool.Scheduler.String() != run.RunConfig.Scheduler {
+                       schedMatches = false;
+       }
+
+       cpuMatches := true
+       if run.RunConfig.Cpus != nil {
+               if !poolPresent {
+                       cpuMatches = false
+               } else {
+                       for i := 0; i <= pool.Cpumap.Max(); i++ {
+                               if pool.Cpumap.Test(i) != Cpumap.Test(i) {
+                                       fmt.Printf("Prep: cpu %d: pool %v, want 
%v, bailing\n",
+                                               i, pool.Cpumap.Test(i), 
Cpumap.Test(i))
+                                       cpuMatches = false
+                                       break
+                               }
                        }
                }
+       }
+               
+
+       // If we're using pool 0, and the scheduler or cpus don't
+       // match, bail; otherwise say we're ready.
+       if poolPresent && pool.Poolid == 0 {
+               if ! schedMatches {
+                       why = "scheduler != "+run.RunConfig.Scheduler+", can't 
change"
+                       return
+               }
 
-               if pool.Scheduler.String() != run.RunConfig.Scheduler {
-                       why = "scheduler != "+run.RunConfig.Scheduler
-                       return 
+               // TODO: Actually, we can modify pool 0; leave this until we 
want it.
+               if ! cpuMatches {
+                       why = "Cpumap mismatch"
+                       return
                }
+
+               fmt.Printf("Prep: Poolid 0, sched and cpumap matches\n")
+               ready = true
+               return
        }
+
+       // OK, we got here it
+       if run.RunConfig.Cpus == nil {
+               // No construction information; is the cpupool ready without it?
+               if !poolPresent {
+                       why = "Pool not present, no pool construction 
information"
+                       return
+               } else if !schedMatches {
+                       why = "scheduler != "+run.RunConfig.Scheduler+", no 
pool construction information"
+                       return
+               }
+
+               // Scheduler matches, pool present, cpus not
+               // specified, just go with it
+               ready = true
+               return
+       }
+
+       // OK, we have all the information we need to create the pool we want.
+       Scheduler := SchedulerCredit
+       err := Scheduler.FromString(run.RunConfig.Scheduler)
+       if err != nil {
+               why = "Invalid scheduler: "+run.RunConfig.Scheduler
+               return
+       }
+
+       // Destroy the pool if it's present;
+       if poolPresent {
+               err := Ctx.CpupoolDestroy(pool.Poolid)
+               if err != nil {
+                       fmt.Printf("Trying to destroy pool: %v\n", err)
+                       why = "Couldn't destroy cpupool"
+                       return
+               }
+       }
+
+       // Free the cpus we need;
+       err = Ctx.CpupoolMakeFree(Cpumap)
+       if err != nil {
+               why = "Couldn't free cpus"
+               return
+       }
+
+       // And create the pool.
+       err, _ = Ctx.CpupoolCreate("schedbench", Scheduler, Cpumap)
+       if err != nil {
+               why = "Couldn't create cpupool"
+               return
+       }
+
        ready = true
        return 
 }
@@ -191,13 +315,18 @@ func (run *BenchmarkRun) Ready() (ready bool, why string) 
{
 func (run *BenchmarkRun) Run() (err error) {
        for wsi := range run.WorkerSets {
                run.WorkerSets[wsi].Config.PropagateFrom(run.WorkerConfig)
+               if run.WorkerSets[wsi].Config.Pool == "" {
+                       run.WorkerSets[wsi].Config.Pool = run.RunConfig.Pool
+               }
                run.WorkerSets[wsi].Params.SetkHZ(CpukHZ)
+               
        }
        
        Workers, err := NewWorkerList(run.WorkerSets, WorkerXen)
        if err != nil {
                fmt.Println("Error creating workers: %v", err)
                return
+
        }
        
        report := make(chan WorkerReport)
@@ -272,7 +401,8 @@ func (plan *BenchmarkPlan) Run() (err error) {
                r := &plan.Runs[i];
                if ! r.Completed { 
                        r.WorkerConfig.PropagateFrom(plan.WorkerConfig)
-                       ready, why := r.Ready()
+                       r.RunConfig.PropagateFrom(plan.RunConfig)
+                       ready, why := r.Prep()
                        if ready {
                                fmt.Printf("Running test [%d] %s\n", i, r.Label)
                                err = r.Run()
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.