[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |