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

[Xen-devel] [PATCH RFC 12/59] Basic 'report' functionality



From: George Dunlap <george.dunlap@xxxxxxxxxx>

Go through the raw data and re-calculate throughput for each
timeframe.  Record for each worker the min and max of these; then take
an average over the whole run.

Have the report go through each and show the worker setup, as well as
the avg, min, and max for each worker.

Also default to running Xen again (rather than processes), and clean
up some chattiness wrt starting Xen processes.

Finally, make the "plan" slightly more programmatic, and test a more
"pipelined" testcase.

Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxx>
---
 benchmark.go | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 main.go      |  56 ++++++++++++++++----
 xenworker.go |   4 +-
 3 files changed, 205 insertions(+), 18 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index b2b2399..ec62c3d 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -9,6 +9,12 @@ import (
        "encoding/json"
 )
 
+type WorkerSummary struct {
+       MaxTput float64
+       AvgTput float64
+       MinTput float64
+}
+
 type WorkerReport struct {
        Id int
        Now int
@@ -43,6 +49,14 @@ type WorkerState struct {
        LastReport WorkerReport
 }
 
+func Throughput(lt int, lm int, t int, m int) (tput float64) {
+       time := float64(t - lt) / SEC
+       mops := m - lm
+       
+       tput = float64(mops) / time
+       return
+}
+
 func Report(ws *WorkerState, r WorkerReport) {
        //fmt.Println(r)
 
@@ -52,8 +66,8 @@ func Report(ws *WorkerState, r WorkerReport) {
                time := float64(r.Now - lr.Now) / SEC
                mops := r.Mops - lr.Mops
 
-               tput := float64(mops) / time
-
+               tput := Throughput(lr.Now, lr.Mops, r.Now, r.Mops)
+               
                fmt.Printf("%d Time: %2.3f Mops: %d Tput: %4.2f\n", r.Id, time, 
mops, tput);
        }
 
@@ -114,19 +128,21 @@ func NewWorkerList(workers []WorkerSet, workerType int) 
(ws WorkerList, err erro
 }
 
 type BenchmarkRunData struct {
-       Raw []WorkerReport
+       WorkerCount int
+       Raw []WorkerReport       `json:",omitempty"`
+       Summary []WorkerSummary  `json:",omitempty"`
 }
 
 type BenchmarkRun struct {
-       Completed bool
        Label string
        Workers []WorkerSet
        RuntimeSeconds int
+       Completed bool
        Results BenchmarkRunData 
 }
 
 func (run *BenchmarkRun) Run() (err error) {
-       Workers, err := NewWorkerList(run.Workers, WorkerProcess)
+       Workers, err := NewWorkerList(run.Workers, WorkerXen)
        if err != nil {
                fmt.Println("Error creating workers: %v", err)
                return
@@ -140,6 +156,8 @@ func (run *BenchmarkRun) Run() (err error) {
        
        i := Workers.Start(report, done)
 
+       run.Results.WorkerCount = i
+
        // FIXME:
        // 1. Make a zero timeout mean "never"
        // 2. Make the signals / timeout thing a bit more rational; signal then 
timeout shouldn't hard kill
@@ -178,8 +196,121 @@ func (run *BenchmarkRun) Run() (err error) {
        return
 }
 
+func (run *BenchmarkRun) checkSummary() (done bool, err error) {
+       if run.Results.WorkerCount == 0 {
+               err = fmt.Errorf("Internal error: WorkerCount 0!")
+               return
+       }
+       
+       if len(run.Results.Summary) == run.Results.WorkerCount {
+               done = true
+               return 
+       }
+       
+       if len(run.Results.Summary) != 0 {
+               err = fmt.Errorf("Internal error: len(Summary) %d, len(Workers) 
%d!\n",
+                       len(run.Results.Summary), run.Results.WorkerCount)
+               return
+       }
+
+       return
+}
+
+func (run *BenchmarkRun) Process() (err error) {
+       done, err := run.checkSummary()
+       if done || err != nil {
+               return
+       }
+       
+       wcount := run.Results.WorkerCount
+
+       if len(run.Results.Summary) != 0 {
+               err = fmt.Errorf("Internal error: len(Summary) %d, len(Workers) 
%d!\n",
+                       len(run.Results.Summary), wcount)
+               return
+       }
+
+       run.Results.Summary = make([]WorkerSummary, wcount)
+
+       // FIXME: Filter out results which started before all have started
+       
+       data := make([]struct{
+               startTime int
+               lastTime int
+               lastMops int}, wcount)
+
+       for i := range run.Results.Raw {
+               e := run.Results.Raw[i]
+               if e.Id > wcount {
+                       err = fmt.Errorf("Internal error: id %d > wcount %d", 
e.Id, wcount)
+                       return
+               }
+               
+               d := &data[e.Id]
+               s := &run.Results.Summary[e.Id]
+
+               if d.startTime == 0 {
+                       d.startTime = e.Now
+               } else {
+                       tput := Throughput(d.lastTime, d.lastMops, e.Now, 
e.Mops)
+               
+                       if tput > s.MaxTput {
+                               s.MaxTput = tput
+                       }
+                       if tput < s.MinTput || s.MinTput == 0 {
+                               s.MinTput = tput
+                       }
+               }
+               d.lastTime = e.Now
+               d.lastMops = e.Mops
+       }
+
+       for i := range data {
+               run.Results.Summary[i].AvgTput = Throughput(data[i].startTime, 
0, data[i].lastTime, data[i].lastMops)
+       }
+       
+       return
+}
+
+func (run *BenchmarkRun) TextReport() (err error) {
+       var done bool
+       done, err = run.checkSummary()
+       if err != nil {
+               return
+       }
+       if ! done {
+               err = fmt.Errorf("Run not yet processed")
+               return
+       }
+
+       fmt.Printf("== RUN %s ==", run.Label)
+
+       fmt.Printf(" Workers (%d total):\n", run.Results.WorkerCount)
+       wStart := 0
+       for i := range run.Workers {
+               ws := &run.Workers[i]
+               n := ws.Count
+               params := ""
+               for _, s := range ws.Params.Args {
+                       params = fmt.Sprintf("%s %s", params, s)
+               }
+               fmt.Printf("[%d-%d]: %s\n", wStart, wStart+n-1, params)
+               wStart += n
+       }
+
+       fmt.Printf("\n%8s %8s %8s %8s\n", "id", "avg", "min", "max")
+       for i := 0; i < run.Results.WorkerCount; i++ {
+               s := &run.Results.Summary[i]
+               fmt.Printf("%8d %8.2f %8.2f %8.2f\n",
+                       i, s.AvgTput, s.MinTput, s.MaxTput)
+       }
+
+       return
+}
+
 type BenchmarkPlan struct {
        filename string
+       WorkerType int
        Runs []BenchmarkRun
 }
 
@@ -254,3 +385,25 @@ func (plan *BenchmarkPlan) Save() (err error) {
        }
        return
 }
+
+func (plan *BenchmarkPlan) TextReport() (err error) {
+       for i := range plan.Runs {
+               r := &plan.Runs[i]
+               if ! r.Completed {
+                       fmt.Printf("Test [%d] %s not run\n", i, r.Label)
+               }
+
+               err = r.Process()
+               if err != nil {
+                       fmt.Printf("Error processing [%d] %s: %v\n", i, 
r.Label, err)
+                       return
+               }
+
+               err = r.TextReport()
+               if err != nil {
+                       return
+               }
+       }
+
+       return
+}
diff --git a/main.go b/main.go
index 4d9701c..2696810 100644
--- a/main.go
+++ b/main.go
@@ -10,27 +10,48 @@ func main() {
 
        switch(os.Args[1]) {
        case "plan":
+               workerA := []string{"burnwait", "20", "20000000"}
+               //workerB := []string{"burnwait", "10", "20000000"}
+               workerB := []string{"burnwait", "1", "20000000",
+                       "burnwait", "2", "20000000",
+                       "burnwait", "1", "20000000",
+                       "burnwait", "1", "20000000",
+                       "burnwait", "1", "20000000",
+                       "burnwait", "1", "20000000",
+                       "burnwait", "3", "20000000",
+               }
+
+
                plan :=  BenchmarkPlan{
+                       WorkerType:WorkerXen,
                        filename:filename,
                        Runs:[]BenchmarkRun{
                                {Label:"baseline-a",
                                        Workers:[]WorkerSet{
-                                               
{Params:WorkerParams{[]string{"burnwait", "20", "20000000"}},
+                                               {Params:WorkerParams{workerA},
                                                        Count:1}},
-                                       RuntimeSeconds:5,},
+                                       RuntimeSeconds:10,},
                                {Label:"baseline-b",
                                        Workers:[]WorkerSet{
-                                               
{Params:WorkerParams{[]string{"burnwait", "10", "20000000"}},
+                                               {Params:WorkerParams{workerB},
                                                        Count:1}},
-                                       RuntimeSeconds:5,},
-                               {Label:"4a+4b",
-                                       Workers:[]WorkerSet{
-                                               
{Params:WorkerParams{[]string{"burnwait", "20", "20000000"}},
-                                                       Count:4},
-                                               
{Params:WorkerParams{[]string{"burnwait", "10", "30000000"}},
-                                                       Count:4}},
-                                       RuntimeSeconds:5,},
+                                       RuntimeSeconds:10,},
                        }}
+
+
+               for i := 1; i <= 16 ; i *= 2 {
+                       label := fmt.Sprintf("%da+%db", i, i)
+                       run := BenchmarkRun{
+                               Label:label,
+                               Workers:[]WorkerSet{
+                                       {Params:WorkerParams{workerA},
+                                               Count:i},
+                                       {Params:WorkerParams{workerB},
+                                               Count:i}},
+                               RuntimeSeconds:10}
+                       plan.Runs = append(plan.Runs, run)
+               }
+               
                err := plan.Save()
                if err != nil {
                        fmt.Println("Saving plan ", filename, " ", err)
@@ -49,6 +70,19 @@ func main() {
                        fmt.Println("Running benchmark run:", err)
                        os.Exit(1)
                }
+               
+       case "report":
+               plan, err := LoadBenchmark(filename)
+               if err != nil {
+                       fmt.Println("Loading benchmark ", filename, " ", err)
+                       os.Exit(1)
+               }
+       
+               err = plan.TextReport()
+               if err != nil {
+                       fmt.Println("Running benchmark run:", err)
+                       os.Exit(1)
+               }
        default:
                fmt.Println("Unknown argument: ", os.Args[1])
        }
diff --git a/xenworker.go b/xenworker.go
index 6023c50..1ed5cf0 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -105,7 +105,7 @@ func (w *XenWorker) Init(p WorkerParams) (err error) {
                        return
                }
 
-               fmt.Printf(" %s domid %d\n", w.vmname, w.domid)
+               //fmt.Printf(" %s domid %d\n", w.vmname, w.domid)
        }
        
        // Set xenstore config
@@ -133,7 +133,7 @@ func (w *XenWorker) Init(p WorkerParams) (err error) {
                //fmt.Printf("json:\n%s\n", string(rcfgBytes))
                rcfgPath := fmt.Sprintf("/local/domain/%d/rumprun/cfg", w.domid)
 
-               fmt.Printf("Writing to %s, json config %s\n", rcfgPath, 
rcfgBytes)
+               //fmt.Printf("Writing to %s, json config %s\n", rcfgPath, 
rcfgBytes)
                
                args := []string{"xenstore-write", rcfgPath, string(rcfgBytes)}
                if mock {
-- 
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®.