All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 01/59] Initial controller framework
@ 2016-12-29  1:13 Ronald Rojas
  2016-12-29  1:13 ` [PATCH RFC 02/59] controller: Revamp communication structure Ronald Rojas
                   ` (57 more replies)
  0 siblings, 58 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:13 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Go code to execute a worker and parse its output.

The go json marshaller needs capitalized structure elements; make the
output match.

Also add fflush()-es to make sure that output actually gets to the controller
in a timely manner.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile | 12 ++++++++++
 main.go  | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+)
 create mode 100644 Makefile
 create mode 100644 main.go

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..736d959
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
+BIN = controller
+BINALL = $(BIN)
+
+.PHONY: all
+all: $(BIN)
+
+controller: main.go
+	go build -o $@ $<
+
+.PHONY: clean
+clean:
+	rm -f $(BINALL)
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..6e90754
--- /dev/null
+++ b/main.go
@@ -0,0 +1,78 @@
+package main
+
+import (
+	"fmt"
+	"os/exec"
+	"encoding/json"
+	"bufio"
+	"io"
+)
+
+type Worker struct {
+	c *exec.Cmd
+
+	stdout io.ReadCloser
+	
+	jsonStarted bool
+}
+
+type WorkerReport struct {
+	Now int
+	Mops int
+	MaxDelta int
+}
+
+func (w *Worker) Start() (err error) {
+	w.c = exec.Command("../worker/worker-proc", "burnwait", "20", "20000000")
+	
+
+	w.stdout, err = w.c.StdoutPipe()
+	if err != nil {
+		fmt.Print("Conneting to stdout: ", err)
+		return
+	}
+
+	w.c.Start()
+
+	b, err := json.Marshal(WorkerReport{5,6,7})
+	fmt.Print("Example json: ", string(b))
+	
+	return
+}
+
+func (w *Worker) Wait() {
+	w.c.Wait()
+}
+
+func (w *Worker) Process() {
+	scanner := bufio.NewScanner(w.stdout)
+
+	for scanner.Scan() {
+		s := scanner.Text()
+		
+		fmt.Println("Got these bytes: ", s);
+
+		if w.jsonStarted {
+			var r WorkerReport
+			
+			json.Unmarshal([]byte(s), &r)
+			fmt.Println(r)
+		} else {
+			if s == "START JSON" {
+				fmt.Println("Got token to start parsing json")
+				w.jsonStarted = true
+			}
+		}
+	}
+}
+
+func main() {
+
+	w:=Worker{}
+	
+	w.Start()
+
+	w.Process()
+
+	w.Wait()
+}
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 02/59] controller: Revamp communication structure
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
@ 2016-12-29  1:13 ` Ronald Rojas
  2016-12-29  1:13 ` [PATCH RFC 03/59] controller: Initial attempt to generalize process / vm creation Ronald Rojas
                   ` (56 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:13 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Two general-purporse channels rather than one per worker.

Set up two workers, gather and collate the information at the central
station.

Have the worker print out a report at start-of-day, so we get timing
information for the first actual report.

Catch SIGINT as a shorthand testing way of managing tear-down
gracefully.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 78 insertions(+), 18 deletions(-)

diff --git a/main.go b/main.go
index 6e90754..0cb9f51 100644
--- a/main.go
+++ b/main.go
@@ -2,13 +2,18 @@ package main
 
 import (
 	"fmt"
+	"os"
 	"os/exec"
+	"os/signal"
 	"encoding/json"
 	"bufio"
 	"io"
+	
 )
 
 type Worker struct {
+	Id int
+	
 	c *exec.Cmd
 
 	stdout io.ReadCloser
@@ -17,14 +22,14 @@ type Worker struct {
 }
 
 type WorkerReport struct {
+	Id int
 	Now int
 	Mops int
 	MaxDelta int
 }
 
-func (w *Worker) Start() (err error) {
+func (w *Worker) Init() (err error) {
 	w.c = exec.Command("../worker/worker-proc", "burnwait", "20", "20000000")
-	
 
 	w.stdout, err = w.c.StdoutPipe()
 	if err != nil {
@@ -32,47 +37,102 @@ func (w *Worker) Start() (err error) {
 		return
 	}
 
-	w.c.Start()
-
-	b, err := json.Marshal(WorkerReport{5,6,7})
-	fmt.Print("Example json: ", string(b))
-	
 	return
 }
 
-func (w *Worker) Wait() {
-	w.c.Wait()
+func (w *Worker) Shutdown() {
+	w.c.Process.Kill()
 }
 
-func (w *Worker) Process() {
+func (w *Worker) Process(report chan WorkerReport, done chan bool) {
+	w.c.Start()
+
 	scanner := bufio.NewScanner(w.stdout)
 
 	for scanner.Scan() {
 		s := scanner.Text()
 		
-		fmt.Println("Got these bytes: ", s);
+		//fmt.Println("Got these bytes: ", s);
 
 		if w.jsonStarted {
 			var r WorkerReport
-			
 			json.Unmarshal([]byte(s), &r)
-			fmt.Println(r)
+			r.Id = w.Id
+			report <- r
 		} else {
 			if s == "START JSON" {
-				fmt.Println("Got token to start parsing json")
+				//fmt.Println("Got token to start parsing json")
 				w.jsonStarted = true
 			}
 		}
 	}
+
+	done <- true
+
+	w.c.Wait()
+}
+
+const (
+	USEC = 1000
+	MSEC = USEC * 1000
+	SEC = MSEC * 1000
+)
+
+type WorkerState struct {
+	Worker
+	LastReport WorkerReport
+}
+
+func Report(ws *WorkerState, r WorkerReport) {
+	//fmt.Println(r)
+
+	lr := ws.LastReport
+
+	if (lr.Now > 0) {
+		time := float64(r.Now - lr.Now) / SEC
+		mops := r.Mops - lr.Mops
+
+		tput := float64(mops) / time
+
+		fmt.Printf("%d Time: %2.3f Mops: %d Tput: %4.2f\n", r.Id, time, mops, tput);
+	}
+
+	ws.LastReport = r
 }
 
 func main() {
+	count := 2
+	
+	report := make(chan WorkerReport)
+	done := make(chan bool)
+	signals := make(chan os.Signal, 1)
 
-	w:=Worker{}
+	signal.Notify(signals, os.Interrupt)
 	
-	w.Start()
+	i := 0
 
-	w.Process()
+	Workers := make([]WorkerState, count)
+	
+	for i = 0; i< count; i++ {
+		Workers[i].Id = i
+		
+		Workers[i].Init()
+		
+		go Workers[i].Process(report, done)
+	}
 
-	w.Wait()
+	for i > 0 {
+		select {
+		case r := <-report:
+			Report(&Workers[r.Id], r)
+		case <-done:
+			i--;
+			fmt.Println(i, "workers left");
+		case <-signals:
+			fmt.Println("SIGINT receieved, shutting down workers")
+			for j := range Workers {
+				Workers[j].Shutdown()
+			}
+		}
+	}
 }
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 03/59] controller: Initial attempt to generalize process / vm creation
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
  2016-12-29  1:13 ` [PATCH RFC 02/59] controller: Revamp communication structure Ronald Rojas
@ 2016-12-29  1:13 ` Ronald Rojas
  2016-12-29  1:13 ` [PATCH RFC 04/59] Controller: Move process worker into its own file Ronald Rojas
                   ` (55 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:13 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Create a "Worker" interface, and have ProcessWorker implement that
interface.

Rename "Worker" to "WorkerReport" to make room for the interface.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 45 +++++++++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/main.go b/main.go
index 0cb9f51..034e2f2 100644
--- a/main.go
+++ b/main.go
@@ -11,24 +11,32 @@ import (
 	
 )
 
-type Worker struct {
+type WorkerReport struct {
 	Id int
-	
-	c *exec.Cmd
+	Now int
+	Mops int
+	MaxDelta int
+}
+
+type Worker interface {
+	SetId(int)
+	Init() error
+	Shutdown()
+	Process(chan WorkerReport, chan bool)
+}
 
+type ProcessWorker struct {
+	id int
+	c *exec.Cmd
 	stdout io.ReadCloser
-	
 	jsonStarted bool
 }
 
-type WorkerReport struct {
-	Id int
-	Now int
-	Mops int
-	MaxDelta int
+func (w *ProcessWorker) SetId(i int) {
+	w.id = i
 }
 
-func (w *Worker) Init() (err error) {
+func (w *ProcessWorker) Init() (err error) {
 	w.c = exec.Command("../worker/worker-proc", "burnwait", "20", "20000000")
 
 	w.stdout, err = w.c.StdoutPipe()
@@ -40,11 +48,11 @@ func (w *Worker) Init() (err error) {
 	return
 }
 
-func (w *Worker) Shutdown() {
+func (w *ProcessWorker) Shutdown() {
 	w.c.Process.Kill()
 }
 
-func (w *Worker) Process(report chan WorkerReport, done chan bool) {
+func (w *ProcessWorker) Process(report chan WorkerReport, done chan bool) {
 	w.c.Start()
 
 	scanner := bufio.NewScanner(w.stdout)
@@ -57,7 +65,7 @@ func (w *Worker) Process(report chan WorkerReport, done chan bool) {
 		if w.jsonStarted {
 			var r WorkerReport
 			json.Unmarshal([]byte(s), &r)
-			r.Id = w.Id
+			r.Id = w.id
 			report <- r
 		} else {
 			if s == "START JSON" {
@@ -79,7 +87,7 @@ const (
 )
 
 type WorkerState struct {
-	Worker
+	w Worker
 	LastReport WorkerReport
 }
 
@@ -114,11 +122,12 @@ func main() {
 	Workers := make([]WorkerState, count)
 	
 	for i = 0; i< count; i++ {
-		Workers[i].Id = i
+		Workers[i].w = &ProcessWorker{}
+		Workers[i].w.SetId(i)
 		
-		Workers[i].Init()
+		Workers[i].w.Init()
 		
-		go Workers[i].Process(report, done)
+		go Workers[i].w.Process(report, done)
 	}
 
 	for i > 0 {
@@ -131,7 +140,7 @@ func main() {
 		case <-signals:
 			fmt.Println("SIGINT receieved, shutting down workers")
 			for j := range Workers {
-				Workers[j].Shutdown()
+				Workers[j].w.Shutdown()
 			}
 		}
 	}
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 04/59] Controller: Move process worker into its own file
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
  2016-12-29  1:13 ` [PATCH RFC 02/59] controller: Revamp communication structure Ronald Rojas
  2016-12-29  1:13 ` [PATCH RFC 03/59] controller: Initial attempt to generalize process / vm creation Ronald Rojas
@ 2016-12-29  1:13 ` Ronald Rojas
  2016-12-29  1:13 ` [PATCH RFC 05/59] controller: Add WorkerParams argument to Init in Worker interface Ronald Rojas
                   ` (54 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:13 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Also fix Makefile rule to use correct automatic variable.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile         |  4 ++--
 main.go          | 59 --------------------------------------------------
 processworker.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+), 61 deletions(-)
 create mode 100644 processworker.go

diff --git a/Makefile b/Makefile
index 736d959..00f732a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,8 @@ BINALL = $(BIN)
 .PHONY: all
 all: $(BIN)
 
-controller: main.go
-	go build -o $@ $<
+controller: main.go processworker.go
+	go build -o $@ $^
 
 .PHONY: clean
 clean:
diff --git a/main.go b/main.go
index 034e2f2..a4986cf 100644
--- a/main.go
+++ b/main.go
@@ -3,11 +3,7 @@ package main
 import (
 	"fmt"
 	"os"
-	"os/exec"
 	"os/signal"
-	"encoding/json"
-	"bufio"
-	"io"
 	
 )
 
@@ -25,61 +21,6 @@ type Worker interface {
 	Process(chan WorkerReport, chan bool)
 }
 
-type ProcessWorker struct {
-	id int
-	c *exec.Cmd
-	stdout io.ReadCloser
-	jsonStarted bool
-}
-
-func (w *ProcessWorker) SetId(i int) {
-	w.id = i
-}
-
-func (w *ProcessWorker) Init() (err error) {
-	w.c = exec.Command("../worker/worker-proc", "burnwait", "20", "20000000")
-
-	w.stdout, err = w.c.StdoutPipe()
-	if err != nil {
-		fmt.Print("Conneting to stdout: ", err)
-		return
-	}
-
-	return
-}
-
-func (w *ProcessWorker) Shutdown() {
-	w.c.Process.Kill()
-}
-
-func (w *ProcessWorker) Process(report chan WorkerReport, done chan bool) {
-	w.c.Start()
-
-	scanner := bufio.NewScanner(w.stdout)
-
-	for scanner.Scan() {
-		s := scanner.Text()
-		
-		//fmt.Println("Got these bytes: ", s);
-
-		if w.jsonStarted {
-			var r WorkerReport
-			json.Unmarshal([]byte(s), &r)
-			r.Id = w.id
-			report <- r
-		} else {
-			if s == "START JSON" {
-				//fmt.Println("Got token to start parsing json")
-				w.jsonStarted = true
-			}
-		}
-	}
-
-	done <- true
-
-	w.c.Wait()
-}
-
 const (
 	USEC = 1000
 	MSEC = USEC * 1000
diff --git a/processworker.go b/processworker.go
new file mode 100644
index 0000000..c1d1fd5
--- /dev/null
+++ b/processworker.go
@@ -0,0 +1,66 @@
+package main
+
+import (
+	"fmt"
+	"os/exec"
+	"encoding/json"
+	"bufio"
+	"io"
+	
+)
+
+type ProcessWorker struct {
+	id int
+	c *exec.Cmd
+	stdout io.ReadCloser
+	jsonStarted bool
+}
+
+func (w *ProcessWorker) SetId(i int) {
+	w.id = i
+}
+
+func (w *ProcessWorker) Init() (err error) {
+	w.c = exec.Command("../worker/worker-proc", "burnwait", "20", "20000000")
+
+	w.stdout, err = w.c.StdoutPipe()
+	if err != nil {
+		fmt.Print("Conneting to stdout: ", err)
+		return
+	}
+
+	return
+}
+
+func (w *ProcessWorker) Shutdown() {
+	w.c.Process.Kill()
+}
+
+func (w *ProcessWorker) Process(report chan WorkerReport, done chan bool) {
+	w.c.Start()
+
+	scanner := bufio.NewScanner(w.stdout)
+
+	for scanner.Scan() {
+		s := scanner.Text()
+		
+		//fmt.Println("Got these bytes: ", s);
+
+		if w.jsonStarted {
+			var r WorkerReport
+			json.Unmarshal([]byte(s), &r)
+			r.Id = w.id
+			report <- r
+		} else {
+			if s == "START JSON" {
+				//fmt.Println("Got token to start parsing json")
+				w.jsonStarted = true
+			}
+		}
+	}
+
+	done <- true
+
+	w.c.Wait()
+}
+
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 05/59] controller: Add WorkerParams argument to Init in Worker interface
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (2 preceding siblings ...)
  2016-12-29  1:13 ` [PATCH RFC 04/59] Controller: Move process worker into its own file Ronald Rojas
@ 2016-12-29  1:13 ` Ronald Rojas
  2016-12-29  1:13 ` [PATCH RFC 06/59] Reorganize to enable "Dist" directory Ronald Rojas
                   ` (53 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:13 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

For now just make it a plain []string; later make it more abstrcted.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go          | 22 +++++++++++++++++-----
 processworker.go |  4 ++--
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/main.go b/main.go
index a4986cf..90388dd 100644
--- a/main.go
+++ b/main.go
@@ -14,9 +14,13 @@ type WorkerReport struct {
 	MaxDelta int
 }
 
+type WorkerParams struct {
+	Args []string
+}
+
 type Worker interface {
 	SetId(int)
-	Init() error
+	Init(WorkerParams) error
 	Shutdown()
 	Process(chan WorkerReport, chan bool)
 }
@@ -49,6 +53,14 @@ func Report(ws *WorkerState, r WorkerReport) {
 	ws.LastReport = r
 }
 
+type WorkerList []WorkerState
+
+func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) {
+	for i := range *ws {
+		go (*ws)[i].w.Process(report, done)
+	}
+}
+
 func main() {
 	count := 2
 	
@@ -60,17 +72,17 @@ func main() {
 	
 	i := 0
 
-	Workers := make([]WorkerState, count)
+	Workers := WorkerList(make([]WorkerState, count))
 	
 	for i = 0; i< count; i++ {
 		Workers[i].w = &ProcessWorker{}
 		Workers[i].w.SetId(i)
 		
-		Workers[i].w.Init()
-		
-		go Workers[i].w.Process(report, done)
+		Workers[i].w.Init(WorkerParams{[]string{"burnwait", "20", "20000000"}})
 	}
 
+	Workers.Start(report, done)
+
 	for i > 0 {
 		select {
 		case r := <-report:
diff --git a/processworker.go b/processworker.go
index c1d1fd5..806e4d7 100644
--- a/processworker.go
+++ b/processworker.go
@@ -20,8 +20,8 @@ func (w *ProcessWorker) SetId(i int) {
 	w.id = i
 }
 
-func (w *ProcessWorker) Init() (err error) {
-	w.c = exec.Command("../worker/worker-proc", "burnwait", "20", "20000000")
+func (w *ProcessWorker) Init(p WorkerParams) (err error) {
+	w.c = exec.Command("../worker/worker-proc", p.Args...)
 
 	w.stdout, err = w.c.StdoutPipe()
 	if err != nil {
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 06/59] Reorganize to enable "Dist" directory
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (3 preceding siblings ...)
  2016-12-29  1:13 ` [PATCH RFC 05/59] controller: Add WorkerParams argument to Init in Worker interface Ronald Rojas
@ 2016-12-29  1:13 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 07/59] controller: Introduce basic Xen functionality Ronald Rojas
                   ` (52 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:13 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Make a toplevel Makefile which defaults to 'make dist'.  Add "make
dist" targets in all subdirs, which copy the distribution files into
$PWD/dist.

Modify processworker.go such that it looks for worker-proc in the same
directory.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile         | 4 ++++
 processworker.go | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 00f732a..332c8d9 100644
--- a/Makefile
+++ b/Makefile
@@ -10,3 +10,7 @@ controller: main.go processworker.go
 .PHONY: clean
 clean:
 	rm -f $(BINALL)
+
+.PHONY: dist
+dist:
+	cp $(BIN) $(DISTDIR)
diff --git a/processworker.go b/processworker.go
index 806e4d7..cca6c3b 100644
--- a/processworker.go
+++ b/processworker.go
@@ -21,7 +21,7 @@ func (w *ProcessWorker) SetId(i int) {
 }
 
 func (w *ProcessWorker) Init(p WorkerParams) (err error) {
-	w.c = exec.Command("../worker/worker-proc", p.Args...)
+	w.c = exec.Command("./worker-proc", p.Args...)
 
 	w.stdout, err = w.c.StdoutPipe()
 	if err != nil {
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 07/59] controller: Introduce basic Xen functionality
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (4 preceding siblings ...)
  2016-12-29  1:13 ` [PATCH RFC 06/59] Reorganize to enable "Dist" directory Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 08/59] controller: Exit after second SIGINT Ronald Rojas
                   ` (51 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Rough-and-ready execution of xl commands, but they work, amazingly.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile     |   2 +-
 main.go      |   3 +-
 xenworker.go | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 234 insertions(+), 2 deletions(-)
 create mode 100644 xenworker.go

diff --git a/Makefile b/Makefile
index 332c8d9..16af528 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ BINALL = $(BIN)
 .PHONY: all
 all: $(BIN)
 
-controller: main.go processworker.go
+controller: main.go processworker.go xenworker.go
 	go build -o $@ $^
 
 .PHONY: clean
diff --git a/main.go b/main.go
index 90388dd..04c8467 100644
--- a/main.go
+++ b/main.go
@@ -75,7 +75,8 @@ func main() {
 	Workers := WorkerList(make([]WorkerState, count))
 	
 	for i = 0; i< count; i++ {
-		Workers[i].w = &ProcessWorker{}
+		//Workers[i].w = &ProcessWorker{}
+		Workers[i].w = &XenWorker{}
 		Workers[i].w.SetId(i)
 		
 		Workers[i].w.Init(WorkerParams{[]string{"burnwait", "20", "20000000"}})
diff --git a/xenworker.go b/xenworker.go
new file mode 100644
index 0000000..6023c50
--- /dev/null
+++ b/xenworker.go
@@ -0,0 +1,231 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"encoding/json"
+	"bufio"
+	"io"
+)
+
+type XenWorker struct {
+	id int
+	vmname string
+	domid int
+	consoleCmd *exec.Cmd
+	console io.ReadCloser
+	jsonStarted bool
+}
+
+// We have to capitalize the element names so that the json class can
+// get access to it; so annotate the elements so they come out lower
+// case
+type RumpRunConfigBlk struct {
+	Source string     `json:"source"`
+	Path string       `json:"path"`
+	Fstype string     `json:"fstype"` 
+	Mountpoint string `json:"mountpoint"`
+}
+
+type RumpRunConfig struct {
+	Blk RumpRunConfigBlk `json:"blk"`
+	Cmdline string       `json:"cmdline"`
+	Hostname string      `json:"hostname"`
+}
+
+func (w *XenWorker) SetId(i int) {
+	w.id = i
+	w.vmname = fmt.Sprintf("worker-%d", i)
+	w.domid = -1 // INVALID DOMID
+}
+
+func (w *XenWorker) Init(p WorkerParams) (err error) {
+	mock := false
+	
+	// Make xl config file
+	//  name=worker-$(id)
+
+	cfgName := os.TempDir()+"/schedbench-"+w.vmname+".cfg"
+
+	cfg, err := os.Create(cfgName)
+	//defer os.Remove(cfgName)
+
+	if err != nil {
+		fmt.Printf("Error creating configfile %s: %v\n", cfgName, err)
+		return
+	}
+
+	fmt.Fprintf(cfg, "name = '%s'\n", w.vmname)
+	fmt.Fprintf(cfg, "kernel = 'worker-xen.img'\n")
+	fmt.Fprintf(cfg, "memory = 32\n")
+	fmt.Fprintf(cfg, "vcpus = 1\n")
+	fmt.Fprintf(cfg, "on_crash = 'destroy'\n")
+
+	
+	// xl create -p [filename]
+	{
+		args := []string{"xl", "create", "-p", cfgName}
+		if mock {
+			args = append([]string{"echo"}, args...)
+		}
+		e := exec.Command(args[0], args[1:]...)
+		
+		e.Stdout = os.Stdout
+		e.Stderr = os.Stderr
+
+		err = e.Run()
+		if err != nil {
+			fmt.Printf("Error creating domain: %v\n", err)
+			return
+		}
+	}
+
+	// Get domid
+	{
+		var domidString []byte
+		var args []string
+		
+		if mock {
+			args = []string{"echo", "232"}
+		} else {
+			args = []string{"xl", "domid", w.vmname}
+		}
+		e := exec.Command(args[0], args[1:]...)
+
+		domidString, err = e.Output()
+		if err != nil {
+			fmt.Printf("Error getting domid: %v\n", err)
+			return
+		}
+
+		_, err = fmt.Sscanf(string(domidString), "%d\n", &w.domid)
+		if err != nil {
+			fmt.Printf("Error converting domid: %v\n", err)
+			return
+		}
+
+		fmt.Printf(" %s domid %d\n", w.vmname, w.domid)
+	}
+	
+	// Set xenstore config
+	{
+		rcfg := RumpRunConfig{
+			Blk:RumpRunConfigBlk{Source:"dev",
+				Path:"virtual",
+				Fstype:"kernfs",
+				Mountpoint:"/kern"},
+			Hostname:w.vmname}
+		
+		rcfg.Cmdline = "worker-xen.img"
+		for _, a := range p.Args {
+			rcfg.Cmdline += fmt.Sprintf(" %s", a)
+		}
+
+		var rcfgBytes []byte
+	
+		rcfgBytes, err = json.Marshal(rcfg)
+		if err != nil {
+			fmt.Printf("Error marshalling rumprun json: %v\n", err)
+			return
+		}
+
+		//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)
+		
+		args := []string{"xenstore-write", rcfgPath, string(rcfgBytes)}
+		if mock {
+			args = append([]string{"echo"}, args...)
+		}
+		e := exec.Command(args[0], args[1:]...)
+		
+		e.Stdout = os.Stdout
+		e.Stderr = os.Stderr
+
+		err = e.Run()
+		if err != nil {
+			fmt.Printf("Error writing json into xenstore: %v\n", err)
+			return
+		}
+	}
+	
+
+	// Run console command, attach to w.console
+	{
+		args := []string{"xl", "console", w.vmname}
+		if mock {
+			args = append([]string{"echo"}, args...)
+		}
+		w.consoleCmd = exec.Command(args[0], args[1:]...)
+
+		w.console, err = w.consoleCmd.StdoutPipe()
+		if err != nil {
+			fmt.Print("Conneting to stdout: ", err)
+			return
+		}
+
+		w.consoleCmd.Start()
+	}
+	
+	return
+}
+
+// FIXME: Return an error
+func (w *XenWorker) Shutdown() {
+	// xl destroy [vmname]
+	e := exec.Command("xl", "destroy", w.vmname)
+
+	e.Stdout = os.Stdout
+	e.Stderr = os.Stderr
+
+	err := e.Run()
+	if err != nil {
+		fmt.Printf("Error destroying domain: %v\n", err)
+		return
+	}
+}
+
+// FIXME: Return an error
+func (w *XenWorker) Process(report chan WorkerReport, done chan bool) {
+	mock := false
+	
+	// xl unpause [vmname]
+	args := []string{"xl", "unpause", w.vmname}
+	if mock {
+		args = append([]string{"echo"}, args...)
+	}
+	e := exec.Command(args[0], args[1:]...)
+
+	err := e.Run()
+	if err != nil {
+		fmt.Printf("Error unpausing domain: %v\n", err)
+		return
+	}
+
+	scanner := bufio.NewScanner(w.console)
+
+	for scanner.Scan() {
+		s := scanner.Text()
+		
+		//fmt.Println("Got these bytes: ", s);
+
+		if w.jsonStarted {
+			var r WorkerReport
+			json.Unmarshal([]byte(s), &r)
+			r.Id = w.id
+			report <- r
+		} else {
+			if s == "START JSON" {
+				//fmt.Println("Got token to start parsing json")
+				w.jsonStarted = true
+			}
+		}
+	}
+
+	done <- true
+
+	w.consoleCmd.Wait()
+}
+
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 08/59] controller: Exit after second SIGINT
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (5 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 07/59] controller: Introduce basic Xen functionality Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 09/59] controller: Refactor creation and stopping of workers into WorkerList methods Ronald Rojas
                   ` (50 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Otherwise you have to kill -9 the process.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/main.go b/main.go
index 04c8467..dbd6276 100644
--- a/main.go
+++ b/main.go
@@ -62,6 +62,8 @@ func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) {
 }
 
 func main() {
+	killed := false
+	
 	count := 2
 	
 	report := make(chan WorkerReport)
@@ -92,9 +94,15 @@ func main() {
 			i--;
 			fmt.Println(i, "workers left");
 		case <-signals:
-			fmt.Println("SIGINT receieved, shutting down workers")
-			for j := range Workers {
-				Workers[j].w.Shutdown()
+			if ! killed {
+				fmt.Println("SIGINT receieved, shutting down workers")
+				for j := range Workers {
+					Workers[j].w.Shutdown()
+				}
+				killed = true
+			} else {
+				fmt.Println("Second SIGINT received, exiting without cleaning up")
+				os.Exit(1)
 			}
 		}
 	}
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 09/59] controller: Refactor creation and stopping of workers into WorkerList methods
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (6 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 08/59] controller: Exit after second SIGINT Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 10/59] controller: First cut at BenchmarkParams Ronald Rojas
                   ` (49 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 59 ++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 42 insertions(+), 17 deletions(-)

diff --git a/main.go b/main.go
index dbd6276..89e9cf3 100644
--- a/main.go
+++ b/main.go
@@ -55,10 +55,43 @@ func Report(ws *WorkerState, r WorkerReport) {
 
 type WorkerList []WorkerState
 
-func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) {
+func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) (i int) {
+	i = 0
+	for j := range *ws {
+		go (*ws)[j].w.Process(report, done)
+		i++
+	}
+	return
+}
+
+func (ws *WorkerList) Stop() {
 	for i := range *ws {
-		go (*ws)[i].w.Process(report, done)
+		(*ws)[i].w.Shutdown()
+	}
+}
+
+const (
+	WorkerProcess = iota
+	WorkerXen = iota
+)
+
+func NewWorkerList(count int, workerType int) (ws WorkerList, err error) {
+	ws = WorkerList(make([]WorkerState, count))
+
+	for i := 0; i< count; i++ {
+		switch workerType {
+		case WorkerProcess:
+			ws[i].w = &ProcessWorker{}
+		case WorkerXen:
+			ws[i].w = &XenWorker{}
+		default:
+			err = fmt.Errorf("Unknown type: %d", workerType)
+		}
+		ws[i].w.SetId(i)
+		
+		ws[i].w.Init(WorkerParams{[]string{"burnwait", "20", "20000000"}})
 	}
+	return
 }
 
 func main() {
@@ -72,19 +105,13 @@ func main() {
 
 	signal.Notify(signals, os.Interrupt)
 	
-	i := 0
-
-	Workers := WorkerList(make([]WorkerState, count))
-	
-	for i = 0; i< count; i++ {
-		//Workers[i].w = &ProcessWorker{}
-		Workers[i].w = &XenWorker{}
-		Workers[i].w.SetId(i)
-		
-		Workers[i].w.Init(WorkerParams{[]string{"burnwait", "20", "20000000"}})
+	Workers, err := NewWorkerList(count, WorkerProcess)
+	if err != nil {
+		fmt.Println("Error creating workers: %v", err)
+		return
 	}
-
-	Workers.Start(report, done)
+	
+	i := Workers.Start(report, done)
 
 	for i > 0 {
 		select {
@@ -96,9 +123,7 @@ func main() {
 		case <-signals:
 			if ! killed {
 				fmt.Println("SIGINT receieved, shutting down workers")
-				for j := range Workers {
-					Workers[j].w.Shutdown()
-				}
+				Workers.Stop()
 				killed = true
 			} else {
 				fmt.Println("Second SIGINT received, exiting without cleaning up")
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 10/59] controller: First cut at BenchmarkParams
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (7 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 09/59] controller: Refactor creation and stopping of workers into WorkerList methods Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 11/59] Refactor to move towards benchmark "plans" and data analysis Ronald Rojas
                   ` (48 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Struct for configurable worker sets, as well as a set runtime.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 53 insertions(+), 22 deletions(-)

diff --git a/main.go b/main.go
index 89e9cf3..7fbb60a 100644
--- a/main.go
+++ b/main.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"os"
 	"os/signal"
-	
+	"time"
 )
 
 type WorkerReport struct {
@@ -18,6 +18,16 @@ type WorkerParams struct {
 	Args []string
 }
 
+type WorkerSet struct {
+	Params WorkerParams
+	Count int
+}
+
+type BenchmarkParams struct {
+	Workers []WorkerSet
+	RuntimeSeconds int
+}
+
 type Worker interface {
 	SetId(int)
 	Init(WorkerParams) error
@@ -75,29 +85,53 @@ const (
 	WorkerXen = iota
 )
 
-func NewWorkerList(count int, workerType int) (ws WorkerList, err error) {
+func NewWorkerList(workers []WorkerSet, workerType int) (ws WorkerList, err error) {
+	count := 0
+
+	// wsi: WorkerSet index
+	for wsi := range workers {
+		count += workers[wsi].Count
+	}
+
+	fmt.Println("Making ", count, " total workers")
 	ws = WorkerList(make([]WorkerState, count))
 
-	for i := 0; i< count; i++ {
-		switch workerType {
-		case WorkerProcess:
-			ws[i].w = &ProcessWorker{}
-		case WorkerXen:
-			ws[i].w = &XenWorker{}
-		default:
-			err = fmt.Errorf("Unknown type: %d", workerType)
-		}
-		ws[i].w.SetId(i)
+	// wli: WorkerList index
+	wli := 0
+	for wsi := range workers {
+		for i := 0; i < workers[wsi].Count; i, wli = i+1, wli+1 {
+			switch workerType {
+			case WorkerProcess:
+				ws[wli].w = &ProcessWorker{}
+			case WorkerXen:
+				ws[wli].w = &XenWorker{}
+			default:
+				err = fmt.Errorf("Unknown type: %d", workerType)
+			}
+			ws[wli].w.SetId(wli)
 		
-		ws[i].w.Init(WorkerParams{[]string{"burnwait", "20", "20000000"}})
+			ws[wli].w.Init(workers[wsi].Params)
+		}
 	}
 	return
 }
 
 func main() {
-	killed := false
-	
-	count := 2
+	bp :=  BenchmarkParams{
+		Workers:[]WorkerSet{
+			{Params:WorkerParams{[]string{"burnwait", "20", "20000000"}},
+				Count:2},
+			{Params:WorkerParams{[]string{"burnwait", "10", "30000000"}},
+			 	Count:3},
+		},
+		RuntimeSeconds:5,
+	}
+
+	Workers, err := NewWorkerList(bp.Workers, WorkerProcess)
+	if err != nil {
+		fmt.Println("Error creating workers: %v", err)
+		return
+	}
 	
 	report := make(chan WorkerReport)
 	done := make(chan bool)
@@ -105,14 +139,10 @@ func main() {
 
 	signal.Notify(signals, os.Interrupt)
 	
-	Workers, err := NewWorkerList(count, WorkerProcess)
-	if err != nil {
-		fmt.Println("Error creating workers: %v", err)
-		return
-	}
-	
 	i := Workers.Start(report, done)
 
+	timeout := time.After(time.Duration(bp.RuntimeSeconds) * time.Second);
+	killed := false
 	for i > 0 {
 		select {
 		case r := <-report:
@@ -121,6 +151,7 @@ func main() {
 			i--;
 			fmt.Println(i, "workers left");
 		case <-signals:
+		case <-timeout:
 			if ! killed {
 				fmt.Println("SIGINT receieved, shutting down workers")
 				Workers.Stop()
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 11/59] Refactor to move towards benchmark "plans" and data analysis
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (8 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 10/59] controller: First cut at BenchmarkParams Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 12/59] Basic 'report' functionality Ronald Rojas
                   ` (47 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

A bit of a roll-up of lots of bits.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile     |   4 +-
 benchmark.go | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 main.go      | 197 ++++++++++-----------------------------------
 3 files changed, 302 insertions(+), 155 deletions(-)
 create mode 100644 benchmark.go

diff --git a/Makefile b/Makefile
index 16af528..7a33cfb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,10 @@
-BIN = controller
+BIN = schedbench
 BINALL = $(BIN)
 
 .PHONY: all
 all: $(BIN)
 
-controller: main.go processworker.go xenworker.go
+schedbench: main.go processworker.go xenworker.go benchmark.go
 	go build -o $@ $^
 
 .PHONY: clean
diff --git a/benchmark.go b/benchmark.go
new file mode 100644
index 0000000..b2b2399
--- /dev/null
+++ b/benchmark.go
@@ -0,0 +1,256 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/signal"
+	"time"
+	"io/ioutil"
+	"encoding/json"
+)
+
+type WorkerReport struct {
+	Id int
+	Now int
+	Mops int
+	MaxDelta int
+}
+
+type WorkerParams struct {
+	Args []string
+}
+
+type WorkerSet struct {
+	Params WorkerParams
+	Count int
+}
+
+type Worker interface {
+	SetId(int)
+	Init(WorkerParams) error
+	Shutdown()
+	Process(chan WorkerReport, chan bool)
+}
+
+const (
+	USEC = 1000
+	MSEC = USEC * 1000
+	SEC = MSEC * 1000
+)
+
+type WorkerState struct {
+	w Worker
+	LastReport WorkerReport
+}
+
+func Report(ws *WorkerState, r WorkerReport) {
+	//fmt.Println(r)
+
+	lr := ws.LastReport
+
+	if (lr.Now > 0) {
+		time := float64(r.Now - lr.Now) / SEC
+		mops := r.Mops - lr.Mops
+
+		tput := float64(mops) / time
+
+		fmt.Printf("%d Time: %2.3f Mops: %d Tput: %4.2f\n", r.Id, time, mops, tput);
+	}
+
+	ws.LastReport = r
+}
+
+type WorkerList []WorkerState
+
+func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) (i int) {
+	i = 0
+	for j := range *ws {
+		go (*ws)[j].w.Process(report, done)
+		i++
+	}
+	return
+}
+
+func (ws *WorkerList) Stop() {
+	for i := range *ws {
+		(*ws)[i].w.Shutdown()
+	}
+}
+
+const (
+	WorkerProcess = iota
+	WorkerXen = iota
+)
+
+func NewWorkerList(workers []WorkerSet, workerType int) (ws WorkerList, err error) {
+	count := 0
+
+	// wsi: WorkerSet index
+	for wsi := range workers {
+		count += workers[wsi].Count
+	}
+
+	fmt.Println("Making ", count, " total workers")
+	ws = WorkerList(make([]WorkerState, count))
+
+	// wli: WorkerList index
+	wli := 0
+	for wsi := range workers {
+		for i := 0; i < workers[wsi].Count; i, wli = i+1, wli+1 {
+			switch workerType {
+			case WorkerProcess:
+				ws[wli].w = &ProcessWorker{}
+			case WorkerXen:
+				ws[wli].w = &XenWorker{}
+			default:
+				err = fmt.Errorf("Unknown type: %d", workerType)
+			}
+			ws[wli].w.SetId(wli)
+		
+			ws[wli].w.Init(workers[wsi].Params)
+		}
+	}
+	return
+}
+
+type BenchmarkRunData struct {
+	Raw []WorkerReport
+}
+
+type BenchmarkRun struct {
+	Completed bool
+	Label string
+	Workers []WorkerSet
+	RuntimeSeconds int
+	Results BenchmarkRunData 
+}
+
+func (run *BenchmarkRun) Run() (err error) {
+	Workers, err := NewWorkerList(run.Workers, WorkerProcess)
+	if err != nil {
+		fmt.Println("Error creating workers: %v", err)
+		return
+	}
+	
+	report := make(chan WorkerReport)
+	done := make(chan bool)
+	signals := make(chan os.Signal, 1)
+
+	signal.Notify(signals, os.Interrupt)
+	
+	i := Workers.Start(report, done)
+
+	// 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
+	timeout := time.After(time.Duration(run.RuntimeSeconds) * time.Second);
+	stopped := false
+	for i > 0 {
+		select {
+		case r := <-report:
+			run.Results.Raw = append(run.Results.Raw, r)
+			Report(&Workers[r.Id], r)
+		case <-done:
+			i--;
+			fmt.Println(i, "workers left");
+		case <-timeout:
+			if ! stopped {
+				Workers.Stop()
+				stopped = true
+				run.Completed = true
+			}
+		case <-signals:
+			if ! stopped {
+				fmt.Println("SIGINT receieved, shutting down workers")
+				Workers.Stop()
+				stopped = true
+				if run.RuntimeSeconds == 0 {
+					run.Completed = true
+				}
+				err = fmt.Errorf("Interrupted")
+			} else {
+				err = fmt.Errorf("Interrupted")
+				fmt.Println("SIGINT received after stop, exiting without cleaning up")
+				return
+			}
+		}
+	}
+	return
+}
+
+type BenchmarkPlan struct {
+	filename string
+	Runs []BenchmarkRun
+}
+
+func (plan *BenchmarkPlan) Run() (err error) {
+	for i := range plan.Runs {
+		if ! plan.Runs[i].Completed {
+			fmt.Printf("Running test [%d] %s\n", i, plan.Runs[i].Label)
+			err = plan.Runs[i].Run()
+			if err != nil {
+				return
+			}
+		}
+		fmt.Printf("Test [%d] %s completed\n", i, plan.Runs[i].Label)
+		err = plan.Save()
+		if err != nil {
+			fmt.Println("Error saving: ", err)
+			return
+		}
+	}
+	return
+}
+
+func LoadBenchmark(filename string) (plan BenchmarkPlan, err error) {
+	plan.filename = filename
+	
+	var b []byte
+	b, err = ioutil.ReadFile(filename)
+	if err != nil {
+		return
+	}
+	
+	err = json.Unmarshal(b, &plan)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+func (plan *BenchmarkPlan) Save() (err error) {
+	if plan.filename == "" {
+		err = fmt.Errorf("Invalid filename")
+		return
+	}
+	
+	var b []byte
+	b, err = json.Marshal(*plan)
+	if err != nil {
+		return
+	}
+
+	backupFilename := fmt.Sprintf(".%s.tmp", plan.filename)
+	err = os.Rename(plan.filename, backupFilename)
+	if err != nil {
+		if os.IsNotExist(err) {
+			backupFilename = ""
+		} else {
+			return
+		}
+	}
+
+	err = ioutil.WriteFile(plan.filename, b, 0666)
+	if err != nil {
+		if backupFilename != "" {
+			os.Rename(backupFilename, plan.filename)
+		}
+		return
+	}
+
+	if backupFilename != "" {
+		os.Remove(backupFilename)
+	}
+	return
+}
diff --git a/main.go b/main.go
index 7fbb60a..4d9701c 100644
--- a/main.go
+++ b/main.go
@@ -3,163 +3,54 @@ package main
 import (
 	"fmt"
 	"os"
-	"os/signal"
-	"time"
 )
 
-type WorkerReport struct {
-	Id int
-	Now int
-	Mops int
-	MaxDelta int
-}
-
-type WorkerParams struct {
-	Args []string
-}
-
-type WorkerSet struct {
-	Params WorkerParams
-	Count int
-}
-
-type BenchmarkParams struct {
-	Workers []WorkerSet
-	RuntimeSeconds int
-}
-
-type Worker interface {
-	SetId(int)
-	Init(WorkerParams) error
-	Shutdown()
-	Process(chan WorkerReport, chan bool)
-}
-
-const (
-	USEC = 1000
-	MSEC = USEC * 1000
-	SEC = MSEC * 1000
-)
-
-type WorkerState struct {
-	w Worker
-	LastReport WorkerReport
-}
-
-func Report(ws *WorkerState, r WorkerReport) {
-	//fmt.Println(r)
-
-	lr := ws.LastReport
-
-	if (lr.Now > 0) {
-		time := float64(r.Now - lr.Now) / SEC
-		mops := r.Mops - lr.Mops
-
-		tput := float64(mops) / time
-
-		fmt.Printf("%d Time: %2.3f Mops: %d Tput: %4.2f\n", r.Id, time, mops, tput);
-	}
-
-	ws.LastReport = r
-}
-
-type WorkerList []WorkerState
-
-func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) (i int) {
-	i = 0
-	for j := range *ws {
-		go (*ws)[j].w.Process(report, done)
-		i++
-	}
-	return
-}
-
-func (ws *WorkerList) Stop() {
-	for i := range *ws {
-		(*ws)[i].w.Shutdown()
-	}
-}
-
-const (
-	WorkerProcess = iota
-	WorkerXen = iota
-)
-
-func NewWorkerList(workers []WorkerSet, workerType int) (ws WorkerList, err error) {
-	count := 0
-
-	// wsi: WorkerSet index
-	for wsi := range workers {
-		count += workers[wsi].Count
-	}
-
-	fmt.Println("Making ", count, " total workers")
-	ws = WorkerList(make([]WorkerState, count))
-
-	// wli: WorkerList index
-	wli := 0
-	for wsi := range workers {
-		for i := 0; i < workers[wsi].Count; i, wli = i+1, wli+1 {
-			switch workerType {
-			case WorkerProcess:
-				ws[wli].w = &ProcessWorker{}
-			case WorkerXen:
-				ws[wli].w = &XenWorker{}
-			default:
-				err = fmt.Errorf("Unknown type: %d", workerType)
-			}
-			ws[wli].w.SetId(wli)
-		
-			ws[wli].w.Init(workers[wsi].Params)
-		}
-	}
-	return
-}
-
 func main() {
-	bp :=  BenchmarkParams{
-		Workers:[]WorkerSet{
-			{Params:WorkerParams{[]string{"burnwait", "20", "20000000"}},
-				Count:2},
-			{Params:WorkerParams{[]string{"burnwait", "10", "30000000"}},
-			 	Count:3},
-		},
-		RuntimeSeconds:5,
-	}
-
-	Workers, err := NewWorkerList(bp.Workers, WorkerProcess)
-	if err != nil {
-		fmt.Println("Error creating workers: %v", err)
-		return
-	}
-	
-	report := make(chan WorkerReport)
-	done := make(chan bool)
-	signals := make(chan os.Signal, 1)
-
-	signal.Notify(signals, os.Interrupt)
+	filename := "test.bench"
+
+	switch(os.Args[1]) {
+	case "plan":
+		plan :=  BenchmarkPlan{
+			filename:filename,
+			Runs:[]BenchmarkRun{
+				{Label:"baseline-a",
+					Workers:[]WorkerSet{
+						{Params:WorkerParams{[]string{"burnwait", "20", "20000000"}},
+							Count:1}},
+					RuntimeSeconds:5,},
+				{Label:"baseline-b",
+					Workers:[]WorkerSet{
+						{Params:WorkerParams{[]string{"burnwait", "10", "20000000"}},
+							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,},
+			}}
+		err := plan.Save()
+		if err != nil {
+			fmt.Println("Saving plan ", filename, " ", err)
+			os.Exit(1)
+		}
+		fmt.Println("Created plan in ", filename)
+	case "run":
+		plan, err := LoadBenchmark(filename)
+		if err != nil {
+			fmt.Println("Loading benchmark ", filename, " ", err)
+			os.Exit(1)
+		}
 	
-	i := Workers.Start(report, done)
-
-	timeout := time.After(time.Duration(bp.RuntimeSeconds) * time.Second);
-	killed := false
-	for i > 0 {
-		select {
-		case r := <-report:
-			Report(&Workers[r.Id], r)
-		case <-done:
-			i--;
-			fmt.Println(i, "workers left");
-		case <-signals:
-		case <-timeout:
-			if ! killed {
-				fmt.Println("SIGINT receieved, shutting down workers")
-				Workers.Stop()
-				killed = true
-			} else {
-				fmt.Println("Second SIGINT received, exiting without cleaning up")
-				os.Exit(1)
-			}
+		err = plan.Run()
+		if err != nil {
+			fmt.Println("Running benchmark run:", err)
+			os.Exit(1)
 		}
+	default:
+		fmt.Println("Unknown argument: ", os.Args[1])
 	}
 }
+
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 12/59] Basic 'report' functionality
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (9 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 11/59] Refactor to move towards benchmark "plans" and data analysis Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 13/59] Add GPL headers / COPYING file (v2 only) Ronald Rojas
                   ` (46 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

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@citrix.com>
---
 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@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 13/59] Add GPL headers / COPYING file (v2 only)
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (10 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 12/59] Basic 'report' functionality Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29 10:51   ` Wei Liu
  2016-12-29  1:14 ` [PATCH RFC 14/59] benchmark: Store data in terms of worker sets and worker ids Ronald Rojas
                   ` (45 subsequent siblings)
  57 siblings, 1 reply; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go     | 18 ++++++++++++++++++
 main.go          | 19 +++++++++++++++++++
 processworker.go | 18 ++++++++++++++++++
 xenworker.go     | 18 ++++++++++++++++++
 4 files changed, 73 insertions(+)

diff --git a/benchmark.go b/benchmark.go
index ec62c3d..2a78d26 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
 package main
 
 import (
diff --git a/main.go b/main.go
index 2696810..ebf990f 100644
--- a/main.go
+++ b/main.go
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
 package main
 
 import (
diff --git a/processworker.go b/processworker.go
index cca6c3b..6f70ce1 100644
--- a/processworker.go
+++ b/processworker.go
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
 package main
 
 import (
diff --git a/xenworker.go b/xenworker.go
index 1ed5cf0..7e85032 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
 package main
 
 import (
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 14/59] benchmark: Store data in terms of worker sets and worker ids
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (11 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 13/59] Add GPL headers / COPYING file (v2 only) Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 15/59] controller: Move "running" code to a separate file Ronald Rojas
                   ` (44 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

...rather than having a single global index, in preparation for
summarizing sets of workers as well as individual workers.

To do this:

- Define a WorkerId type which consists of the worker set + worker id
  within that set.  Pass this to the workers and use this in the
  report values.

- Use maps based on this WorkerId for currently running processes,
  accumulated data, and (for now) the results summary.

In a future patch, we'll break down the results summary by worker sets
as well.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go     | 120 +++++++++++++++++++++++++++----------------------------
 processworker.go |   4 +-
 xenworker.go     |   6 +--
 3 files changed, 63 insertions(+), 67 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index 2a78d26..4354a47 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -33,8 +33,17 @@ type WorkerSummary struct {
 	MinTput float64
 }
 
-type WorkerReport struct {
+type WorkerId struct {
+	Set int
 	Id int
+}
+
+func (wid WorkerId) String() (string) {
+	return fmt.Sprintf("%d:%d", wid.Set, wid.Id)
+}
+
+type WorkerReport struct {
+	Id WorkerId
 	Now int
 	Mops int
 	MaxDelta int
@@ -50,7 +59,7 @@ type WorkerSet struct {
 }
 
 type Worker interface {
-	SetId(int)
+	SetId(WorkerId)
 	Init(WorkerParams) error
 	Shutdown()
 	Process(chan WorkerReport, chan bool)
@@ -86,13 +95,13 @@ func Report(ws *WorkerState, r WorkerReport) {
 
 		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);
+		fmt.Printf("%v Time: %2.3f Mops: %d Tput: %4.2f\n", r.Id, time, mops, tput);
 	}
 
 	ws.LastReport = r
 }
 
-type WorkerList []WorkerState
+type WorkerList map[WorkerId]*WorkerState
 
 func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) (i int) {
 	i = 0
@@ -114,41 +123,44 @@ const (
 	WorkerXen = iota
 )
 
-func NewWorkerList(workers []WorkerSet, workerType int) (ws WorkerList, err error) {
-	count := 0
+func NewWorkerList(workers []WorkerSet, workerType int) (wl WorkerList, err error) {
+	wl = WorkerList(make(map[WorkerId]*WorkerState))
 
-	// wsi: WorkerSet index
 	for wsi := range workers {
-		count += workers[wsi].Count
-	}
+		for i := 0; i < workers[wsi].Count; i = i+1 {
+			Id := WorkerId{Set:wsi,Id:i}
 
-	fmt.Println("Making ", count, " total workers")
-	ws = WorkerList(make([]WorkerState, count))
+			ws := wl[Id]
 
-	// wli: WorkerList index
-	wli := 0
-	for wsi := range workers {
-		for i := 0; i < workers[wsi].Count; i, wli = i+1, wli+1 {
+			if ws != nil {
+				panic("Duplicate worker for id!")
+			}
+			
+			ws = &WorkerState{}
+			
 			switch workerType {
 			case WorkerProcess:
-				ws[wli].w = &ProcessWorker{}
+				ws.w = &ProcessWorker{}
 			case WorkerXen:
-				ws[wli].w = &XenWorker{}
+				ws.w = &XenWorker{}
 			default:
 				err = fmt.Errorf("Unknown type: %d", workerType)
+				return
 			}
-			ws[wli].w.SetId(wli)
+			
+			ws.w.SetId(Id)
 		
-			ws[wli].w.Init(workers[wsi].Params)
+			ws.w.Init(workers[wsi].Params)
+
+			wl[Id] = ws
 		}
 	}
 	return
 }
 
 type BenchmarkRunData struct {
-	WorkerCount int
 	Raw []WorkerReport       `json:",omitempty"`
-	Summary []WorkerSummary  `json:",omitempty"`
+	Summary map[WorkerId]*WorkerSummary  `json:",omitempty"`
 }
 
 type BenchmarkRun struct {
@@ -174,8 +186,6 @@ 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
@@ -185,7 +195,7 @@ func (run *BenchmarkRun) Run() (err error) {
 		select {
 		case r := <-report:
 			run.Results.Raw = append(run.Results.Raw, r)
-			Report(&Workers[r.Id], r)
+			Report(Workers[r.Id], r)
 		case <-done:
 			i--;
 			fmt.Println(i, "workers left");
@@ -215,22 +225,11 @@ func (run *BenchmarkRun) Run() (err error) {
 }
 
 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 {
+	if run.Results.Summary != nil {
 		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
 }
 
@@ -239,33 +238,31 @@ func (run *BenchmarkRun) Process() (err error) {
 	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)
+	run.Results.Summary = make(map[WorkerId]*WorkerSummary)
 
-	// FIXME: Filter out results which started before all have started
-	
-	data := make([]struct{
+	type Data struct{
 		startTime int
 		lastTime int
-		lastMops int}, wcount)
+		lastMops int
+	}
+	
+	data := make(map[WorkerId]*Data)
 
+	// FIXME: Filter out results which started before all have started
 	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]
+		d := data[e.Id]
+		if d == nil {
+			d = &Data{}
+			data[e.Id] = d
+		}
+		s := run.Results.Summary[e.Id]
+		if s == nil {
+			s = &WorkerSummary{}
+			run.Results.Summary[e.Id] = s
+		}
 
 		if d.startTime == 0 {
 			d.startTime = e.Now
@@ -283,8 +280,9 @@ func (run *BenchmarkRun) Process() (err error) {
 		d.lastMops = e.Mops
 	}
 
-	for i := range data {
-		run.Results.Summary[i].AvgTput = Throughput(data[i].startTime, 0, data[i].lastTime, data[i].lastMops)
+	for Id := range data {
+		run.Results.Summary[Id].AvgTput = Throughput(data[Id].startTime,
+			0, data[Id].lastTime, data[Id].lastMops)
 	}
 	
 	return
@@ -303,7 +301,6 @@ func (run *BenchmarkRun) TextReport() (err error) {
 
 	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]
@@ -317,10 +314,9 @@ func (run *BenchmarkRun) TextReport() (err error) {
 	}
 
 	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)
+	for id, s := range run.Results.Summary {
+		fmt.Printf("%8v %8.2f %8.2f %8.2f\n",
+			id, s.AvgTput, s.MinTput, s.MaxTput)
 	}
 
 	return
diff --git a/processworker.go b/processworker.go
index 6f70ce1..5e26d81 100644
--- a/processworker.go
+++ b/processworker.go
@@ -28,13 +28,13 @@ import (
 )
 
 type ProcessWorker struct {
-	id int
+	id WorkerId
 	c *exec.Cmd
 	stdout io.ReadCloser
 	jsonStarted bool
 }
 
-func (w *ProcessWorker) SetId(i int) {
+func (w *ProcessWorker) SetId(i WorkerId) {
 	w.id = i
 }
 
diff --git a/xenworker.go b/xenworker.go
index 7e85032..e14676c 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -28,7 +28,7 @@ import (
 )
 
 type XenWorker struct {
-	id int
+	id WorkerId
 	vmname string
 	domid int
 	consoleCmd *exec.Cmd
@@ -52,9 +52,9 @@ type RumpRunConfig struct {
 	Hostname string      `json:"hostname"`
 }
 
-func (w *XenWorker) SetId(i int) {
+func (w *XenWorker) SetId(i WorkerId) {
 	w.id = i
-	w.vmname = fmt.Sprintf("worker-%d", i)
+	w.vmname = fmt.Sprintf("worker-%v", i)
 	w.domid = -1 // INVALID DOMID
 }
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 15/59] controller: Move "running" code to a separate file
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (12 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 14/59] benchmark: Store data in terms of worker sets and worker ids Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 16/59] controller: Rename an element in BenchmarkRun to be more accurate Ronald Rojas
                   ` (43 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile     |   2 +-
 benchmark.go | 153 --------------------------------------------------
 run.go       | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 179 insertions(+), 154 deletions(-)
 create mode 100644 run.go

diff --git a/Makefile b/Makefile
index 7a33cfb..2e06f87 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ BINALL = $(BIN)
 .PHONY: all
 all: $(BIN)
 
-schedbench: main.go processworker.go xenworker.go benchmark.go
+schedbench: main.go processworker.go xenworker.go benchmark.go run.go
 	go build -o $@ $^
 
 .PHONY: clean
diff --git a/benchmark.go b/benchmark.go
index 4354a47..2e03fe5 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -21,8 +21,6 @@ package main
 import (
 	"fmt"
 	"os"
-	"os/signal"
-	"time"
 	"io/ioutil"
 	"encoding/json"
 )
@@ -71,11 +69,6 @@ const (
 	SEC = MSEC * 1000
 )
 
-type WorkerState struct {
-	w Worker
-	LastReport WorkerReport
-}
-
 func Throughput(lt int, lm int, t int, m int) (tput float64) {
 	time := float64(t - lt) / SEC
 	mops := m - lm
@@ -84,80 +77,6 @@ func Throughput(lt int, lm int, t int, m int) (tput float64) {
 	return
 }
 
-func Report(ws *WorkerState, r WorkerReport) {
-	//fmt.Println(r)
-
-	lr := ws.LastReport
-
-	if (lr.Now > 0) {
-		time := float64(r.Now - lr.Now) / SEC
-		mops := r.Mops - lr.Mops
-
-		tput := Throughput(lr.Now, lr.Mops, r.Now, r.Mops)
-		
-		fmt.Printf("%v Time: %2.3f Mops: %d Tput: %4.2f\n", r.Id, time, mops, tput);
-	}
-
-	ws.LastReport = r
-}
-
-type WorkerList map[WorkerId]*WorkerState
-
-func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) (i int) {
-	i = 0
-	for j := range *ws {
-		go (*ws)[j].w.Process(report, done)
-		i++
-	}
-	return
-}
-
-func (ws *WorkerList) Stop() {
-	for i := range *ws {
-		(*ws)[i].w.Shutdown()
-	}
-}
-
-const (
-	WorkerProcess = iota
-	WorkerXen = iota
-)
-
-func NewWorkerList(workers []WorkerSet, workerType int) (wl WorkerList, err error) {
-	wl = WorkerList(make(map[WorkerId]*WorkerState))
-
-	for wsi := range workers {
-		for i := 0; i < workers[wsi].Count; i = i+1 {
-			Id := WorkerId{Set:wsi,Id:i}
-
-			ws := wl[Id]
-
-			if ws != nil {
-				panic("Duplicate worker for id!")
-			}
-			
-			ws = &WorkerState{}
-			
-			switch workerType {
-			case WorkerProcess:
-				ws.w = &ProcessWorker{}
-			case WorkerXen:
-				ws.w = &XenWorker{}
-			default:
-				err = fmt.Errorf("Unknown type: %d", workerType)
-				return
-			}
-			
-			ws.w.SetId(Id)
-		
-			ws.w.Init(workers[wsi].Params)
-
-			wl[Id] = ws
-		}
-	}
-	return
-}
-
 type BenchmarkRunData struct {
 	Raw []WorkerReport       `json:",omitempty"`
 	Summary map[WorkerId]*WorkerSummary  `json:",omitempty"`
@@ -171,59 +90,6 @@ type BenchmarkRun struct {
 	Results BenchmarkRunData 
 }
 
-func (run *BenchmarkRun) Run() (err error) {
-	Workers, err := NewWorkerList(run.Workers, WorkerXen)
-	if err != nil {
-		fmt.Println("Error creating workers: %v", err)
-		return
-	}
-	
-	report := make(chan WorkerReport)
-	done := make(chan bool)
-	signals := make(chan os.Signal, 1)
-
-	signal.Notify(signals, os.Interrupt)
-	
-	i := Workers.Start(report, done)
-
-	// 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
-	timeout := time.After(time.Duration(run.RuntimeSeconds) * time.Second);
-	stopped := false
-	for i > 0 {
-		select {
-		case r := <-report:
-			run.Results.Raw = append(run.Results.Raw, r)
-			Report(Workers[r.Id], r)
-		case <-done:
-			i--;
-			fmt.Println(i, "workers left");
-		case <-timeout:
-			if ! stopped {
-				Workers.Stop()
-				stopped = true
-				run.Completed = true
-			}
-		case <-signals:
-			if ! stopped {
-				fmt.Println("SIGINT receieved, shutting down workers")
-				Workers.Stop()
-				stopped = true
-				if run.RuntimeSeconds == 0 {
-					run.Completed = true
-				}
-				err = fmt.Errorf("Interrupted")
-			} else {
-				err = fmt.Errorf("Interrupted")
-				fmt.Println("SIGINT received after stop, exiting without cleaning up")
-				return
-			}
-		}
-	}
-	return
-}
-
 func (run *BenchmarkRun) checkSummary() (done bool, err error) {
 	if run.Results.Summary != nil {
 		done = true
@@ -328,25 +194,6 @@ type BenchmarkPlan struct {
 	Runs []BenchmarkRun
 }
 
-func (plan *BenchmarkPlan) Run() (err error) {
-	for i := range plan.Runs {
-		if ! plan.Runs[i].Completed {
-			fmt.Printf("Running test [%d] %s\n", i, plan.Runs[i].Label)
-			err = plan.Runs[i].Run()
-			if err != nil {
-				return
-			}
-		}
-		fmt.Printf("Test [%d] %s completed\n", i, plan.Runs[i].Label)
-		err = plan.Save()
-		if err != nil {
-			fmt.Println("Error saving: ", err)
-			return
-		}
-	}
-	return
-}
-
 func LoadBenchmark(filename string) (plan BenchmarkPlan, err error) {
 	plan.filename = filename
 	
diff --git a/run.go b/run.go
new file mode 100644
index 0000000..7b5ef0a
--- /dev/null
+++ b/run.go
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/signal"
+	"time"
+)
+
+type WorkerState struct {
+	w Worker
+	LastReport WorkerReport
+}
+
+func Report(ws *WorkerState, r WorkerReport) {
+	//fmt.Println(r)
+
+	lr := ws.LastReport
+
+	if (lr.Now > 0) {
+		time := float64(r.Now - lr.Now) / SEC
+		mops := r.Mops - lr.Mops
+
+		tput := Throughput(lr.Now, lr.Mops, r.Now, r.Mops)
+		
+		fmt.Printf("%v Time: %2.3f Mops: %d Tput: %4.2f\n", r.Id, time, mops, tput);
+	}
+
+	ws.LastReport = r
+}
+
+type WorkerList map[WorkerId]*WorkerState
+
+func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) (i int) {
+	i = 0
+	for j := range *ws {
+		go (*ws)[j].w.Process(report, done)
+		i++
+	}
+	return
+}
+
+func (ws *WorkerList) Stop() {
+	for i := range *ws {
+		(*ws)[i].w.Shutdown()
+	}
+}
+
+const (
+	WorkerProcess = iota
+	WorkerXen = iota
+)
+
+func NewWorkerList(WorkerSets []WorkerSet, workerType int) (wl WorkerList, err error) {
+	wl = WorkerList(make(map[WorkerId]*WorkerState))
+
+	for wsi := range WorkerSets {
+		for i := 0; i < WorkerSets[wsi].Count; i = i+1 {
+			Id := WorkerId{Set:wsi,Id:i}
+
+			ws := wl[Id]
+
+			if ws != nil {
+				panic("Duplicate worker for id!")
+			}
+			
+			ws = &WorkerState{}
+			
+			switch workerType {
+			case WorkerProcess:
+				ws.w = &ProcessWorker{}
+			case WorkerXen:
+				ws.w = &XenWorker{}
+			default:
+				err = fmt.Errorf("Unknown type: %d", workerType)
+				return
+			}
+			
+			ws.w.SetId(Id)
+		
+			ws.w.Init(WorkerSets[wsi].Params)
+
+			wl[Id] = ws
+		}
+	}
+	return
+}
+
+func (run *BenchmarkRun) Run() (err error) {
+	Workers, err := NewWorkerList(run.Workers, WorkerXen)
+	if err != nil {
+		fmt.Println("Error creating workers: %v", err)
+		return
+	}
+	
+	report := make(chan WorkerReport)
+	done := make(chan bool)
+	signals := make(chan os.Signal, 1)
+
+	signal.Notify(signals, os.Interrupt)
+	
+	i := Workers.Start(report, done)
+
+	// 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
+	timeout := time.After(time.Duration(run.RuntimeSeconds) * time.Second);
+	stopped := false
+	for i > 0 {
+		select {
+		case r := <-report:
+			run.Results.Raw = append(run.Results.Raw, r)
+			Report(Workers[r.Id], r)
+		case <-done:
+			i--;
+			fmt.Println(i, "workers left");
+		case <-timeout:
+			if ! stopped {
+				Workers.Stop()
+				stopped = true
+				run.Completed = true
+			}
+		case <-signals:
+			if ! stopped {
+				fmt.Println("SIGINT receieved, shutting down workers")
+				Workers.Stop()
+				stopped = true
+				if run.RuntimeSeconds == 0 {
+					run.Completed = true
+				}
+				err = fmt.Errorf("Interrupted")
+			} else {
+				err = fmt.Errorf("Interrupted")
+				fmt.Println("SIGINT received after stop, exiting without cleaning up")
+				return
+			}
+		}
+	}
+	return
+}
+
+func (plan *BenchmarkPlan) Run() (err error) {
+	for i := range plan.Runs {
+		if ! plan.Runs[i].Completed {
+			fmt.Printf("Running test [%d] %s\n", i, plan.Runs[i].Label)
+			err = plan.Runs[i].Run()
+			if err != nil {
+				return
+			}
+		}
+		fmt.Printf("Test [%d] %s completed\n", i, plan.Runs[i].Label)
+		err = plan.Save()
+		if err != nil {
+			fmt.Println("Error saving: ", err)
+			return
+		}
+	}
+	return
+}
+
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 16/59] controller: Rename an element in BenchmarkRun to be more accurate
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (13 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 15/59] controller: Move "running" code to a separate file Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 17/59] controller: Collect and display statistics on WorkerSets Ronald Rojas
                   ` (42 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go | 6 +++---
 main.go      | 6 +++---
 run.go       | 2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index 2e03fe5..aaa4c98 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -84,7 +84,7 @@ type BenchmarkRunData struct {
 
 type BenchmarkRun struct {
 	Label string
-	Workers []WorkerSet
+	WorkerSets []WorkerSet
 	RuntimeSeconds int
 	Completed bool
 	Results BenchmarkRunData 
@@ -168,8 +168,8 @@ func (run *BenchmarkRun) TextReport() (err error) {
 	fmt.Printf("== RUN %s ==", run.Label)
 
 	wStart := 0
-	for i := range run.Workers {
-		ws := &run.Workers[i]
+	for i := range run.WorkerSets {
+		ws := &run.WorkerSets[i]
 		n := ws.Count
 		params := ""
 		for _, s := range ws.Params.Args {
diff --git a/main.go b/main.go
index ebf990f..f58068f 100644
--- a/main.go
+++ b/main.go
@@ -46,12 +46,12 @@ func main() {
 			filename:filename,
 			Runs:[]BenchmarkRun{
 				{Label:"baseline-a",
-					Workers:[]WorkerSet{
+					WorkerSets:[]WorkerSet{
 						{Params:WorkerParams{workerA},
 							Count:1}},
 					RuntimeSeconds:10,},
 				{Label:"baseline-b",
-					Workers:[]WorkerSet{
+					WorkerSets:[]WorkerSet{
 						{Params:WorkerParams{workerB},
 							Count:1}},
 					RuntimeSeconds:10,},
@@ -62,7 +62,7 @@ func main() {
 			label := fmt.Sprintf("%da+%db", i, i)
 			run := BenchmarkRun{
 				Label:label,
-				Workers:[]WorkerSet{
+				WorkerSets:[]WorkerSet{
 					{Params:WorkerParams{workerA},
 						Count:i},
 					{Params:WorkerParams{workerB},
diff --git a/run.go b/run.go
index 7b5ef0a..762b408 100644
--- a/run.go
+++ b/run.go
@@ -105,7 +105,7 @@ func NewWorkerList(WorkerSets []WorkerSet, workerType int) (wl WorkerList, err e
 }
 
 func (run *BenchmarkRun) Run() (err error) {
-	Workers, err := NewWorkerList(run.Workers, WorkerXen)
+	Workers, err := NewWorkerList(run.WorkerSets, WorkerXen)
 	if err != nil {
 		fmt.Println("Error creating workers: %v", err)
 		return
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 17/59] controller: Collect and display statistics on WorkerSets
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (14 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 16/59] controller: Rename an element in BenchmarkRun to be more accurate Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 18/59] controller: Add cpupool global config Ronald Rojas
                   ` (41 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Introduce WorkerSetSummary, to contain WorkerSummary's and collect
data for the set.

For now "if false"-out reporting of individual worker averages; we can
add this back in as an option later.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go | 156 +++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 121 insertions(+), 35 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index aaa4c98..4cc9d61 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -23,14 +23,9 @@ import (
 	"os"
 	"io/ioutil"
 	"encoding/json"
+	"math"
 )
 
-type WorkerSummary struct {
-	MaxTput float64
-	AvgTput float64
-	MinTput float64
-}
-
 type WorkerId struct {
 	Set int
 	Id int
@@ -77,9 +72,26 @@ func Throughput(lt int, lm int, t int, m int) (tput float64) {
 	return
 }
 
+type WorkerSummary struct {
+	MaxTput float64
+	AvgTput float64
+	MinTput float64
+}
+
+type WorkerSetSummary struct {
+	Workers    []WorkerSummary
+	TotalTput     float64
+	MaxTput       float64
+	AvgAvgTput    float64
+	AvgStdDevTput float64
+	AvgMaxTput    float64
+	AvgMinTput    float64
+	MinTput       float64
+}
+
 type BenchmarkRunData struct {
 	Raw []WorkerReport       `json:",omitempty"`
-	Summary map[WorkerId]*WorkerSummary  `json:",omitempty"`
+	Summary []WorkerSetSummary  `json:",omitempty"`
 }
 
 type BenchmarkRun struct {
@@ -90,6 +102,12 @@ type BenchmarkRun struct {
 	Results BenchmarkRunData 
 }
 
+type BenchmarkPlan struct {
+	filename string
+	WorkerType int
+	Runs []BenchmarkRun
+}
+
 func (run *BenchmarkRun) checkSummary() (done bool, err error) {
 	if run.Results.Summary != nil {
 		done = true
@@ -105,7 +123,7 @@ func (run *BenchmarkRun) Process() (err error) {
 		return
 	}
 
-	run.Results.Summary = make(map[WorkerId]*WorkerSummary)
+	run.Results.Summary = make([]WorkerSetSummary, len(run.WorkerSets))
 
 	type Data struct{
 		startTime int
@@ -118,18 +136,32 @@ func (run *BenchmarkRun) Process() (err error) {
 	// FIXME: Filter out results which started before all have started
 	for i := range run.Results.Raw {
 		e := run.Results.Raw[i]
+
+		if e.Id.Set > len(run.Results.Summary) {
+			return fmt.Errorf("Internal error: e.Id.Set %d > len(Results.Summary) %d\n",
+				e.Id.Set, len(run.Results.Summary))
+		}
 		
+		if run.Results.Summary[e.Id.Set].Workers == nil {
+			run.Results.Summary[e.Id.Set].Workers = make([]WorkerSummary,
+				run.WorkerSets[e.Id.Set].Count)
+		}
+
+		ws := &run.Results.Summary[e.Id.Set]
+		
+		if e.Id.Id > len(ws.Workers) {
+			return fmt.Errorf("Internal error: e.Id.Id %d > len(Results.Summary[].Workers) %d\n",
+				e.Id.Id, len(ws.Workers))
+		}
+
+		s := &ws.Workers[e.Id.Id]
+
 		d := data[e.Id]
 		if d == nil {
 			d = &Data{}
 			data[e.Id] = d
 		}
-		s := run.Results.Summary[e.Id]
-		if s == nil {
-			s = &WorkerSummary{}
-			run.Results.Summary[e.Id] = s
-		}
-
+			
 		if d.startTime == 0 {
 			d.startTime = e.Now
 		} else {
@@ -141,16 +173,63 @@ func (run *BenchmarkRun) Process() (err error) {
 			if tput < s.MinTput || s.MinTput == 0 {
 				s.MinTput = tput
 			}
+			if tput > ws.MaxTput {
+				ws.MaxTput = tput
+			}
+			if tput < ws.MinTput || ws.MinTput == 0 {
+				ws.MinTput = tput
+			}
 		}
 		d.lastTime = e.Now
 		d.lastMops = e.Mops
 	}
 
-	for Id := range data {
-		run.Results.Summary[Id].AvgTput = Throughput(data[Id].startTime,
-			0, data[Id].lastTime, data[Id].lastMops)
+	for Id, d := range data {
+		ws := &run.Results.Summary[Id.Set]
+		s := &ws.Workers[Id.Id]
+
+		s.AvgTput = Throughput(d.startTime, 0, d.lastTime, d.lastMops)
+		if s.AvgTput > ws.AvgMaxTput {
+			ws.AvgMaxTput = s.AvgTput
+		}
+		if s.AvgTput < ws.AvgMinTput || ws.AvgMinTput == 0 {
+			ws.AvgMinTput = s.AvgTput
+		}
+		
 	}
-	
+
+	// Calculate the average-of-averages for each set
+	for set := range run.Results.Summary {
+		ws := &run.Results.Summary[set]
+		
+		var total float64
+		var count int
+		for id := range ws.Workers {
+			total += ws.Workers[id].AvgTput
+			count++
+		}
+
+		// FIXME -- Is this legit?
+		ws.TotalTput = total
+		ws.AvgAvgTput = total / float64(count)
+	}
+
+	// Then calculate the standard deviation
+	for set := range run.Results.Summary {
+		ws := &run.Results.Summary[set]
+		
+		var total float64
+		var count int
+		
+		for id := range ws.Workers {
+			d := ws.Workers[id].AvgTput - ws.AvgAvgTput
+			total += d * d
+			count++
+		}
+		v := total / float64(count)
+		ws.AvgStdDevTput = math.Sqrt(v)
+	}
+
 	return
 }
 
@@ -165,33 +244,40 @@ func (run *BenchmarkRun) TextReport() (err error) {
 		return
 	}
 
-	fmt.Printf("== RUN %s ==", run.Label)
+	fmt.Printf("== RUN %s ==\n", run.Label)
 
-	wStart := 0
-	for i := range run.WorkerSets {
-		ws := &run.WorkerSets[i]
-		n := ws.Count
+	for set := range run.WorkerSets {
+		ws := &run.WorkerSets[set]
 		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("Set %d: %s\n", set, params)
 	}
 
-	fmt.Printf("\n%8s %8s %8s %8s\n", "id", "avg", "min", "max")
-	for id, s := range run.Results.Summary {
-		fmt.Printf("%8v %8.2f %8.2f %8.2f\n",
-			id, s.AvgTput, s.MinTput, s.MaxTput)
+	fmt.Printf("\n%8s %8s %8s %8s %8s %8s %8s %8s\n", "set", "total", "avgavg", "stdev", "avgmax", "avgmin", "totmax", "totmin")
+	for set := range run.WorkerSets {
+		ws := &run.Results.Summary[set]
+		fmt.Printf("%8d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n",
+			set, ws.TotalTput, ws.AvgAvgTput, ws.AvgStdDevTput, ws.AvgMaxTput, ws.AvgMinTput,
+			ws.MaxTput, ws.MinTput)
+		
 	}
 
-	return
-}
+	if false {
+		fmt.Printf("\n%8s %8s %8s %8s\n", "workerid", "avg", "min", "max")
+		for set := range run.Results.Summary {
+			for id := range run.Results.Summary[set].Workers {
+				s := run.Results.Summary[set].Workers[id]
+				fmt.Printf("%2d:%2d    %8.2f %8.2f %8.2f\n",
+					set, id, s.AvgTput, s.MinTput, s.MaxTput)
+			}
+		}
+	}
 
-type BenchmarkPlan struct {
-	filename string
-	WorkerType int
-	Runs []BenchmarkRun
+	fmt.Printf("\n\n")
+
+	return
 }
 
 func LoadBenchmark(filename string) (plan BenchmarkPlan, err error) {
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 18/59] controller: Add cpupool global config
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (15 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 17/59] controller: Collect and display statistics on WorkerSets Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 19/59] Add basic libxl framework, get domain cpu_time Ronald Rojas
                   ` (40 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Define WorkerConfig for worker configuration, add "Pool" as a pool in
which to place the worker (currently implemented in Xen only).

Add WorkerConfig options at the WorkerSet, BenchmarkRun, and
BenchmarkPlan levels; allow local levels to "override" global config
options.

The cpupool must already be defined.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go     | 19 ++++++++++++++++++-
 main.go          |  1 +
 processworker.go |  2 +-
 run.go           | 16 +++++++++++-----
 xenworker.go     |  6 +++++-
 5 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index 4cc9d61..7fa83d2 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -46,14 +46,27 @@ type WorkerParams struct {
 	Args []string
 }
 
+type WorkerConfig struct {
+	Pool string
+}
+
+// Propagate unset values from a higher level
+func (l *WorkerConfig) PropagateFrom(g WorkerConfig) {
+	if l.Pool == "" {
+		l.Pool = g.Pool
+	}
+}
+
+
 type WorkerSet struct {
 	Params WorkerParams
+	Config WorkerConfig
 	Count int
 }
 
 type Worker interface {
 	SetId(WorkerId)
-	Init(WorkerParams) error
+	Init(WorkerParams, WorkerConfig) error
 	Shutdown()
 	Process(chan WorkerReport, chan bool)
 }
@@ -97,6 +110,7 @@ type BenchmarkRunData struct {
 type BenchmarkRun struct {
 	Label string
 	WorkerSets []WorkerSet
+	WorkerConfig
 	RuntimeSeconds int
 	Completed bool
 	Results BenchmarkRunData 
@@ -105,6 +119,9 @@ type BenchmarkRun struct {
 type BenchmarkPlan struct {
 	filename string
 	WorkerType int
+	// Global options for workers that will be over-ridden by Run
+	// and WorkerSet config options
+	WorkerConfig
 	Runs []BenchmarkRun
 }
 
diff --git a/main.go b/main.go
index f58068f..a931567 100644
--- a/main.go
+++ b/main.go
@@ -43,6 +43,7 @@ func main() {
 
 		plan :=  BenchmarkPlan{
 			WorkerType:WorkerXen,
+			WorkerConfig:WorkerConfig{Pool:"schedbench"},
 			filename:filename,
 			Runs:[]BenchmarkRun{
 				{Label:"baseline-a",
diff --git a/processworker.go b/processworker.go
index 5e26d81..f517321 100644
--- a/processworker.go
+++ b/processworker.go
@@ -38,7 +38,7 @@ func (w *ProcessWorker) SetId(i WorkerId) {
 	w.id = i
 }
 
-func (w *ProcessWorker) Init(p WorkerParams) (err error) {
+func (w *ProcessWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
 	w.c = exec.Command("./worker-proc", p.Args...)
 
 	w.stdout, err = w.c.StdoutPipe()
diff --git a/run.go b/run.go
index 762b408..9f1edcf 100644
--- a/run.go
+++ b/run.go
@@ -96,7 +96,7 @@ func NewWorkerList(WorkerSets []WorkerSet, workerType int) (wl WorkerList, err e
 			
 			ws.w.SetId(Id)
 		
-			ws.w.Init(WorkerSets[wsi].Params)
+			ws.w.Init(WorkerSets[wsi].Params, WorkerSets[wsi].Config)
 
 			wl[Id] = ws
 		}
@@ -105,6 +105,10 @@ func NewWorkerList(WorkerSets []WorkerSet, workerType int) (wl WorkerList, err e
 }
 
 func (run *BenchmarkRun) Run() (err error) {
+	for wsi := range run.WorkerSets {
+		run.WorkerSets[wsi].Config.PropagateFrom(run.WorkerConfig)
+	}
+	
 	Workers, err := NewWorkerList(run.WorkerSets, WorkerXen)
 	if err != nil {
 		fmt.Println("Error creating workers: %v", err)
@@ -159,14 +163,16 @@ func (run *BenchmarkRun) Run() (err error) {
 
 func (plan *BenchmarkPlan) Run() (err error) {
 	for i := range plan.Runs {
-		if ! plan.Runs[i].Completed {
-			fmt.Printf("Running test [%d] %s\n", i, plan.Runs[i].Label)
-			err = plan.Runs[i].Run()
+		r := &plan.Runs[i];
+		if ! r.Completed {
+			r.WorkerConfig.PropagateFrom(plan.WorkerConfig)
+			fmt.Printf("Running test [%d] %s\n", i, r.Label)
+			err = r.Run()
 			if err != nil {
 				return
 			}
 		}
-		fmt.Printf("Test [%d] %s completed\n", i, plan.Runs[i].Label)
+		fmt.Printf("Test [%d] %s completed\n", i, r.Label)
 		err = plan.Save()
 		if err != nil {
 			fmt.Println("Error saving: ", err)
diff --git a/xenworker.go b/xenworker.go
index e14676c..4d42e5e 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -58,7 +58,7 @@ func (w *XenWorker) SetId(i WorkerId) {
 	w.domid = -1 // INVALID DOMID
 }
 
-func (w *XenWorker) Init(p WorkerParams) (err error) {
+func (w *XenWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
 	mock := false
 	
 	// Make xl config file
@@ -80,6 +80,10 @@ func (w *XenWorker) Init(p WorkerParams) (err error) {
 	fmt.Fprintf(cfg, "vcpus = 1\n")
 	fmt.Fprintf(cfg, "on_crash = 'destroy'\n")
 
+	if g.Pool != "" {
+		fmt.Fprintf(cfg, "pool = '%s'\n", g.Pool)
+	}
+
 	
 	// xl create -p [filename]
 	{
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 19/59] Add basic libxl framework, get domain cpu_time
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (16 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 18/59] controller: Add cpupool global config Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 20/59] xenworker: Use libxl_domain_unpause rather than forking xl Ronald Rojas
                   ` (39 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Introduce libxl "Context" class with open, close, and dominfo.

Create a global variable in xenworker.go to hold the context; open on
first worker creation, close on last worker destruction.

Add a new element to WorkerReport, Cputime, and print it out.

For now, include hard-coded link to local Xen libraries.  This should
be sorted out at some point.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile     |  13 +++++--
 benchmark.go |   2 ++
 libxl.go     | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 run.go       |   2 +-
 xenworker.go |  26 ++++++++++++++
 5 files changed, 156 insertions(+), 3 deletions(-)
 create mode 100644 libxl.go

diff --git a/Makefile b/Makefile
index 2e06f87..54f2ce8 100644
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,17 @@ BINALL = $(BIN)
 .PHONY: all
 all: $(BIN)
 
-schedbench: main.go processworker.go xenworker.go benchmark.go run.go
-	go build -o $@ $^
+
+
+CGO_CFLAGS = -I/build/hg/xen.git/dist/install/usr/local/include
+CGO_LIBS = -lyajl -lxenlight
+
+# FIXME
+XENLIB_PATH ?= /build/hg/xen.git/dist/install/usr/local/lib/
+CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH) $(CGO_LIBS)
+
+schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go
+	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -o $@ $^
 
 .PHONY: clean
 clean:
diff --git a/benchmark.go b/benchmark.go
index 7fa83d2..4b2d805 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -24,6 +24,7 @@ import (
 	"io/ioutil"
 	"encoding/json"
 	"math"
+	"time"
 )
 
 type WorkerId struct {
@@ -40,6 +41,7 @@ type WorkerReport struct {
 	Now int
 	Mops int
 	MaxDelta int
+	Cputime time.Duration
 }
 
 type WorkerParams struct {
diff --git a/libxl.go b/libxl.go
new file mode 100644
index 0000000..39e47ab
--- /dev/null
+++ b/libxl.go
@@ -0,0 +1,116 @@
+package main
+
+/*
+#include <libxl.h>
+*/
+import "C"
+
+import (
+	"unsafe"
+	"fmt"
+	"time"
+)
+
+type Context struct {
+	ctx *C.libxl_ctx
+}
+
+func NewContext() (Ctx *Context, err error) {
+	Ctx = &Context{}
+	
+	err = Ctx.Open()
+
+	return
+}
+
+func (Ctx *Context) IsOpen() bool {
+	return Ctx.ctx != nil
+}
+
+func (Ctx *Context) Open() (err error) {
+	ret := C.libxl_ctx_alloc(unsafe.Pointer(&Ctx.ctx), C.LIBXL_VERSION, 0, nil)
+
+	if ret != 0 {
+		err = fmt.Errorf("Allocating libxl context: %d", ret)
+	}
+	return
+}
+
+func (Ctx *Context) Close() (err error) {
+	ret := C.libxl_ctx_free(unsafe.Pointer(Ctx.ctx))
+	Ctx.ctx = nil
+
+	if ret != 0 {
+		err = fmt.Errorf("Freeing libxl context: %d", ret)
+	}
+	return
+}
+
+type Domid uint32
+
+type MemKB uint64
+
+// FIXME: Use the idl to generate types
+type Dominfo struct {
+	// FIXME: uuid
+	Domid             Domid
+	Running           bool
+	Blocked           bool
+	Paused            bool
+	Shutdown          bool
+	Dying             bool
+	Never_stop        bool
+	
+	Shutdown_reason   int32 // FIXME shutdown_reason enumeration
+	Outstanding_memkb MemKB
+	Current_memkb     MemKB
+	Shared_memkb      MemKB
+	Paged_memkb       MemKB
+	Max_memkb         MemKB
+	Cpu_time          time.Duration
+	Vcpu_max_id       uint32
+	Vcpu_online       uint32
+	Cpupool           uint32
+	Domain_type       int32 //FIXME libxl_domain_type enumeration
+
+}
+
+func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
+	if Ctx.ctx == nil {
+		err = fmt.Errorf("Context not opened")
+		return
+	}
+
+		
+	var cdi C.libxl_dominfo
+
+	ret := C.libxl_domain_info(Ctx.ctx, unsafe.Pointer(&cdi), C.uint32_t(Id))
+
+	// FIXME: IsDomainNotPresentError
+	if ret != 0 {
+		err = fmt.Errorf("libxl_domain_info failed: %d", ret)
+		return
+	}
+
+	// FIXME -- use introspection to make this more robust
+	di = &Dominfo{}
+	di.Domid = Domid(cdi.domid)
+	di.Running = bool(cdi.running)
+	di.Blocked = bool(cdi.blocked)
+	di.Paused = bool(cdi.paused)
+	di.Shutdown = bool(cdi.shutdown)
+	di.Dying = bool(cdi.dying)
+	di.Never_stop = bool(cdi.never_stop)
+	di.Shutdown_reason = int32(cdi.shutdown_reason)
+	di.Outstanding_memkb = MemKB(cdi.outstanding_memkb)
+	di.Current_memkb = MemKB(cdi.current_memkb)
+	di.Shared_memkb = MemKB(cdi.shared_memkb)
+	di.Paged_memkb = MemKB(cdi.paged_memkb)
+	di.Max_memkb = MemKB(cdi.max_memkb)
+	di.Cpu_time = time.Duration(cdi.cpu_time)
+	di.Vcpu_max_id = uint32(cdi.vcpu_max_id)
+	di.Vcpu_online = uint32(cdi.vcpu_online)
+	di.Cpupool = uint32(cdi.cpupool)
+	di.Domain_type = int32(cdi.domain_type)
+	return
+}
diff --git a/run.go b/run.go
index 9f1edcf..788c541 100644
--- a/run.go
+++ b/run.go
@@ -41,7 +41,7 @@ func Report(ws *WorkerState, r WorkerReport) {
 
 		tput := Throughput(lr.Now, lr.Mops, r.Now, r.Mops)
 		
-		fmt.Printf("%v Time: %2.3f Mops: %d Tput: %4.2f\n", r.Id, time, mops, tput);
+		fmt.Printf("%v Time: %2.3f Mops: %d Tput: %4.2f Cputime: %v\n", r.Id, time, mops, tput, r.Cputime);
 	}
 
 	ws.LastReport = r
diff --git a/xenworker.go b/xenworker.go
index 4d42e5e..31af35f 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -27,8 +27,16 @@ import (
 	"io"
 )
 
+type xenGlobal struct {
+	Ctx Context
+	count int
+}
+
+var xg xenGlobal
+
 type XenWorker struct {
 	id WorkerId
+	Ctx Context
 	vmname string
 	domid int
 	consoleCmd *exec.Cmd
@@ -59,6 +67,14 @@ func (w *XenWorker) SetId(i WorkerId) {
 }
 
 func (w *XenWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
+	if xg.count == 0 {
+		err = xg.Ctx.Open()
+		if err != nil {
+			return
+		}
+	}
+	xg.count++
+	
 	mock := false
 	
 	// Make xl config file
@@ -202,6 +218,11 @@ func (w *XenWorker) Shutdown() {
 	e.Stdout = os.Stdout
 	e.Stderr = os.Stderr
 
+	xg.count--
+	if xg.count == 0 {
+		defer xg.Ctx.Close()
+	}
+
 	err := e.Run()
 	if err != nil {
 		fmt.Printf("Error destroying domain: %v\n", err)
@@ -237,6 +258,11 @@ func (w *XenWorker) Process(report chan WorkerReport, done chan bool) {
 			var r WorkerReport
 			json.Unmarshal([]byte(s), &r)
 			r.Id = w.id
+			di, err := xg.Ctx.DomainInfo(Domid(w.domid))
+			// Ignore errors for now
+			if err == nil {
+				r.Cputime = di.Cpu_time
+			}
 			report <- r
 		} else {
 			if s == "START JSON" {
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 20/59] xenworker: Use libxl_domain_unpause rather than forking xl
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (17 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 19/59] Add basic libxl framework, get domain cpu_time Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 21/59] Report utilization statistics Ronald Rojas
                   ` (38 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Unpause is a time-sensitive operation; use libxl to unpause directly
rather than forking and execing xl for each VM.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go     | 14 ++++++++++++++
 xenworker.go | 12 ++----------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/libxl.go b/libxl.go
index 39e47ab..415de7f 100644
--- a/libxl.go
+++ b/libxl.go
@@ -114,3 +114,17 @@ func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
 	di.Domain_type = int32(cdi.domain_type)
 	return
 }
+
+func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
+	if Ctx.ctx == nil {
+		err = fmt.Errorf("Context not opened")
+		return
+	}
+
+	ret := C.libxl_domain_unpause(Ctx.ctx, C.uint32_t(Id))
+
+	if ret != 0 {
+		err = fmt.Errorf("libxl_domain_unpause failed: %d", ret)
+	}
+	return
+}
diff --git a/xenworker.go b/xenworker.go
index 31af35f..4077e77 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -232,16 +232,8 @@ func (w *XenWorker) Shutdown() {
 
 // FIXME: Return an error
 func (w *XenWorker) Process(report chan WorkerReport, done chan bool) {
-	mock := false
-	
-	// xl unpause [vmname]
-	args := []string{"xl", "unpause", w.vmname}
-	if mock {
-		args = append([]string{"echo"}, args...)
-	}
-	e := exec.Command(args[0], args[1:]...)
-
-	err := e.Run()
+	// // xl unpause [vmname]
+	err := xg.Ctx.DomainUnpause(Domid(w.domid))
 	if err != nil {
 		fmt.Printf("Error unpausing domain: %v\n", err)
 		return
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 21/59] Report utilization statistics
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (18 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 20/59] xenworker: Use libxl_domain_unpause rather than forking xl Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 22/59] Use tsc for time rather than rumpkernel clock_gettime() Ronald Rojas
                   ` (37 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Refactor the min/max into a separate type.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go | 119 +++++++++++++++++++++++++++++++++++++----------------------
 run.go       |   4 +-
 2 files changed, 78 insertions(+), 45 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index 4b2d805..b0b55c7 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -87,21 +87,45 @@ func Throughput(lt int, lm int, t int, m int) (tput float64) {
 	return
 }
 
+func Utilization(lt int, lct time.Duration, t int, ct time.Duration) (util float64) {
+	util = float64(ct - lct) / float64(t - lt)
+	return
+}
+
+type MinMax struct {
+	Min float64
+	Max float64
+}
+
+func (mm *MinMax) Update(x float64) {
+	if x > mm.Max {
+		mm.Max = x
+	}
+	if x < mm.Min || mm.Min == 0 {
+		mm.Min = x
+	}
+}
+
 type WorkerSummary struct {
-	MaxTput float64
+	MinMaxTput MinMax
+	MinMaxUtil MinMax
 	AvgTput float64
-	MinTput float64
+	AvgUtil float64
 }
 
 type WorkerSetSummary struct {
 	Workers    []WorkerSummary
 	TotalTput     float64
-	MaxTput       float64
 	AvgAvgTput    float64
+	MinMaxTput    MinMax
+	MinMaxAvgTput MinMax
 	AvgStdDevTput float64
-	AvgMaxTput    float64
-	AvgMinTput    float64
-	MinTput       float64
+
+	TotalUtil     float64
+	MinMaxUtil    MinMax
+	MinMaxAvgUtil MinMax
+	AvgAvgUtil    float64
+	AvgStdDevUtil float64
 }
 
 type BenchmarkRunData struct {
@@ -146,8 +170,10 @@ func (run *BenchmarkRun) Process() (err error) {
 
 	type Data struct{
 		startTime int
+		startCputime time.Duration
 		lastTime int
 		lastMops int
+		lastCputime time.Duration
 	}
 	
 	data := make(map[WorkerId]*Data)
@@ -183,24 +209,19 @@ func (run *BenchmarkRun) Process() (err error) {
 			
 		if d.startTime == 0 {
 			d.startTime = e.Now
+			d.startCputime = e.Cputime
 		} 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
-			}
-			if tput > ws.MaxTput {
-				ws.MaxTput = tput
-			}
-			if tput < ws.MinTput || ws.MinTput == 0 {
-				ws.MinTput = tput
-			}
+			util := Utilization(d.lastTime, d.lastCputime, e.Now, e.Cputime)
+
+			s.MinMaxTput.Update(tput)
+			s.MinMaxUtil.Update(util)
+			ws.MinMaxTput.Update(tput)
+			ws.MinMaxUtil.Update(util)
 		}
 		d.lastTime = e.Now
 		d.lastMops = e.Mops
+		d.lastCputime = e.Cputime
 	}
 
 	for Id, d := range data {
@@ -208,45 +229,51 @@ func (run *BenchmarkRun) Process() (err error) {
 		s := &ws.Workers[Id.Id]
 
 		s.AvgTput = Throughput(d.startTime, 0, d.lastTime, d.lastMops)
-		if s.AvgTput > ws.AvgMaxTput {
-			ws.AvgMaxTput = s.AvgTput
-		}
-		if s.AvgTput < ws.AvgMinTput || ws.AvgMinTput == 0 {
-			ws.AvgMinTput = s.AvgTput
-		}
-		
+		s.AvgUtil = Utilization(d.startTime, d.startCputime, d.lastTime, d.lastCputime)
+
+		ws.MinMaxAvgTput.Update(s.AvgTput)
+		ws.MinMaxAvgUtil.Update(s.AvgUtil)
 	}
 
 	// Calculate the average-of-averages for each set
 	for set := range run.Results.Summary {
 		ws := &run.Results.Summary[set]
 		
-		var total float64
+		var totalTput float64
+		var totalUtil float64
 		var count int
 		for id := range ws.Workers {
-			total += ws.Workers[id].AvgTput
+			totalTput += ws.Workers[id].AvgTput
+			totalUtil += ws.Workers[id].AvgUtil
 			count++
 		}
 
 		// FIXME -- Is this legit?
-		ws.TotalTput = total
-		ws.AvgAvgTput = total / float64(count)
+		ws.TotalTput = totalTput
+		ws.TotalUtil = totalUtil
+		ws.AvgAvgTput = totalTput / float64(count)
+		ws.AvgAvgUtil = totalUtil / float64(count)
 	}
 
 	// Then calculate the standard deviation
 	for set := range run.Results.Summary {
 		ws := &run.Results.Summary[set]
 		
-		var total float64
+		var totalAvgTput float64
+		var totalAvgUtil float64
 		var count int
 		
 		for id := range ws.Workers {
-			d := ws.Workers[id].AvgTput - ws.AvgAvgTput
-			total += d * d
+			d1 := ws.Workers[id].AvgTput - ws.AvgAvgTput
+			d2 := ws.Workers[id].AvgUtil - ws.AvgAvgUtil
+			totalAvgTput += d1 * d1
+			totalAvgUtil += d2 * d2
 			count++
 		}
-		v := total / float64(count)
-		ws.AvgStdDevTput = math.Sqrt(v)
+		v1 := totalAvgTput / float64(count)
+		v2 := totalAvgUtil / float64(count)
+		ws.AvgStdDevTput = math.Sqrt(v1)
+		ws.AvgStdDevUtil = math.Sqrt(v2)
 	}
 
 	return
@@ -274,22 +301,26 @@ func (run *BenchmarkRun) TextReport() (err error) {
 		fmt.Printf("Set %d: %s\n", set, params)
 	}
 
-	fmt.Printf("\n%8s %8s %8s %8s %8s %8s %8s %8s\n", "set", "total", "avgavg", "stdev", "avgmax", "avgmin", "totmax", "totmin")
+	fmt.Printf("\n%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s\n", "set", "ttotal", "tavgavg", "tstdev", "tavgmax", "tavgmin", "ttotmax", "ttotmin", "utotal", "uavgavg", "ustdev", "uavgmax", "uavgmin", "utotmax", "utotmin")
 	for set := range run.WorkerSets {
 		ws := &run.Results.Summary[set]
-		fmt.Printf("%8d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n",
-			set, ws.TotalTput, ws.AvgAvgTput, ws.AvgStdDevTput, ws.AvgMaxTput, ws.AvgMinTput,
-			ws.MaxTput, ws.MinTput)
-		
+		fmt.Printf("%8d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n",
+			set,
+			ws.TotalTput, ws.AvgAvgTput, ws.AvgStdDevTput, ws.MinMaxAvgTput.Max,
+			ws.MinMaxAvgTput.Min, ws.MinMaxTput.Max, ws.MinMaxTput.Min,
+			ws.TotalUtil, ws.AvgAvgUtil, ws.AvgStdDevUtil, ws.MinMaxAvgUtil.Max,
+			ws.MinMaxAvgUtil.Min, ws.MinMaxUtil.Max, ws.MinMaxUtil.Min)
 	}
 
-	if false {
-		fmt.Printf("\n%8s %8s %8s %8s\n", "workerid", "avg", "min", "max")
+	if true {
+		fmt.Printf("\n%8s %8s %8s %8s %8s %8s %8s\n", "workerid", "tavg", "tmin", "tmax", "uavg", "umin", "umax")
 		for set := range run.Results.Summary {
 			for id := range run.Results.Summary[set].Workers {
 				s := run.Results.Summary[set].Workers[id]
-				fmt.Printf("%2d:%2d    %8.2f %8.2f %8.2f\n",
-					set, id, s.AvgTput, s.MinTput, s.MaxTput)
+				fmt.Printf("%2d:%2d    %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n",
+					set, id,
+					s.AvgTput, s.MinMaxTput.Min, s.MinMaxTput.Max,
+					s.AvgUtil, s.MinMaxUtil.Min, s.MinMaxUtil.Max)
 			}
 		}
 	}
diff --git a/run.go b/run.go
index 788c541..2a93405 100644
--- a/run.go
+++ b/run.go
@@ -40,8 +40,10 @@ func Report(ws *WorkerState, r WorkerReport) {
 		mops := r.Mops - lr.Mops
 
 		tput := Throughput(lr.Now, lr.Mops, r.Now, r.Mops)
+
+		util := Utilization(lr.Now, lr.Cputime, r.Now, r.Cputime)
 		
-		fmt.Printf("%v Time: %2.3f Mops: %d Tput: %4.2f Cputime: %v\n", r.Id, time, mops, tput, r.Cputime);
+		fmt.Printf("%v Time: %2.3f Mops: %d Tput: %4.2f Cputime: %v Util: %4.2f\n", r.Id, time, mops, tput, r.Cputime, util);
 	}
 
 	ws.LastReport = r
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 22/59] Use tsc for time rather than rumpkernel clock_gettime()
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (19 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 21/59] Report utilization statistics Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 23/59] run: Don't collect results reported after command to stop guests is issued Ronald Rojas
                   ` (36 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

The rumpkernel clock_gettime() drifts drastically when the system is
overloaded.  Switch to using a TSC timesource instead:

* Use tsc_mode='native' in guest config
* Read the host tsc from /proc/cpuinfo when starting a run
* Pass it as an argument to the worker
* Implement now() with rdtsc

The results appear to continue to be accurate even with heavy
overcommitment.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go |  8 ++++++++
 run.go       | 45 +++++++++++++++++++++++++++++++++++++++++++++
 xenworker.go |  1 +
 3 files changed, 54 insertions(+)

diff --git a/benchmark.go b/benchmark.go
index b0b55c7..7ea9aaa 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -48,6 +48,14 @@ type WorkerParams struct {
 	Args []string
 }
 
+func (l *WorkerParams) SetkHZ(kHZ uint64) {
+	if l.Args[0] == "kHZ" {
+		l.Args[1] = fmt.Sprintf("%d", kHZ)
+	} else {
+		l.Args = append([]string{"kHZ", fmt.Sprintf("%d", kHZ)}, l.Args...)
+	}
+}
+
 type WorkerConfig struct {
 	Pool string
 }
diff --git a/run.go b/run.go
index 2a93405..4222001 100644
--- a/run.go
+++ b/run.go
@@ -23,6 +23,9 @@ import (
 	"os"
 	"os/signal"
 	"time"
+	"regexp"
+	"strconv"
+	"bufio"
 )
 
 type WorkerState struct {
@@ -106,9 +109,45 @@ func NewWorkerList(WorkerSets []WorkerSet, workerType int) (wl WorkerList, err e
 	return
 }
 
+var CpukHZ uint64
+
+func getCpuHz() (err error) {
+	if CpukHZ == 0 {
+		var cpuinfo *os.File
+		cpuinfo, err = os.Open("/proc/cpuinfo")
+		if err != nil {
+			return
+		}
+		re := regexp.MustCompile("^cpu MHz\\s*: ([0-9.]+)$")
+		scanner := bufio.NewScanner(cpuinfo)
+		for scanner.Scan() {
+			s := scanner.Text()
+			m := re.FindStringSubmatch(s)
+			if m != nil {
+				var MHZ float64
+				MHZ, err = strconv.ParseFloat(m[1], 64)
+				if err != nil {
+					return
+				}
+				CpukHZ = uint64(MHZ*1000)
+				break
+			}
+		}
+		if CpukHZ == 0 {
+			err = fmt.Errorf("Couldn't find cpu MHz")
+			return
+		} else {
+			fmt.Println("CpukHZ: ", CpukHZ)
+			
+		}
+	}
+	return
+}
+
 func (run *BenchmarkRun) Run() (err error) {
 	for wsi := range run.WorkerSets {
 		run.WorkerSets[wsi].Config.PropagateFrom(run.WorkerConfig)
+		run.WorkerSets[wsi].Params.SetkHZ(CpukHZ)
 	}
 	
 	Workers, err := NewWorkerList(run.WorkerSets, WorkerXen)
@@ -164,6 +203,12 @@ func (run *BenchmarkRun) Run() (err error) {
 }
 
 func (plan *BenchmarkPlan) Run() (err error) {
+
+	err = getCpuHz()
+	if err != nil {
+		return
+	}
+	
 	for i := range plan.Runs {
 		r := &plan.Runs[i];
 		if ! r.Completed {
diff --git a/xenworker.go b/xenworker.go
index 4077e77..e98c970 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -95,6 +95,7 @@ func (w *XenWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
 	fmt.Fprintf(cfg, "memory = 32\n")
 	fmt.Fprintf(cfg, "vcpus = 1\n")
 	fmt.Fprintf(cfg, "on_crash = 'destroy'\n")
+	fmt.Fprintf(cfg, "tsc_mode = 'native'\n")
 
 	if g.Pool != "" {
 		fmt.Fprintf(cfg, "pool = '%s'\n", g.Pool)
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 23/59] run: Don't collect results reported after command to stop guests is issued
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (20 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 22/59] Use tsc for time rather than rumpkernel clock_gettime() Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 24/59] report: Lots of changes Ronald Rojas
                   ` (35 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Particularly on heavily-loaded systems, this can lead to skew as some
guests have already stopped processing.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 run.go | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/run.go b/run.go
index 4222001..41408dd 100644
--- a/run.go
+++ b/run.go
@@ -172,9 +172,14 @@ func (run *BenchmarkRun) Run() (err error) {
 	for i > 0 {
 		select {
 		case r := <-report:
-			run.Results.Raw = append(run.Results.Raw, r)
-			Report(Workers[r.Id], r)
+			if ! stopped {
+				run.Results.Raw = append(run.Results.Raw, r)
+				Report(Workers[r.Id], r)
+			}
 		case <-done:
+			if ! stopped {
+				fmt.Println("WARNING: Worker left early")
+			}
 			i--;
 			fmt.Println(i, "workers left");
 		case <-timeout:
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 24/59] report: Lots of changes
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (21 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 23/59] run: Don't collect results reported after command to stop guests is issued Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 25/59] main: Change default workload to something a bit more extreme Ronald Rojas
                   ` (34 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Store raw worker reports in the worker summary for easy printing.

Add "level" argument to textreport to easly switch between different
levels of granularity.

Report total throughput, time, and cputime for workers.

When running, print plain time and aggregate cputime in addition to
deltas.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go | 34 +++++++++++++++++++++++++++-------
 main.go      |  2 +-
 run.go       |  7 +++++--
 3 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index 7ea9aaa..73c5441 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -115,8 +115,12 @@ func (mm *MinMax) Update(x float64) {
 }
 
 type WorkerSummary struct {
+	Raw []WorkerReport
 	MinMaxTput MinMax
 	MinMaxUtil MinMax
+	TotalTput int
+	TotalTime time.Duration
+	TotalCputime time.Duration
 	AvgTput float64
 	AvgUtil float64
 }
@@ -201,7 +205,7 @@ func (run *BenchmarkRun) Process() (err error) {
 		}
 
 		ws := &run.Results.Summary[e.Id.Set]
-		
+
 		if e.Id.Id > len(ws.Workers) {
 			return fmt.Errorf("Internal error: e.Id.Id %d > len(Results.Summary[].Workers) %d\n",
 				e.Id.Id, len(ws.Workers))
@@ -209,6 +213,8 @@ func (run *BenchmarkRun) Process() (err error) {
 
 		s := &ws.Workers[e.Id.Id]
 
+		s.Raw = append(s.Raw, e)
+		
 		d := data[e.Id]
 		if d == nil {
 			d = &Data{}
@@ -236,6 +242,10 @@ func (run *BenchmarkRun) Process() (err error) {
 		ws := &run.Results.Summary[Id.Set]
 		s := &ws.Workers[Id.Id]
 
+		s.TotalTput = d.lastMops
+		s.TotalTime = time.Duration(d.lastTime - d.startTime)
+		s.TotalCputime = d.lastCputime - d.startCputime
+		
 		s.AvgTput = Throughput(d.startTime, 0, d.lastTime, d.lastMops)
 		s.AvgUtil = Utilization(d.startTime, d.startCputime, d.lastTime, d.lastCputime)
 
@@ -287,7 +297,7 @@ func (run *BenchmarkRun) Process() (err error) {
 	return
 }
 
-func (run *BenchmarkRun) TextReport() (err error) {
+func (run *BenchmarkRun) TextReport(level int) (err error) {
 	var done bool
 	done, err = run.checkSummary()
 	if err != nil {
@@ -320,15 +330,25 @@ func (run *BenchmarkRun) TextReport() (err error) {
 			ws.MinMaxAvgUtil.Min, ws.MinMaxUtil.Max, ws.MinMaxUtil.Min)
 	}
 
-	if true {
-		fmt.Printf("\n%8s %8s %8s %8s %8s %8s %8s\n", "workerid", "tavg", "tmin", "tmax", "uavg", "umin", "umax")
+	if level >= 1 {
+ 		fmt.Printf("\n%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s\n", "workerid", "toput", "time", "cpu", "tavg", "tmin", "tmax", "uavg", "umin", "umax")
 		for set := range run.Results.Summary {
 			for id := range run.Results.Summary[set].Workers {
 				s := run.Results.Summary[set].Workers[id]
-				fmt.Printf("%2d:%2d    %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n",
+				fmt.Printf("%2d:%2d    %10d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n",
 					set, id,
+					s.TotalTput, s.TotalTime.Seconds(), s.TotalCputime.Seconds(),
 					s.AvgTput, s.MinMaxTput.Min, s.MinMaxTput.Max,
 					s.AvgUtil, s.MinMaxUtil.Min, s.MinMaxUtil.Max)
+
+				if level >= 2 {
+					for _, e := range s.Raw {
+						time := float64(e.Now) / SEC
+						fmt.Printf ("   [%8.3f] %8.3f %8d %12d\n", time,
+							e.Cputime.Seconds(), e.Mops, e.MaxDelta)
+					}
+				}
+
 			}
 		}
 	}
@@ -391,7 +411,7 @@ func (plan *BenchmarkPlan) Save() (err error) {
 	return
 }
 
-func (plan *BenchmarkPlan) TextReport() (err error) {
+func (plan *BenchmarkPlan) TextReport(level int) (err error) {
 	for i := range plan.Runs {
 		r := &plan.Runs[i]
 		if ! r.Completed {
@@ -404,7 +424,7 @@ func (plan *BenchmarkPlan) TextReport() (err error) {
 			return
 		}
 
-		err = r.TextReport()
+		err = r.TextReport(level)
 		if err != nil {
 			return
 		}
diff --git a/main.go b/main.go
index a931567..bb46dbc 100644
--- a/main.go
+++ b/main.go
@@ -98,7 +98,7 @@ func main() {
 			os.Exit(1)
 		}
 	
-		err = plan.TextReport()
+		err = plan.TextReport(2)
 		if err != nil {
 			fmt.Println("Running benchmark run:", err)
 			os.Exit(1)
diff --git a/run.go b/run.go
index 41408dd..259f427 100644
--- a/run.go
+++ b/run.go
@@ -39,14 +39,17 @@ func Report(ws *WorkerState, r WorkerReport) {
 	lr := ws.LastReport
 
 	if (lr.Now > 0) {
-		time := float64(r.Now - lr.Now) / SEC
+		time := float64(r.Now) / SEC
+		dtime := float64(r.Now - lr.Now) / SEC
 		mops := r.Mops - lr.Mops
 
 		tput := Throughput(lr.Now, lr.Mops, r.Now, r.Mops)
 
 		util := Utilization(lr.Now, lr.Cputime, r.Now, r.Cputime)
 		
-		fmt.Printf("%v Time: %2.3f Mops: %d Tput: %4.2f Cputime: %v Util: %4.2f\n", r.Id, time, mops, tput, r.Cputime, util);
+		fmt.Printf("%v %8.3f [%8.3f] cpu %8.3f [%8.3f] Mops: %8d [%8d] Tput: %4.2f Util: %4.2f\n",
+			r.Id, time, dtime, r.Cputime.Seconds(), r.Cputime.Seconds() - lr.Cputime.Seconds(),
+			r.Mops, mops, tput, util);
 	}
 
 	ws.LastReport = r
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 25/59] main: Change default workload to something a bit more extreme
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (22 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 24/59] report: Lots of changes Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 26/59] Use kops rather than mops Ronald Rojas
                   ` (33 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/main.go b/main.go
index bb46dbc..61d3949 100644
--- a/main.go
+++ b/main.go
@@ -29,15 +29,15 @@ func main() {
 
 	switch(os.Args[1]) {
 	case "plan":
-		workerA := []string{"burnwait", "20", "20000000"}
+		workerA := []string{"burnwait", "1", "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",
+		workerB := []string{"burnwait", "1", "30000000",
+			"burnwait", "2", "30000000",
+			"burnwait", "1", "30000000",
+			"burnwait", "1", "30000000",
+			"burnwait", "1", "30000000",
+			"burnwait", "1", "30000000",
+			"burnwait", "3", "30000000",
 		}
 
 
@@ -58,7 +58,6 @@ func main() {
 					RuntimeSeconds:10,},
 			}}
 
-
 		for i := 1; i <= 16 ; i *= 2 {
 			label := fmt.Sprintf("%da+%db", i, i)
 			run := BenchmarkRun{
@@ -98,7 +97,7 @@ func main() {
 			os.Exit(1)
 		}
 	
-		err = plan.TextReport(2)
+		err = plan.TextReport(0)
 		if err != nil {
 			fmt.Println("Running benchmark run:", err)
 			os.Exit(1)
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 26/59] Use kops rather than mops
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (23 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 25/59] main: Change default workload to something a bit more extreme Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 27/59] report: Allow report verbosity to be specified Ronald Rojas
                   ` (32 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

1 million operations on my test box takes about 3ms -- meaning the
minimum granularity for how long to burn cpu is far longer than
typical.  Make this kops instead, giving us a minimum granularity of 3us.

Update most of the default workers to have similar patterns but on a
1/100 (nb not 1/1000) scale; with the exception of worker A (1/1000
scale) and the first worker in worker B (1/10 scale).

Also, actually fix the name of the scheduler in the README.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go | 18 +++++++++---------
 main.go      | 16 ++++++++--------
 run.go       |  8 ++++----
 3 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index 73c5441..ffecb82 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -39,7 +39,7 @@ func (wid WorkerId) String() (string) {
 type WorkerReport struct {
 	Id WorkerId
 	Now int
-	Mops int
+	Kops int
 	MaxDelta int
 	Cputime time.Duration
 }
@@ -89,9 +89,9 @@ const (
 
 func Throughput(lt int, lm int, t int, m int) (tput float64) {
 	time := float64(t - lt) / SEC
-	mops := m - lm
+	kops := m - lm
 	
-	tput = float64(mops) / time
+	tput = float64(kops) / time
 	return
 }
 
@@ -184,7 +184,7 @@ func (run *BenchmarkRun) Process() (err error) {
 		startTime int
 		startCputime time.Duration
 		lastTime int
-		lastMops int
+		lastKops int
 		lastCputime time.Duration
 	}
 	
@@ -225,7 +225,7 @@ func (run *BenchmarkRun) Process() (err error) {
 			d.startTime = e.Now
 			d.startCputime = e.Cputime
 		} else {
-			tput := Throughput(d.lastTime, d.lastMops, e.Now, e.Mops)
+			tput := Throughput(d.lastTime, d.lastKops, e.Now, e.Kops)
 			util := Utilization(d.lastTime, d.lastCputime, e.Now, e.Cputime)
 
 			s.MinMaxTput.Update(tput)
@@ -234,7 +234,7 @@ func (run *BenchmarkRun) Process() (err error) {
 			ws.MinMaxUtil.Update(util)
 		}
 		d.lastTime = e.Now
-		d.lastMops = e.Mops
+		d.lastKops = e.Kops
 		d.lastCputime = e.Cputime
 	}
 
@@ -242,11 +242,11 @@ func (run *BenchmarkRun) Process() (err error) {
 		ws := &run.Results.Summary[Id.Set]
 		s := &ws.Workers[Id.Id]
 
-		s.TotalTput = d.lastMops
+		s.TotalTput = d.lastKops
 		s.TotalTime = time.Duration(d.lastTime - d.startTime)
 		s.TotalCputime = d.lastCputime - d.startCputime
 		
-		s.AvgTput = Throughput(d.startTime, 0, d.lastTime, d.lastMops)
+		s.AvgTput = Throughput(d.startTime, 0, d.lastTime, d.lastKops)
 		s.AvgUtil = Utilization(d.startTime, d.startCputime, d.lastTime, d.lastCputime)
 
 		ws.MinMaxAvgTput.Update(s.AvgTput)
@@ -345,7 +345,7 @@ func (run *BenchmarkRun) TextReport(level int) (err error) {
 					for _, e := range s.Raw {
 						time := float64(e.Now) / SEC
 						fmt.Printf ("   [%8.3f] %8.3f %8d %12d\n", time,
-							e.Cputime.Seconds(), e.Mops, e.MaxDelta)
+							e.Cputime.Seconds(), e.Kops, e.MaxDelta)
 					}
 				}
 
diff --git a/main.go b/main.go
index 61d3949..6eaa39e 100644
--- a/main.go
+++ b/main.go
@@ -29,15 +29,15 @@ func main() {
 
 	switch(os.Args[1]) {
 	case "plan":
-		workerA := []string{"burnwait", "1", "20000000"}
+		workerA := []string{"burnwait", "7", "20000"}
 		//workerB := []string{"burnwait", "10", "20000000"}
-		workerB := []string{"burnwait", "1", "30000000",
-			"burnwait", "2", "30000000",
-			"burnwait", "1", "30000000",
-			"burnwait", "1", "30000000",
-			"burnwait", "1", "30000000",
-			"burnwait", "1", "30000000",
-			"burnwait", "3", "30000000",
+		workerB := []string{"burnwait", "100", "3000000",
+			"burnwait", "20", "300000",
+			"burnwait", "10", "300000",
+			"burnwait", "10", "300000",
+			"burnwait", "10", "300000",
+			"burnwait", "10", "300000",
+			"burnwait", "30", "300000",
 		}
 
 
diff --git a/run.go b/run.go
index 259f427..ed1957b 100644
--- a/run.go
+++ b/run.go
@@ -41,15 +41,15 @@ func Report(ws *WorkerState, r WorkerReport) {
 	if (lr.Now > 0) {
 		time := float64(r.Now) / SEC
 		dtime := float64(r.Now - lr.Now) / SEC
-		mops := r.Mops - lr.Mops
+		kops := r.Kops - lr.Kops
 
-		tput := Throughput(lr.Now, lr.Mops, r.Now, r.Mops)
+		tput := Throughput(lr.Now, lr.Kops, r.Now, r.Kops)
 
 		util := Utilization(lr.Now, lr.Cputime, r.Now, r.Cputime)
 		
-		fmt.Printf("%v %8.3f [%8.3f] cpu %8.3f [%8.3f] Mops: %8d [%8d] Tput: %4.2f Util: %4.2f\n",
+		fmt.Printf("%v %8.3f [%8.3f] cpu %8.3f [%8.3f] Kops: %8d [%8d] Tput: %4.2f Util: %4.2f\n",
 			r.Id, time, dtime, r.Cputime.Seconds(), r.Cputime.Seconds() - lr.Cputime.Seconds(),
-			r.Mops, mops, tput, util);
+			r.Kops, kops, tput, util);
 	}
 
 	ws.LastReport = r
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 27/59] report: Allow report verbosity to be specified
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (24 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 26/59] Use kops rather than mops Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 28/59] controller: Handle worker early death Ronald Rojas
                   ` (31 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Take a third argument to control the level of verbosity.

Also add helpful deltas when reporting the raw results.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go | 17 +++++++++++++++--
 main.go      | 11 ++++++++---
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index ffecb82..5e35997 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -342,10 +342,23 @@ func (run *BenchmarkRun) TextReport(level int) (err error) {
 					s.AvgUtil, s.MinMaxUtil.Min, s.MinMaxUtil.Max)
 
 				if level >= 2 {
+					var le WorkerReport
 					for _, e := range s.Raw {
+						var dtime float64
+						var dCputime time.Duration
+						var dKops int
 						time := float64(e.Now) / SEC
-						fmt.Printf ("   [%8.3f] %8.3f %8d %12d\n", time,
-							e.Cputime.Seconds(), e.Kops, e.MaxDelta)
+						if e.Now > le.Now {
+							dtime = float64(e.Now - le.Now) / SEC
+							dCputime = e.Cputime - le.Cputime
+							dKops = e.Kops - le.Kops
+
+						}
+						fmt.Printf ("   [%8.3f] (%8.3f) %8.3f (%8.3f) %8d (%8d) %12d\n",
+							time, dtime,
+							e.Cputime.Seconds(), dCputime.Seconds(),
+							e.Kops, dKops, e.MaxDelta)
+						le = e
 					}
 				}
 
diff --git a/main.go b/main.go
index 6eaa39e..13230a7 100644
--- a/main.go
+++ b/main.go
@@ -22,6 +22,7 @@ package main
 import (
 	"fmt"
 	"os"
+	"strconv"
 )
 
 func main() {
@@ -29,9 +30,9 @@ func main() {
 
 	switch(os.Args[1]) {
 	case "plan":
-		workerA := []string{"burnwait", "7", "20000"}
+		workerA := []string{"burnwait", "70", "200000"}
 		//workerB := []string{"burnwait", "10", "20000000"}
-		workerB := []string{"burnwait", "100", "3000000",
+		workerB := []string{"burnwait", "10", "300000",
 			"burnwait", "20", "300000",
 			"burnwait", "10", "300000",
 			"burnwait", "10", "300000",
@@ -91,13 +92,17 @@ func main() {
 		}
 		
 	case "report":
+		verbosity := 0
+		if len(os.Args) > 2 {
+			verbosity, _ = strconv.Atoi(os.Args[2])
+		}
 		plan, err := LoadBenchmark(filename)
 		if err != nil {
 			fmt.Println("Loading benchmark ", filename, " ", err)
 			os.Exit(1)
 		}
 	
-		err = plan.TextReport(0)
+		err = plan.TextReport(verbosity)
 		if err != nil {
 			fmt.Println("Running benchmark run:", err)
 			os.Exit(1)
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 28/59] controller: Handle worker early death
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (25 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 27/59] report: Allow report verbosity to be specified Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 29/59] report: Add basic html report Ronald Rojas
                   ` (30 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Log raw worker output.  In the event of an unexpected worker death,
dump the output and stop further processing.

Also fix an assert that caused workers to die if the timer was too
exact.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go     |  7 -------
 processworker.go | 18 ++++++++++++++++--
 run.go           | 24 ++++++++++++++++++------
 xenworker.go     | 21 +++++++++++++++++++--
 4 files changed, 53 insertions(+), 17 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index 5e35997..de1f650 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -74,13 +74,6 @@ type WorkerSet struct {
 	Count int
 }
 
-type Worker interface {
-	SetId(WorkerId)
-	Init(WorkerParams, WorkerConfig) error
-	Shutdown()
-	Process(chan WorkerReport, chan bool)
-}
-
 const (
 	USEC = 1000
 	MSEC = USEC * 1000
diff --git a/processworker.go b/processworker.go
index f517321..999e76a 100644
--- a/processworker.go
+++ b/processworker.go
@@ -32,6 +32,7 @@ type ProcessWorker struct {
 	c *exec.Cmd
 	stdout io.ReadCloser
 	jsonStarted bool
+	Log []string
 }
 
 func (w *ProcessWorker) SetId(i WorkerId) {
@@ -54,7 +55,19 @@ func (w *ProcessWorker) Shutdown() {
 	w.c.Process.Kill()
 }
 
-func (w *ProcessWorker) Process(report chan WorkerReport, done chan bool) {
+func (w *ProcessWorker) DumpLog(f io.Writer) (err error) {
+	b := bufio.NewWriter(f)
+	defer b.Flush()
+	for _, line := range w.Log {
+		_, err = fmt.Println(b, line)
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+func (w *ProcessWorker) Process(report chan WorkerReport, done chan WorkerId) {
 	w.c.Start()
 
 	scanner := bufio.NewScanner(w.stdout)
@@ -63,6 +76,7 @@ func (w *ProcessWorker) Process(report chan WorkerReport, done chan bool) {
 		s := scanner.Text()
 		
 		//fmt.Println("Got these bytes: ", s);
+		w.Log = append(w.Log, s)
 
 		if w.jsonStarted {
 			var r WorkerReport
@@ -77,7 +91,7 @@ func (w *ProcessWorker) Process(report chan WorkerReport, done chan bool) {
 		}
 	}
 
-	done <- true
+	done <- w.id
 
 	w.c.Wait()
 }
diff --git a/run.go b/run.go
index ed1957b..1b39730 100644
--- a/run.go
+++ b/run.go
@@ -26,6 +26,7 @@ import (
 	"regexp"
 	"strconv"
 	"bufio"
+	"io"
 )
 
 type WorkerState struct {
@@ -33,6 +34,14 @@ type WorkerState struct {
 	LastReport WorkerReport
 }
 
+type Worker interface {
+	SetId(WorkerId)
+	Init(WorkerParams, WorkerConfig) error
+	Shutdown()
+	Process(chan WorkerReport, chan WorkerId)
+	DumpLog(io.Writer) error
+}
+
 func Report(ws *WorkerState, r WorkerReport) {
 	//fmt.Println(r)
 
@@ -57,7 +66,7 @@ func Report(ws *WorkerState, r WorkerReport) {
 
 type WorkerList map[WorkerId]*WorkerState
 
-func (ws *WorkerList) Start(report chan WorkerReport, done chan bool) (i int) {
+func (ws *WorkerList) Start(report chan WorkerReport, done chan WorkerId) (i int) {
 	i = 0
 	for j := range *ws {
 		go (*ws)[j].w.Process(report, done)
@@ -160,7 +169,7 @@ func (run *BenchmarkRun) Run() (err error) {
 	}
 	
 	report := make(chan WorkerReport)
-	done := make(chan bool)
+	done := make(chan WorkerId)
 	signals := make(chan os.Signal, 1)
 
 	signal.Notify(signals, os.Interrupt)
@@ -179,12 +188,16 @@ func (run *BenchmarkRun) Run() (err error) {
 				run.Results.Raw = append(run.Results.Raw, r)
 				Report(Workers[r.Id], r)
 			}
-		case <-done:
+		case did := <-done:
 			if ! stopped {
-				fmt.Println("WARNING: Worker left early")
+				fmt.Println("WARNING: Worker", did, "left early, shutting down workers")
+				Workers.Stop()
+				stopped = true
+				err = fmt.Errorf("Worker %v exited early", did)
+				Workers[did].w.DumpLog(os.Stdout)
 			}
 			i--;
-			fmt.Println(i, "workers left");
+			fmt.Printf("Worker %v exited; %d workers left\n", did, i);
 		case <-timeout:
 			if ! stopped {
 				Workers.Stop()
@@ -201,7 +214,6 @@ func (run *BenchmarkRun) Run() (err error) {
 				}
 				err = fmt.Errorf("Interrupted")
 			} else {
-				err = fmt.Errorf("Interrupted")
 				fmt.Println("SIGINT received after stop, exiting without cleaning up")
 				return
 			}
diff --git a/xenworker.go b/xenworker.go
index e98c970..45e0876 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -42,6 +42,7 @@ type XenWorker struct {
 	consoleCmd *exec.Cmd
 	console io.ReadCloser
 	jsonStarted bool
+	Log []string
 }
 
 // We have to capitalize the element names so that the json class can
@@ -231,8 +232,22 @@ func (w *XenWorker) Shutdown() {
 	}
 }
 
+func (w *XenWorker) DumpLog(f io.Writer) (err error) {
+	b := bufio.NewWriter(f)
+	defer b.Flush()
+	for _, line := range w.Log {
+		_, err = fmt.Fprintln(b, line)
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+
+
 // FIXME: Return an error
-func (w *XenWorker) Process(report chan WorkerReport, done chan bool) {
+func (w *XenWorker) Process(report chan WorkerReport, done chan WorkerId) {
 	// // xl unpause [vmname]
 	err := xg.Ctx.DomainUnpause(Domid(w.domid))
 	if err != nil {
@@ -244,6 +259,8 @@ func (w *XenWorker) Process(report chan WorkerReport, done chan bool) {
 
 	for scanner.Scan() {
 		s := scanner.Text()
+
+		w.Log = append(w.Log, s)
 		
 		//fmt.Println("Got these bytes: ", s);
 
@@ -265,7 +282,7 @@ func (w *XenWorker) Process(report chan WorkerReport, done chan bool) {
 		}
 	}
 
-	done <- true
+	done <- w.id
 
 	w.consoleCmd.Wait()
 }
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 29/59] report: Add basic html report
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (26 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 28/59] controller: Handle worker early death Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 30/59] htmlreport: Include utilization scatterplots Ronald Rojas
                   ` (29 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Use Google's chartapi to create a (mostly) self-contained html file.
Start with just scatterplots of the raw data for proof-of-concept.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile      |   2 +-
 benchmark.go  |   1 +
 htmlreport.go | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 main.go       |  12 +++
 4 files changed, 247 insertions(+), 1 deletion(-)
 create mode 100644 htmlreport.go

diff --git a/Makefile b/Makefile
index 54f2ce8..c1b9ee4 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ CGO_LIBS = -lyajl -lxenlight
 XENLIB_PATH ?= /build/hg/xen.git/dist/install/usr/local/lib/
 CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH) $(CGO_LIBS)
 
-schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go
+schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go htmlreport.go
 	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -o $@ $^
 
 .PHONY: clean
diff --git a/benchmark.go b/benchmark.go
index de1f650..8be00a0 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -438,3 +438,4 @@ func (plan *BenchmarkPlan) TextReport(level int) (err error) {
 
 	return
 }
+
diff --git a/htmlreport.go b/htmlreport.go
new file mode 100644
index 0000000..6f61998
--- /dev/null
+++ b/htmlreport.go
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+package main
+
+import (
+	"fmt"
+	"os"
+	"io"
+	"encoding/json"
+)
+
+type OptionAxis struct {
+	Title string `json:"title"`
+	MinValue float64 `json:"minValue"`
+	MaxValue float64 `json:"maxValue"`
+}
+
+type Options struct {
+	Title string     `json:"title"`
+	HAxis OptionAxis `json:"hAxis"`
+	VAxis OptionAxis `json:"vAxis"`
+	Legend string    `json:"legend"`
+}
+
+type Point struct {
+	x float64
+	y float64
+}
+
+type RunRaw struct {
+	Label string
+	Points [][]Point
+}
+
+func (options *Options) OutputJavascript(w io.Writer, id int) (err error) {
+	var optionsJson []byte
+	optionsJson, err = json.Marshal(options)
+	if err != nil {
+		return
+	}
+
+	fmt.Fprintf(w, "        var sp%dopt = ", id)
+	fmt.Fprint(w, string(optionsJson))
+	fmt.Fprintln(w, ";")
+
+	return
+}
+
+func (p *Point) OutputJson(w io.Writer, id int, max int) (err error) {
+	fmt.Fprintf(w, "            [%f", p.x)
+	for i := 0; i < max; i++ {
+		if i == id {
+			fmt.Fprintf(w, ", %f", p.y)
+		} else {
+			fmt.Fprintf(w, ", null")
+		}
+	}
+	fmt.Fprint(w, "],\n")
+	return
+}
+
+func (d *RunRaw) OutputHTML(w io.Writer, run int) (err error) {
+	fmt.Fprintf(w, "    <div class='scatterplot' id='scatterplot%d'></div>\n", run)
+	return
+}
+
+func (d *RunRaw) OutputJavascript(w io.Writer, run int) (err error) {
+	var options Options
+
+	options.Title = fmt.Sprintf("Run %s (%d) Individual Throughput", d.Label, run)
+	options.HAxis.Title = "Time"
+	options.VAxis.Title = "Throughput"
+
+	var xmm MinMax
+	var ymm MinMax
+	for i := range d.Points {
+		for j := range d.Points[i] {
+			xmm.Update(d.Points[i][j].x)
+			ymm.Update(d.Points[i][j].y)
+		}
+	}
+
+	options.HAxis.MaxValue = xmm.Max
+	options.VAxis.MaxValue = ymm.Max
+
+	err = options.OutputJavascript(w, run)
+	if err != nil {
+		return
+	}
+
+	fmt.Printf("        var sp%ddata = new google.visualization.DataTable();\n", run)
+	fmt.Printf("        sp%ddata.addColumn('number', 'Time');\n", run)
+	for i := range d.Points {
+		fmt.Printf("        sp%ddata.addColumn('number', 'Worker %d');\n", run, i)
+	}
+	fmt.Printf("        sp%ddata.addRows([\n", run)
+
+	// Can't use json here because we need to be able to use 'null' for non-existent values
+	for i := range d.Points {
+		for j := range d.Points[i] {
+			err = d.Points[i][j].OutputJson(w, i, len(d.Points))
+			if err != nil {
+				return
+			}
+		}
+	}
+	fmt.Print("          ]);\n")
+	
+	fmt.Printf("        var sp%dchart = new google.visualization.ScatterChart(document.getElementById('scatterplot%d'));\n", run, run);
+	fmt.Printf("        sp%dchart.draw(sp%ddata, sp%dopt);\n\n", run, run, run)
+	
+	return
+}
+
+type HTMLReport struct {
+	Raw []RunRaw
+}
+
+
+func (rpt *HTMLReport) Output(w io.Writer) (err error) {
+	// Print start -> json charts
+	fmt.Fprint(w,
+		`<html>
+  <head>
+    <style>
+      .scatterplot {
+      margin:auto;
+      width: 100vw;
+      height: 60vw;
+      }
+
+      .empty {
+      margin: auto;
+      }
+    </style>
+    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
+    <script type="text/javascript">
+      google.charts.load('current', {'packages':['corechart']});
+      google.charts.setOnLoadCallback(drawCharts);
+      function drawCharts() {
+`);
+	// Print json chart code
+	for i := range rpt.Raw {
+		err = rpt.Raw[i].OutputJavascript(w, i)
+		if err != nil {
+			return
+		}
+	}
+	// Print json -> html
+	fmt.Fprint(w,
+		`      }
+    </script>
+  </head>
+  <body>
+`);
+	// Print html
+	for i := range rpt.Raw {
+		err = rpt.Raw[i].OutputHTML(w, i)
+		if err != nil {
+			return
+		}
+	}
+	// Print html -> end
+	fmt.Fprint(w,
+		`  </body>
+</html>
+`);
+	return
+}
+
+func (rpt *HTMLReport) AddRun(run *BenchmarkRun) (err error) {
+	var d RunRaw
+
+	d.Label = run.Label
+	for set := range run.Results.Summary {
+		var idPoints []Point
+		for id := range run.Results.Summary[set].Workers {
+			var le WorkerReport
+			for _, e := range run.Results.Summary[set].Workers[id].Raw {
+				if e.Now > le.Now {
+					time := float64(e.Now) / SEC
+					tput := Throughput(e.Now, e.Kops, le.Now, le.Kops)
+					idPoints = append(idPoints, Point{x:time, y:tput})
+				}
+				le = e
+			}
+		}
+		d.Points = append(d.Points, idPoints)
+	}
+	rpt.Raw = append(rpt.Raw, d)
+	return
+}
+
+func (plan *BenchmarkPlan) HTMLReport() (err error) {
+	rpt := HTMLReport{}
+
+	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 = rpt.AddRun(r)
+		if err != nil {
+			return
+		}
+	}
+	err = rpt.Output(os.Stdout)
+
+	return
+}
diff --git a/main.go b/main.go
index 13230a7..f8d77cf 100644
--- a/main.go
+++ b/main.go
@@ -107,6 +107,18 @@ func main() {
 			fmt.Println("Running benchmark run:", err)
 			os.Exit(1)
 		}
+	case "htmlreport":
+		plan, err := LoadBenchmark(filename)
+		if err != nil {
+			fmt.Println("Loading benchmark ", filename, " ", err)
+			os.Exit(1)
+		}
+	
+		err = plan.HTMLReport()
+		if err != nil {
+			fmt.Println("Running benchmark run:", err)
+			os.Exit(1)
+		}
 	default:
 		fmt.Println("Unknown argument: ", os.Args[1])
 	}
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 30/59] htmlreport: Include utilization scatterplots
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (27 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 29/59] report: Add basic html report Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 31/59] Make a binary that can run reports on a system without libxl Ronald Rojas
                   ` (28 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Reformat RunRaw so that it's a more generic scatterplot, with the
caller specifying the javascript tag, title, and axes.  Keep them as a
straight list to be displayed rather than defining them on a per-run
basis.

Collect a slice of utilization points at the same time as collecting
the throughput metrics, add them both at the same time.

While we're here, add "omitempty" to some of the options so no json is
generated if nothing is specified.  Leave "MinValue" so that we are
able to specify a zero origin (which will also be the default).

Finally, don't bother finding minimum and maximum points; the chart
plotter will do that anyway.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 htmlreport.go | 89 +++++++++++++++++++++++++++++++----------------------------
 1 file changed, 47 insertions(+), 42 deletions(-)

diff --git a/htmlreport.go b/htmlreport.go
index 6f61998..545582d 100644
--- a/htmlreport.go
+++ b/htmlreport.go
@@ -26,16 +26,17 @@ import (
 )
 
 type OptionAxis struct {
-	Title string `json:"title"`
+	Title string `json:"title,omitempty"`
+	// Always include this one so that we can start graphs at 0
 	MinValue float64 `json:"minValue"`
-	MaxValue float64 `json:"maxValue"`
+	MaxValue float64 `json:"maxValue,omitempty"`
 }
 
 type Options struct {
-	Title string     `json:"title"`
+	Title string     `json:"title,omitempty"`
 	HAxis OptionAxis `json:"hAxis"`
 	VAxis OptionAxis `json:"vAxis"`
-	Legend string    `json:"legend"`
+	Legend string    `json:"legend,omitempty"`
 }
 
 type Point struct {
@@ -44,18 +45,21 @@ type Point struct {
 }
 
 type RunRaw struct {
-	Label string
+	Tag string
+	Title string
+	hTitle string
+	vTitle string
 	Points [][]Point
 }
 
-func (options *Options) OutputJavascript(w io.Writer, id int) (err error) {
+func (options *Options) OutputJavascript(w io.Writer, tag string) (err error) {
 	var optionsJson []byte
 	optionsJson, err = json.Marshal(options)
 	if err != nil {
 		return
 	}
 
-	fmt.Fprintf(w, "        var sp%dopt = ", id)
+	fmt.Fprintf(w, "        var %sopt = ", tag)
 	fmt.Fprint(w, string(optionsJson))
 	fmt.Fprintln(w, ";")
 
@@ -75,41 +79,29 @@ func (p *Point) OutputJson(w io.Writer, id int, max int) (err error) {
 	return
 }
 
-func (d *RunRaw) OutputHTML(w io.Writer, run int) (err error) {
-	fmt.Fprintf(w, "    <div class='scatterplot' id='scatterplot%d'></div>\n", run)
+func (d *RunRaw) OutputHTML(w io.Writer) (err error) {
+	fmt.Fprintf(w, "    <div class='scatterplot' id='scatterplot%s'></div>\n", d.Tag)
 	return
 }
 
-func (d *RunRaw) OutputJavascript(w io.Writer, run int) (err error) {
+func (d *RunRaw) OutputJavascript(w io.Writer) (err error) {
 	var options Options
 
-	options.Title = fmt.Sprintf("Run %s (%d) Individual Throughput", d.Label, run)
-	options.HAxis.Title = "Time"
-	options.VAxis.Title = "Throughput"
+	options.Title = d.Title
+	options.HAxis.Title = d.hTitle
+	options.VAxis.Title = d.vTitle
 
-	var xmm MinMax
-	var ymm MinMax
-	for i := range d.Points {
-		for j := range d.Points[i] {
-			xmm.Update(d.Points[i][j].x)
-			ymm.Update(d.Points[i][j].y)
-		}
-	}
-
-	options.HAxis.MaxValue = xmm.Max
-	options.VAxis.MaxValue = ymm.Max
-
-	err = options.OutputJavascript(w, run)
+	err = options.OutputJavascript(w, d.Tag)
 	if err != nil {
 		return
 	}
 
-	fmt.Printf("        var sp%ddata = new google.visualization.DataTable();\n", run)
-	fmt.Printf("        sp%ddata.addColumn('number', 'Time');\n", run)
+	fmt.Printf("        var %sdata = new google.visualization.DataTable();\n", d.Tag)
+	fmt.Printf("        %sdata.addColumn('number', 'Time');\n", d.Tag)
 	for i := range d.Points {
-		fmt.Printf("        sp%ddata.addColumn('number', 'Worker %d');\n", run, i)
+		fmt.Printf("        %sdata.addColumn('number', 'Worker %d');\n", d.Tag, i)
 	}
-	fmt.Printf("        sp%ddata.addRows([\n", run)
+	fmt.Printf("        %sdata.addRows([\n", d.Tag)
 
 	// Can't use json here because we need to be able to use 'null' for non-existent values
 	for i := range d.Points {
@@ -122,8 +114,8 @@ func (d *RunRaw) OutputJavascript(w io.Writer, run int) (err error) {
 	}
 	fmt.Print("          ]);\n")
 	
-	fmt.Printf("        var sp%dchart = new google.visualization.ScatterChart(document.getElementById('scatterplot%d'));\n", run, run);
-	fmt.Printf("        sp%dchart.draw(sp%ddata, sp%dopt);\n\n", run, run, run)
+	fmt.Printf("        var %schart = new google.visualization.ScatterChart(document.getElementById('scatterplot%s'));\n", d.Tag, d.Tag);
+	fmt.Printf("        %schart.draw(%sdata, %sopt);\n\n", d.Tag, d.Tag, d.Tag)
 	
 	return
 }
@@ -157,7 +149,7 @@ func (rpt *HTMLReport) Output(w io.Writer) (err error) {
 `);
 	// Print json chart code
 	for i := range rpt.Raw {
-		err = rpt.Raw[i].OutputJavascript(w, i)
+		err = rpt.Raw[i].OutputJavascript(w)
 		if err != nil {
 			return
 		}
@@ -171,7 +163,7 @@ func (rpt *HTMLReport) Output(w io.Writer) (err error) {
 `);
 	// Print html
 	for i := range rpt.Raw {
-		err = rpt.Raw[i].OutputHTML(w, i)
+		err = rpt.Raw[i].OutputHTML(w)
 		if err != nil {
 			return
 		}
@@ -185,25 +177,38 @@ func (rpt *HTMLReport) Output(w io.Writer) (err error) {
 }
 
 func (rpt *HTMLReport) AddRun(run *BenchmarkRun) (err error) {
-	var d RunRaw
-
-	d.Label = run.Label
+	var tPut RunRaw
+	var Util RunRaw
+
+	tPut.Title = fmt.Sprintf("Run %s Individual Throughput", run.Label)
+	tPut.hTitle = "Time (s)"
+	tPut.vTitle = "Throughput (kOps)"
+	Util.Title = fmt.Sprintf("Run %s Individual Utilization", run.Label)
+	Util.hTitle = "Time (s)"
+	Util.vTitle = "Utilization"
 	for set := range run.Results.Summary {
-		var idPoints []Point
+		var idTput []Point
+		var idUtil []Point
 		for id := range run.Results.Summary[set].Workers {
 			var le WorkerReport
 			for _, e := range run.Results.Summary[set].Workers[id].Raw {
-				if e.Now > le.Now {
+				if e.Kops > 0 {
 					time := float64(e.Now) / SEC
 					tput := Throughput(e.Now, e.Kops, le.Now, le.Kops)
-					idPoints = append(idPoints, Point{x:time, y:tput})
+					util := Utilization(e.Now, e.Cputime, le.Now, le.Cputime)
+					idTput = append(idTput, Point{x:time, y:tput})
+					idUtil = append(idUtil, Point{x:time, y:util})
 				}
 				le = e
 			}
 		}
-		d.Points = append(d.Points, idPoints)
+		tPut.Points = append(tPut.Points, idTput)
+		Util.Points = append(Util.Points, idUtil)
 	}
-	rpt.Raw = append(rpt.Raw, d)
+	tPut.Tag = fmt.Sprintf("raw%d", len(rpt.Raw))
+	rpt.Raw = append(rpt.Raw, tPut)
+	Util.Tag = fmt.Sprintf("raw%d", len(rpt.Raw))
+	rpt.Raw = append(rpt.Raw, Util)
 	return
 }
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 31/59] Make a binary that can run reports on a system without libxl
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (28 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 30/59] htmlreport: Include utilization scatterplots Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 32/59] controller: Allow specification of an input file Ronald Rojas
                   ` (27 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

To simplify report-generation and iteration, make a binary that
doesn't link against libxl.  Create a "dummy" Xen library that just
returns errors and warnings.

A better way to do this is probably to do some dlopen hackery (so we
can use the same binary), but that's for another day.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile           |  6 +++++-
 xenworker_dummy.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 xenworker_dummy.go

diff --git a/Makefile b/Makefile
index c1b9ee4..6dee499 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-BIN = schedbench
+BIN = schedbench schedbench-report
 BINALL = $(BIN)
 
 .PHONY: all
@@ -16,6 +16,10 @@ CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH) $(CGO_LIBS)
 schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go htmlreport.go
 	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -o $@ $^
 
+# FIXME: Do with dlopen instead
+schedbench-report: main.go processworker.go xenworker_dummy.go benchmark.go run.go htmlreport.go
+	go build -o $@ $^
+
 .PHONY: clean
 clean:
 	rm -f $(BINALL)
diff --git a/xenworker_dummy.go b/xenworker_dummy.go
new file mode 100644
index 0000000..02e90ce
--- /dev/null
+++ b/xenworker_dummy.go
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+package main
+
+import (
+	"fmt"
+	"io"
+)
+
+type XenWorker struct {
+}
+
+func (w *XenWorker) SetId(i WorkerId) {
+}
+
+func (w *XenWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
+	err = fmt.Errorf("Xen functionality not implemented");
+	return
+}
+
+// FIXME: Return an error
+func (w *XenWorker) Shutdown() {
+	
+	return
+}
+
+func (w *XenWorker) DumpLog(f io.Writer) (err error) {
+	err = fmt.Errorf("Xen functionality not implemented");
+	return
+}
+
+
+
+// FIXME: Return an error
+func (w *XenWorker) Process(report chan WorkerReport, done chan WorkerId) {
+	return;
+}
+
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 32/59] controller: Allow specification of an input file
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (29 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 31/59] Make a binary that can run reports on a system without libxl Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 33/59] controller: Add verbosity argument and update README with new instructions Ronald Rojas
                   ` (26 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

So that we can analyze data later if we want.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 194 +++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 106 insertions(+), 88 deletions(-)

diff --git a/main.go b/main.go
index f8d77cf..ddb768c 100644
--- a/main.go
+++ b/main.go
@@ -26,101 +26,119 @@ import (
 )
 
 func main() {
-	filename := "test.bench"
-
-	switch(os.Args[1]) {
-	case "plan":
-		workerA := []string{"burnwait", "70", "200000"}
-		//workerB := []string{"burnwait", "10", "20000000"}
-		workerB := []string{"burnwait", "10", "300000",
-			"burnwait", "20", "300000",
-			"burnwait", "10", "300000",
-			"burnwait", "10", "300000",
-			"burnwait", "10", "300000",
-			"burnwait", "10", "300000",
-			"burnwait", "30", "300000",
-		}
+	Args := os.Args
 
+	Args = Args[1:]
+	filename := "test.bench"
 
-		plan :=  BenchmarkPlan{
-			WorkerType:WorkerXen,
-			WorkerConfig:WorkerConfig{Pool:"schedbench"},
-			filename:filename,
-			Runs:[]BenchmarkRun{
-				{Label:"baseline-a",
+	for len(Args) > 0 {
+		switch(Args[0]) {
+		case "-f":
+			if len(Args) < 2 {
+				fmt.Println("Need arg for -f")
+				os.Exit(1)
+			}
+			filename = Args[1]
+			Args = Args[2:]
+		case "plan":
+			workerA := []string{"burnwait", "70", "200000"}
+			//workerB := []string{"burnwait", "10", "20000000"}
+			workerB := []string{"burnwait", "10", "300000",
+				"burnwait", "20", "300000",
+				"burnwait", "10", "300000",
+				"burnwait", "10", "300000",
+				"burnwait", "10", "300000",
+				"burnwait", "10", "300000",
+				"burnwait", "30", "300000",
+			}
+			
+			
+			plan :=  BenchmarkPlan{
+				WorkerType:WorkerXen,
+				WorkerConfig:WorkerConfig{Pool:"schedbench"},
+				filename:filename,
+				Runs:[]BenchmarkRun{
+					{Label:"baseline-a",
+						WorkerSets:[]WorkerSet{
+							{Params:WorkerParams{workerA},
+								Count:1}},
+						RuntimeSeconds:10,},
+					{Label:"baseline-b",
+						WorkerSets:[]WorkerSet{
+							{Params:WorkerParams{workerB},
+								Count:1}},
+						RuntimeSeconds:10,},
+				}}
+			
+			for i := 1; i <= 16 ; i *= 2 {
+				label := fmt.Sprintf("%da+%db", i, i)
+				run := BenchmarkRun{
+					Label:label,
 					WorkerSets:[]WorkerSet{
 						{Params:WorkerParams{workerA},
-							Count:1}},
-					RuntimeSeconds:10,},
-				{Label:"baseline-b",
-					WorkerSets:[]WorkerSet{
+							Count:i},
 						{Params:WorkerParams{workerB},
-							Count:1}},
-					RuntimeSeconds:10,},
-			}}
-
-		for i := 1; i <= 16 ; i *= 2 {
-			label := fmt.Sprintf("%da+%db", i, i)
-			run := BenchmarkRun{
-				Label:label,
-				WorkerSets:[]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)
-			os.Exit(1)
-		}
-		fmt.Println("Created plan in ", filename)
-	case "run":
-		plan, err := LoadBenchmark(filename)
-		if err != nil {
-			fmt.Println("Loading benchmark ", filename, " ", err)
-			os.Exit(1)
-		}
-	
-		err = plan.Run()
-		if err != nil {
-			fmt.Println("Running benchmark run:", err)
-			os.Exit(1)
-		}
-		
-	case "report":
-		verbosity := 0
-		if len(os.Args) > 2 {
-			verbosity, _ = strconv.Atoi(os.Args[2])
-		}
-		plan, err := LoadBenchmark(filename)
-		if err != nil {
-			fmt.Println("Loading benchmark ", filename, " ", err)
-			os.Exit(1)
-		}
-	
-		err = plan.TextReport(verbosity)
-		if err != nil {
-			fmt.Println("Running benchmark run:", err)
-			os.Exit(1)
-		}
-	case "htmlreport":
-		plan, err := LoadBenchmark(filename)
-		if err != nil {
-			fmt.Println("Loading benchmark ", filename, " ", err)
-			os.Exit(1)
-		}
-	
-		err = plan.HTMLReport()
-		if err != nil {
-			fmt.Println("Running benchmark run:", err)
+							Count:i}},
+					RuntimeSeconds:10}
+				plan.Runs = append(plan.Runs, run)
+			}
+			
+			err := plan.Save()
+			if err != nil {
+				fmt.Println("Saving plan ", filename, " ", err)
+				os.Exit(1)
+			}
+			fmt.Println("Created plan in ", filename)
+			Args = Args[1:]
+		case "run":
+			plan, err := LoadBenchmark(filename)
+			if err != nil {
+				fmt.Println("Loading benchmark ", filename, " ", err)
+				os.Exit(1)
+			}
+			
+			err = plan.Run()
+			if err != nil {
+				fmt.Println("Running benchmark run:", err)
+				os.Exit(1)
+			}
+			Args = Args[1:]
+			
+		case "report":
+			verbosity := 0
+			Args = Args[1:]
+			if len(Args) > 0 {
+				verbosity, _ = strconv.Atoi(os.Args[0])
+				Args = Args[1:]
+			}
+			plan, err := LoadBenchmark(filename)
+			if err != nil {
+				fmt.Println("Loading benchmark ", filename, " ", err)
+				os.Exit(1)
+			}
+			
+			err = plan.TextReport(verbosity)
+			if err != nil {
+				fmt.Println("Running benchmark run:", err)
+				os.Exit(1)
+			}
+		case "htmlreport":
+			plan, err := LoadBenchmark(filename)
+			if err != nil {
+				fmt.Println("Loading benchmark ", filename, " ", err)
+				os.Exit(1)
+			}
+			
+			err = plan.HTMLReport()
+			if err != nil {
+				fmt.Println("Running benchmark run:", err)
+				os.Exit(1)
+			}
+			Args = Args[1:]
+		default:
+			fmt.Println("Unknown argument: ", Args[0])
 			os.Exit(1)
 		}
-	default:
-		fmt.Println("Unknown argument: ", os.Args[1])
 	}
 }
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 33/59] controller: Add verbosity argument and update README with new instructions
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (30 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 32/59] controller: Allow specification of an input file Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 34/59] controller: Make a useful config file Ronald Rojas
                   ` (25 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/main.go b/main.go
index ddb768c..2aa8bae 100644
--- a/main.go
+++ b/main.go
@@ -30,6 +30,7 @@ func main() {
 
 	Args = Args[1:]
 	filename := "test.bench"
+	verbosity := 0
 
 	for len(Args) > 0 {
 		switch(Args[0]) {
@@ -40,6 +41,13 @@ func main() {
 			}
 			filename = Args[1]
 			Args = Args[2:]
+		case "-v":
+			if len(Args) < 2 {
+				fmt.Println("Need arg for -v")
+				os.Exit(1)
+			}
+			verbosity, _ = strconv.Atoi(Args[1])
+			Args = Args[2:]
 		case "plan":
 			workerA := []string{"burnwait", "70", "200000"}
 			//workerB := []string{"burnwait", "10", "20000000"}
@@ -105,12 +113,7 @@ func main() {
 			Args = Args[1:]
 			
 		case "report":
-			verbosity := 0
 			Args = Args[1:]
-			if len(Args) > 0 {
-				verbosity, _ = strconv.Atoi(os.Args[0])
-				Args = Args[1:]
-			}
 			plan, err := LoadBenchmark(filename)
 			if err != nil {
 				fmt.Println("Loading benchmark ", filename, " ", err)
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 34/59] controller: Make a useful config file
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (31 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 33/59] controller: Add verbosity argument and update README with new instructions Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 35/59] libxl: Add ListCpupool Ronald Rojas
                   ` (24 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Allow a simple "skeleton" config file which can be adapted for the
particular use case.  Have 'plan' expand this with the real benchmark
plan.

Include "sample.bench" as a template to modify.  Also update the
README.md accordingly.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile     |  4 +--
 benchmark.go |  9 ++++---
 main.go      | 48 ++++++------------------------------
 plan.go      | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 47 deletions(-)
 create mode 100644 plan.go

diff --git a/Makefile b/Makefile
index 6dee499..af55e0a 100644
--- a/Makefile
+++ b/Makefile
@@ -13,11 +13,11 @@ CGO_LIBS = -lyajl -lxenlight
 XENLIB_PATH ?= /build/hg/xen.git/dist/install/usr/local/lib/
 CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH) $(CGO_LIBS)
 
-schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go htmlreport.go
+schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go htmlreport.go plan.go
 	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -o $@ $^
 
 # FIXME: Do with dlopen instead
-schedbench-report: main.go processworker.go xenworker_dummy.go benchmark.go run.go htmlreport.go
+schedbench-report: main.go processworker.go xenworker_dummy.go benchmark.go run.go htmlreport.go plan.go
 	go build -o $@ $^
 
 .PHONY: clean
diff --git a/benchmark.go b/benchmark.go
index 8be00a0..31b3711 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -148,12 +148,13 @@ type BenchmarkRun struct {
 }
 
 type BenchmarkPlan struct {
-	filename string
-	WorkerType int
+	Input *PlanInput     `json:",omitempty"`
+	filename string      `json:",omitempty"`
+	WorkerType int       `json:",omitempty"`
 	// Global options for workers that will be over-ridden by Run
 	// and WorkerSet config options
-	WorkerConfig
-	Runs []BenchmarkRun
+	WorkerConfig         `json:",omitempty"`
+	Runs []BenchmarkRun  `json:",omitempty"`
 }
 
 func (run *BenchmarkRun) checkSummary() (done bool, err error) {
diff --git a/main.go b/main.go
index 2aa8bae..059a54a 100644
--- a/main.go
+++ b/main.go
@@ -49,49 +49,15 @@ func main() {
 			verbosity, _ = strconv.Atoi(Args[1])
 			Args = Args[2:]
 		case "plan":
-			workerA := []string{"burnwait", "70", "200000"}
-			//workerB := []string{"burnwait", "10", "20000000"}
-			workerB := []string{"burnwait", "10", "300000",
-				"burnwait", "20", "300000",
-				"burnwait", "10", "300000",
-				"burnwait", "10", "300000",
-				"burnwait", "10", "300000",
-				"burnwait", "10", "300000",
-				"burnwait", "30", "300000",
-			}
-			
-			
-			plan :=  BenchmarkPlan{
-				WorkerType:WorkerXen,
-				WorkerConfig:WorkerConfig{Pool:"schedbench"},
-				filename:filename,
-				Runs:[]BenchmarkRun{
-					{Label:"baseline-a",
-						WorkerSets:[]WorkerSet{
-							{Params:WorkerParams{workerA},
-								Count:1}},
-						RuntimeSeconds:10,},
-					{Label:"baseline-b",
-						WorkerSets:[]WorkerSet{
-							{Params:WorkerParams{workerB},
-								Count:1}},
-						RuntimeSeconds:10,},
-				}}
-			
-			for i := 1; i <= 16 ; i *= 2 {
-				label := fmt.Sprintf("%da+%db", i, i)
-				run := BenchmarkRun{
-					Label:label,
-					WorkerSets:[]WorkerSet{
-						{Params:WorkerParams{workerA},
-							Count:i},
-						{Params:WorkerParams{workerB},
-							Count:i}},
-					RuntimeSeconds:10}
-				plan.Runs = append(plan.Runs, run)
+			plan, err := LoadBenchmark(filename)
+			if err != nil {
+				fmt.Println("Loading benchmark ", filename, " ", err)
+				os.Exit(1)
 			}
 			
-			err := plan.Save()
+			plan.ExpandInput()
+
+			err = plan.Save()
 			if err != nil {
 				fmt.Println("Saving plan ", filename, " ", err)
 				os.Exit(1)
diff --git a/plan.go b/plan.go
new file mode 100644
index 0000000..2983e78
--- /dev/null
+++ b/plan.go
@@ -0,0 +1,79 @@
+package main
+
+import (
+	"fmt"
+)
+
+type PlanSimpleMatrix struct {
+	Schedulers []string
+	Workers []string
+	Count []int
+}
+
+type PlanInput struct {
+	WorkerPresets map[string]WorkerParams
+	SimpleMatrix *PlanSimpleMatrix
+}
+
+var WorkerPresets = map[string]WorkerParams{
+	"P001":WorkerParams{[]string{"burnwait", "70", "200000"}},
+}
+
+
+func (plan *BenchmarkPlan) ExpandInput() (err error) {
+	if plan.Runs != nil {
+		fmt.Printf("plan.Expand: Runs non-empty, not doing anything\n");
+		return
+	}
+	
+	if plan.Input.SimpleMatrix == nil {
+		fmt.Printf("plan.Expand: SimpleMatrix nil, nothing to do\n");
+		return
+	}
+
+	for k := range plan.Input.WorkerPresets {
+		WorkerPresets[k] = plan.Input.WorkerPresets[k];
+	}
+
+	// Always do the baselines
+	for _, wn := range plan.Input.SimpleMatrix.Workers {
+		wp := WorkerPresets[wn]
+
+		if wp.Args == nil {
+			err = fmt.Errorf("Invalid worker preset: %s", wn)
+			return
+		}
+
+		run := BenchmarkRun{
+			Label:wn+" baseline",
+			WorkerSets:[]WorkerSet{{Params:wp, Count:1}},
+			RuntimeSeconds:10,
+		}
+
+		plan.Runs = append(plan.Runs, run)
+	}
+
+	for _, c := range plan.Input.SimpleMatrix.Count {
+		run := BenchmarkRun{
+			RuntimeSeconds:10,
+		}
+
+		var label string
+		for _, wn := range plan.Input.SimpleMatrix.Workers {
+			wp := WorkerPresets[wn]
+			
+			if label != "" {
+				label = label+" + "
+			}
+			label = fmt.Sprintf("%s%s %d", label, wn, c)
+			
+			ws := WorkerSet{Params:wp, Count:c}
+			run.WorkerSets = append(run.WorkerSets, ws)
+		}
+		run.Label = label
+
+		plan.Runs = append(plan.Runs, run)
+	}
+
+	return
+}
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 35/59] libxl: Add ListCpupool
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (32 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 34/59] controller: Make a useful config file Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 36/59] controller: Make 'dummy' at the level of 'run' rather than xenworker Ronald Rojas
                   ` (23 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Add libxl bindings for libxl_list_cpupool().

Define the Scheduler type (based on libxl_schedler) with appropriate
constants and string functions.

Punt on the cpumap part of CpupoolInfo for now.

Also create "xltest" command for testing libxl bindings

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go           | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 main.go            |   5 ++
 xenworker_dummy.go |   4 ++
 3 files changed, 161 insertions(+)

diff --git a/libxl.go b/libxl.go
index 415de7f..5bdabb1 100644
--- a/libxl.go
+++ b/libxl.go
@@ -2,6 +2,7 @@ package main
 
 /*
 #include <libxl.h>
+#include <stdlib.h>
 */
 import "C"
 
@@ -128,3 +129,154 @@ func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
 	}
 	return
 }
+
+
+// typedef struct {
+//     uint32_t size;          /* number of bytes in map */
+//     uint8_t *map;
+// } libxl_bitmap;
+// void libxl_bitmap_init(libxl_bitmap *map);
+// void libxl_bitmap_dispose(libxl_bitmap *map);
+
+// # Consistent with values defined in domctl.h
+// # Except unknown which we have made up
+// libxl_scheduler = Enumeration("scheduler", [
+//     (0, "unknown"),
+//     (4, "sedf"),
+//     (5, "credit"),
+//     (6, "credit2"),
+//     (7, "arinc653"),
+//     (8, "rtds"),
+//     ])
+type Scheduler int
+var (
+	SchedulerUnknown  Scheduler = 0
+	SchedulerSedf     Scheduler = 4
+	SchedulerCredit   Scheduler = 5
+	SchedulerCredit2  Scheduler = 6
+	SchedulerArinc653 Scheduler = 7
+	SchedulerRTDS     Scheduler = 8
+)
+
+// const char *libxl_scheduler_to_string(libxl_scheduler p);
+// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
+func (s Scheduler) String() (string) {
+	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
+	// No need to free const return value
+
+	return C.GoString(cs)
+}
+
+func SchedulerFromString(name string) (s Scheduler, err error) {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+
+	var cs C.libxl_scheduler
+
+	ret := C.libxl_scheduler_from_string(cname, &cs)
+	if ret != 0 {
+		err = fmt.Errorf("libxl_scheduler_from_string failed: %d", ret)
+		return
+	}
+
+	s = Scheduler(cs)
+
+	return
+}
+
+// libxl_cpupoolinfo = Struct("cpupoolinfo", [
+//     ("poolid",      uint32),
+//     ("pool_name",   string),
+//     ("sched",       libxl_scheduler),
+//     ("n_dom",       uint32),
+//     ("cpumap",      libxl_bitmap)
+//     ], dir=DIR_OUT)
+
+type CpupoolInfo struct {
+	PoolId uint32
+	PoolName string
+	Scheduler Scheduler
+	DomainCount int
+	// Punt on cpumap for now
+}
+
+// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
+// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
+func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
+	var nbPool C.int
+
+	c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
+
+	defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
+
+	if int(nbPool) == 0 {
+		return
+	}
+
+	// Magic
+	cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
+
+	for i := range cpupoolListSlice {
+		var info CpupoolInfo
+		
+		info.PoolId = uint32(cpupoolListSlice[i].poolid)
+		info.PoolName = C.GoString(cpupoolListSlice[i].pool_name)
+		info.Scheduler = Scheduler(cpupoolListSlice[i].sched)
+		info.DomainCount = int(cpupoolListSlice[i].n_dom)
+
+		list = append(list, info)
+	}
+
+	return
+}
+
+func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		if plist[i].PoolName == name {
+			found = true
+			info = plist[i]
+			return
+		}
+	}
+	return
+}
+
+func XlTest(Args []string) {
+	var Ctx Context
+
+	err := Ctx.Open()
+	if err != nil {
+		fmt.Printf("Opening context: %v\n", err)
+		return
+	}
+
+	pool, found := Ctx.CpupoolFindByName("schedbench")
+
+	if found {
+		fmt.Printf("%v\n", pool)
+
+		a := int(pool.Scheduler)
+		b := pool.Scheduler.String()
+		c, err  := SchedulerFromString(b)
+
+		if err != nil {
+			fmt.Printf("Error: %v\n", err)
+		}
+
+		fmt.Printf("a: %d b: %s c: %d\n", a, b, int(c)) 
+	} else {
+		fmt.Printf("schedbench not found")
+	}
+
+	pool, found = Ctx.CpupoolFindByName("schedbnch")
+
+	if found {
+		fmt.Printf("%v\n", pool)
+	} else {
+		fmt.Printf("schedbnch not found")
+	}
+
+	Ctx.Close()
+}
diff --git a/main.go b/main.go
index 059a54a..2f68969 100644
--- a/main.go
+++ b/main.go
@@ -104,6 +104,11 @@ func main() {
 				os.Exit(1)
 			}
 			Args = Args[1:]
+
+		case "xltest":
+			XlTest(Args)
+			Args = nil
+			
 		default:
 			fmt.Println("Unknown argument: ", Args[0])
 			os.Exit(1)
diff --git a/xenworker_dummy.go b/xenworker_dummy.go
index 02e90ce..e2dbdae 100644
--- a/xenworker_dummy.go
+++ b/xenworker_dummy.go
@@ -26,6 +26,10 @@ import (
 type XenWorker struct {
 }
 
+func XlTest(Args []string) {
+	return
+}
+
 func (w *XenWorker) SetId(i WorkerId) {
 }
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 36/59] controller: Make 'dummy' at the level of 'run' rather than xenworker
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (33 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 35/59] libxl: Add ListCpupool Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 37/59] libxl.go: Provide a single global context by default Ronald Rojas
                   ` (22 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Get rid of xenworker_dummy.go and use stubs.go instead.  This is much
cleaner (as evidenced by the size of the file), and allows us to use
libxl-based things in run.go without having to make a load of dummy
libxl stub functions.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile           |  2 +-
 stubs.go           | 34 ++++++++++++++++++++++++++++++++
 xenworker_dummy.go | 58 ------------------------------------------------------
 3 files changed, 35 insertions(+), 59 deletions(-)
 create mode 100644 stubs.go
 delete mode 100644 xenworker_dummy.go

diff --git a/Makefile b/Makefile
index af55e0a..0e0b231 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go h
 	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -o $@ $^
 
 # FIXME: Do with dlopen instead
-schedbench-report: main.go processworker.go xenworker_dummy.go benchmark.go run.go htmlreport.go plan.go
+schedbench-report: main.go benchmark.go stubs.go htmlreport.go plan.go
 	go build -o $@ $^
 
 .PHONY: clean
diff --git a/stubs.go b/stubs.go
new file mode 100644
index 0000000..78987ad
--- /dev/null
+++ b/stubs.go
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+package main
+
+import (
+	"fmt"
+)
+
+func (plan *BenchmarkPlan) Run() (err error) {
+	err = fmt.Errorf("Not implemented")
+
+	return
+}
+
+func XlTest(Args []string) {
+	return
+}
+
diff --git a/xenworker_dummy.go b/xenworker_dummy.go
deleted file mode 100644
index e2dbdae..0000000
--- a/xenworker_dummy.go
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-import (
-	"fmt"
-	"io"
-)
-
-type XenWorker struct {
-}
-
-func XlTest(Args []string) {
-	return
-}
-
-func (w *XenWorker) SetId(i WorkerId) {
-}
-
-func (w *XenWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
-	err = fmt.Errorf("Xen functionality not implemented");
-	return
-}
-
-// FIXME: Return an error
-func (w *XenWorker) Shutdown() {
-	
-	return
-}
-
-func (w *XenWorker) DumpLog(f io.Writer) (err error) {
-	err = fmt.Errorf("Xen functionality not implemented");
-	return
-}
-
-
-
-// FIXME: Return an error
-func (w *XenWorker) Process(report chan WorkerReport, done chan WorkerId) {
-	return;
-}
-
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 37/59] libxl.go: Provide a single global context by default
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (34 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 36/59] controller: Make 'dummy' at the level of 'run' rather than xenworker Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 38/59] controller: Allow multiple schedulers in the same benchmark file Ronald Rojas
                   ` (21 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Provide a single global context by default, Ctx.  Allow this to be
called with Ctx.Open() multiple times (but Close() only once).

Move xenworker.go to use this global context instead; and open it when
starting the benchmark (rather than opening and closing it for every
run, which is effectively what happens now).

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go     | 12 +++++-------
 run.go       |  7 +++++++
 xenworker.go | 25 +++++--------------------
 3 files changed, 17 insertions(+), 27 deletions(-)

diff --git a/libxl.go b/libxl.go
index 5bdabb1..9477bca 100644
--- a/libxl.go
+++ b/libxl.go
@@ -16,19 +16,17 @@ type Context struct {
 	ctx *C.libxl_ctx
 }
 
-func NewContext() (Ctx *Context, err error) {
-	Ctx = &Context{}
-	
-	err = Ctx.Open()
-
-	return
-}
+var Ctx Context
 
 func (Ctx *Context) IsOpen() bool {
 	return Ctx.ctx != nil
 }
 
 func (Ctx *Context) Open() (err error) {
+	if Ctx.ctx != nil {
+		return
+	}
+	
 	ret := C.libxl_ctx_alloc(unsafe.Pointer(&Ctx.ctx), C.LIBXL_VERSION, 0, nil)
 
 	if ret != 0 {
diff --git a/run.go b/run.go
index 1b39730..08a43ff 100644
--- a/run.go
+++ b/run.go
@@ -228,6 +228,13 @@ func (plan *BenchmarkPlan) Run() (err error) {
 	if err != nil {
 		return
 	}
+
+	if plan.WorkerType == WorkerXen {
+		err = Ctx.Open()
+		if err != nil {
+			return
+		}
+	}
 	
 	for i := range plan.Runs {
 		r := &plan.Runs[i];
diff --git a/xenworker.go b/xenworker.go
index 45e0876..2649392 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -27,13 +27,6 @@ import (
 	"io"
 )
 
-type xenGlobal struct {
-	Ctx Context
-	count int
-}
-
-var xg xenGlobal
-
 type XenWorker struct {
 	id WorkerId
 	Ctx Context
@@ -68,13 +61,9 @@ func (w *XenWorker) SetId(i WorkerId) {
 }
 
 func (w *XenWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
-	if xg.count == 0 {
-		err = xg.Ctx.Open()
-		if err != nil {
-			return
-		}
+	if err != nil {
+		return
 	}
-	xg.count++
 	
 	mock := false
 	
@@ -220,11 +209,6 @@ func (w *XenWorker) Shutdown() {
 	e.Stdout = os.Stdout
 	e.Stderr = os.Stderr
 
-	xg.count--
-	if xg.count == 0 {
-		defer xg.Ctx.Close()
-	}
-
 	err := e.Run()
 	if err != nil {
 		fmt.Printf("Error destroying domain: %v\n", err)
@@ -249,7 +233,8 @@ func (w *XenWorker) DumpLog(f io.Writer) (err error) {
 // FIXME: Return an error
 func (w *XenWorker) Process(report chan WorkerReport, done chan WorkerId) {
 	// // xl unpause [vmname]
-	err := xg.Ctx.DomainUnpause(Domid(w.domid))
+	//err := xg.Ctx.DomainUnpause(Domid(w.domid))
+	err := Ctx.DomainUnpause(Domid(w.domid))
 	if err != nil {
 		fmt.Printf("Error unpausing domain: %v\n", err)
 		return
@@ -268,7 +253,7 @@ func (w *XenWorker) Process(report chan WorkerReport, done chan WorkerId) {
 			var r WorkerReport
 			json.Unmarshal([]byte(s), &r)
 			r.Id = w.id
-			di, err := xg.Ctx.DomainInfo(Domid(w.domid))
+			di, err := Ctx.DomainInfo(Domid(w.domid))
 			// Ignore errors for now
 			if err == nil {
 				r.Cputime = di.Cpu_time
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 38/59] controller: Allow multiple schedulers in the same benchmark file
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (35 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 37/59] libxl.go: Provide a single global context by default Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 39/59] libxl.go: Put common link flags in libxl.go Ronald Rojas
                   ` (20 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

First, add a RunConfig element to BenchmarkRun, which contains a
(string) name of the scheduler for this run.

Add run.Ready(), which if RunConfig.Scheduler is non-null, will check
to see if the cpupool in which the VMs will run (either
WorkerConfig.Pool or PoolID 0) has the specified scheduler.

Finally, when expanding the SimpleMatrix plan, if
SimpleMatrix.Schedulers is non-emply, add it to the matrix of runs.
Put them next to each other so that it's easy to compare similar runs
on different schedulers.

Refactor schedbench.sh to account for this, and also update the
README.md.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go |  5 +++++
 plan.go      | 38 +++++++++++++++++++++++++++-----------
 run.go       | 59 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 3 files changed, 81 insertions(+), 21 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index 31b3711..b77b66b 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -138,10 +138,15 @@ type BenchmarkRunData struct {
 	Summary []WorkerSetSummary  `json:",omitempty"`
 }
 
+type RunConfig struct {
+	Scheduler string
+}
+
 type BenchmarkRun struct {
 	Label string
 	WorkerSets []WorkerSet
 	WorkerConfig
+	RunConfig
 	RuntimeSeconds int
 	Completed bool
 	Results BenchmarkRunData 
diff --git a/plan.go b/plan.go
index 2983e78..24c6bd4 100644
--- a/plan.go
+++ b/plan.go
@@ -35,29 +35,42 @@ func (plan *BenchmarkPlan) ExpandInput() (err error) {
 		WorkerPresets[k] = plan.Input.WorkerPresets[k];
 	}
 
+	// Use named schedulers, or default to "" (which will use the
+	// current one)
+	var schedulers []string
+	if plan.Input.SimpleMatrix.Schedulers != nil {
+		schedulers = plan.Input.SimpleMatrix.Schedulers
+	} else {
+		schedulers = append(schedulers, "")
+	}
+
 	// Always do the baselines
 	for _, wn := range plan.Input.SimpleMatrix.Workers {
 		wp := WorkerPresets[wn]
-
+		
 		if wp.Args == nil {
 			err = fmt.Errorf("Invalid worker preset: %s", wn)
 			return
 		}
-
+		
 		run := BenchmarkRun{
-			Label:wn+" baseline",
 			WorkerSets:[]WorkerSet{{Params:wp, Count:1}},
 			RuntimeSeconds:10,
 		}
-
-		plan.Runs = append(plan.Runs, run)
+		
+		for _, s := range schedulers {
+			fmt.Printf("Making baseline %s run, sched %s\n", wn, s)
+			run.RunConfig.Scheduler = s
+			run.Label = wn+" baseline "+s
+			plan.Runs = append(plan.Runs, run)
+		}
 	}
-
+		
 	for _, c := range plan.Input.SimpleMatrix.Count {
 		run := BenchmarkRun{
 			RuntimeSeconds:10,
 		}
-
+		
 		var label string
 		for _, wn := range plan.Input.SimpleMatrix.Workers {
 			wp := WorkerPresets[wn]
@@ -65,14 +78,17 @@ func (plan *BenchmarkPlan) ExpandInput() (err error) {
 			if label != "" {
 				label = label+" + "
 			}
-			label = fmt.Sprintf("%s%s %d", label, wn, c)
+			label = fmt.Sprintf("%s%s %d ", label, wn, c)
 			
 			ws := WorkerSet{Params:wp, Count:c}
 			run.WorkerSets = append(run.WorkerSets, ws)
 		}
-		run.Label = label
-
-		plan.Runs = append(plan.Runs, run)
+		for _, s := range schedulers {
+			fmt.Printf("Making count %d run, sched %s\n", c, s)
+			run.RunConfig.Scheduler = s
+			run.Label = label+s
+			plan.Runs = append(plan.Runs, run)
+		}
 	}
 
 	return
diff --git a/run.go b/run.go
index 08a43ff..1a753bc 100644
--- a/run.go
+++ b/run.go
@@ -3,7 +3,7 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
+ * published by the Free Software Foundation; version 2 of the
  * License only.
  *
  * This program is distributed in the hope that it will be useful, but
@@ -156,6 +156,38 @@ 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]
+			} else {
+				why = "cpupool error"
+				return
+			}
+		}
+
+		if pool.Scheduler.String() != run.RunConfig.Scheduler {
+			why = "scheduler != "+run.RunConfig.Scheduler
+			return 
+		}
+	}
+	ready = true
+	return 
+}
+
 func (run *BenchmarkRun) Run() (err error) {
 	for wsi := range run.WorkerSets {
 		run.WorkerSets[wsi].Config.PropagateFrom(run.WorkerConfig)
@@ -238,20 +270,27 @@ func (plan *BenchmarkPlan) Run() (err error) {
 	
 	for i := range plan.Runs {
 		r := &plan.Runs[i];
-		if ! r.Completed {
+		if ! r.Completed { 
 			r.WorkerConfig.PropagateFrom(plan.WorkerConfig)
-			fmt.Printf("Running test [%d] %s\n", i, r.Label)
-			err = r.Run()
+			ready, why := r.Ready()
+			if ready {
+				fmt.Printf("Running test [%d] %s\n", i, r.Label)
+				err = r.Run()
+				if err != nil {
+					return
+				}
+			} else {
+				fmt.Printf("Test [%d]: %s skipped (%s)\n", i, r.Label, why)
+			}
+		}
+		if r.Completed {
+			fmt.Printf("Test [%d] %s completed\n", i, r.Label)
+			err = plan.Save()
 			if err != nil {
+				fmt.Println("Error saving: ", err)
 				return
 			}
 		}
-		fmt.Printf("Test [%d] %s completed\n", i, r.Label)
-		err = plan.Save()
-		if err != nil {
-			fmt.Println("Error saving: ", err)
-			return
-		}
 	}
 	return
 }
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 39/59] libxl.go: Put common link flags in libxl.go
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (36 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 38/59] controller: Allow multiple schedulers in the same benchmark file Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 40/59] controller: Add / update GPL text Ronald Rojas
                   ` (19 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

...so that the only things added in the makefile are extra flags
required when linking against non-installed builds.

Add in the text of the GPL while we're at it.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile |  3 +--
 libxl.go | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 0e0b231..0265dc8 100644
--- a/Makefile
+++ b/Makefile
@@ -7,11 +7,10 @@ all: $(BIN)
 
 
 CGO_CFLAGS = -I/build/hg/xen.git/dist/install/usr/local/include
-CGO_LIBS = -lyajl -lxenlight
 
 # FIXME
 XENLIB_PATH ?= /build/hg/xen.git/dist/install/usr/local/lib/
-CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH) $(CGO_LIBS)
+CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH)
 
 schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go htmlreport.go plan.go
 	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -o $@ $^
diff --git a/libxl.go b/libxl.go
index 9477bca..6621974 100644
--- a/libxl.go
+++ b/libxl.go
@@ -1,6 +1,25 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
 package main
 
 /*
+#cgo LDFLAGS: -lyajl -lxenlight
 #include <libxl.h>
 #include <stdlib.h>
 */
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 40/59] controller: Add / update GPL text
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (37 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 39/59] libxl.go: Put common link flags in libxl.go Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 41/59] libxl.go: Link statically rather than dynamically Ronald Rojas
                   ` (18 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Add it to files which are missing it; clarify the wording regarding
version 2 only in others.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go     | 2 +-
 main.go          | 2 +-
 processworker.go | 2 +-
 xenworker.go     | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index b77b66b..aecb574 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -3,7 +3,7 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
+ * published by the Free Software Foundation; version 2 of the
  * License only.
  *
  * This program is distributed in the hope that it will be useful, but
diff --git a/main.go b/main.go
index 2f68969..8cbd708 100644
--- a/main.go
+++ b/main.go
@@ -3,7 +3,7 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
+ * published by the Free Software Foundation; version 2 of the
  * License only.
  *
  * This program is distributed in the hope that it will be useful, but
diff --git a/processworker.go b/processworker.go
index 999e76a..8c27f15 100644
--- a/processworker.go
+++ b/processworker.go
@@ -3,7 +3,7 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
+ * published by the Free Software Foundation; version 2 of the
  * License only.
  *
  * This program is distributed in the hope that it will be useful, but
diff --git a/xenworker.go b/xenworker.go
index 2649392..10817b5 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -3,7 +3,7 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
+ * published by the Free Software Foundation; version 2 of the
  * License only.
  *
  * This program is distributed in the hope that it will be useful, but
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 41/59] libxl.go: Link statically rather than dynamically
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (38 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 40/59] controller: Add / update GPL text Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 42/59] plan: Allow "templating" from other runs Ronald Rojas
                   ` (17 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Link statically rather than dynamically, because Go prefers that.

This also gets rid of the need for schedbench-report, so disable that
from the build (although keep the rule and the dummy file around just
in case.

Also update README.md.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 Makefile | 11 +++++++----
 libxl.go | 10 +++++++++-
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/Makefile b/Makefile
index 0265dc8..699cc53 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-BIN = schedbench schedbench-report
+BIN = schedbench
 BINALL = $(BIN)
 
 .PHONY: all
@@ -10,12 +10,15 @@ CGO_CFLAGS = -I/build/hg/xen.git/dist/install/usr/local/include
 
 # FIXME
 XENLIB_PATH ?= /build/hg/xen.git/dist/install/usr/local/lib/
-CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH)
+CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH) 
 
 schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go htmlreport.go plan.go
-	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -o $@ $^
+	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -ldflags '-linkmode external -extldflags "-static"' -o $@ $^
 
-# FIXME: Do with dlopen instead
+# If we use a statically linked binary we don't need this; the same
+# binary can be used on any system.  Keep this version (without any
+# run support) support) around for now in case we want to go back to
+# it.
 schedbench-report: main.go benchmark.go stubs.go htmlreport.go plan.go
 	go build -o $@ $^
 
diff --git a/libxl.go b/libxl.go
index 6621974..27e7766 100644
--- a/libxl.go
+++ b/libxl.go
@@ -19,12 +19,20 @@
 package main
 
 /*
-#cgo LDFLAGS: -lyajl -lxenlight
+#cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
 #include <libxl.h>
 #include <stdlib.h>
 */
 import "C"
 
+/*
+ * Other flags that may be needed at some point: 
+ *  -lnl-route-3 -lnl-3
+ *
+ * To get back to simple dynamic linking:
+#cgo LDFLAGS: -lxenlight -lyajl
+*/
+
 import (
 	"unsafe"
 	"fmt"
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 42/59] plan: Allow "templating" from other runs
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (39 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 41/59] libxl.go: Link statically rather than dynamically Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 43/59] libxl: Add bitmap support Ronald Rojas
                   ` (16 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Allow 'plan' to use an existing run as a "template": load the template,
discard the runs, and save the result in the new file.

Use like this:

./schedbench -t 18.bench -f 20.bench plan

This will make 20 with an empty plan identical to that in 18.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 main.go | 38 +++++++++++++++++++++++++++++++++-----
 plan.go | 32 ++++++++++++++++++++++++++++++--
 2 files changed, 63 insertions(+), 7 deletions(-)

diff --git a/main.go b/main.go
index 8cbd708..ead6ab0 100644
--- a/main.go
+++ b/main.go
@@ -30,6 +30,7 @@ func main() {
 
 	Args = Args[1:]
 	filename := "test.bench"
+	template := ""
 	verbosity := 0
 
 	for len(Args) > 0 {
@@ -41,6 +42,13 @@ func main() {
 			}
 			filename = Args[1]
 			Args = Args[2:]
+		case "-t":
+			if len(Args) < 2 {
+				fmt.Println("Need arg for -t")
+				os.Exit(1)
+			}
+			template = Args[1]
+			Args = Args[2:]
 		case "-v":
 			if len(Args) < 2 {
 				fmt.Println("Need arg for -v")
@@ -49,20 +57,40 @@ func main() {
 			verbosity, _ = strconv.Atoi(Args[1])
 			Args = Args[2:]
 		case "plan":
-			plan, err := LoadBenchmark(filename)
+			// Load either the template benchmark or the filename
+			loadfile := filename
+			if template != "" {
+				loadfile = template
+			}
+			plan, err := LoadBenchmark(loadfile)
 			if err != nil {
-				fmt.Println("Loading benchmark ", filename, " ", err)
+				fmt.Printf("Loading benchmark %s: %v\n",
+					loadfile, err)
 				os.Exit(1)
 			}
+
+			if template != "" {
+				plan.filename = filename
+				err = plan.ClearRuns()
+				if err != nil {
+					fmt.Printf("Clearing runs: %v\n",
+						err)
+					os.Exit(1)
+				}
+			}
 			
-			plan.ExpandInput()
+			err = plan.ExpandInput()
+			if err != nil {
+				fmt.Printf("Expanding plan: %v\n", err)
+				os.Exit(1)
+			}
 
 			err = plan.Save()
 			if err != nil {
-				fmt.Println("Saving plan ", filename, " ", err)
+				fmt.Printf("Saving plan %s: %v\n", filename, err)
 				os.Exit(1)
 			}
-			fmt.Println("Created plan in ", filename)
+			fmt.Printf("Created plan in %s\n", filename)
 			Args = Args[1:]
 		case "run":
 			plan, err := LoadBenchmark(filename)
diff --git a/plan.go b/plan.go
index 24c6bd4..e535603 100644
--- a/plan.go
+++ b/plan.go
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
 package main
 
 import (
@@ -19,15 +37,25 @@ var WorkerPresets = map[string]WorkerParams{
 	"P001":WorkerParams{[]string{"burnwait", "70", "200000"}},
 }
 
+func (plan *BenchmarkPlan) ClearRuns() (err error) {
+	plan.Runs = nil
+
+	return
+}
 
 func (plan *BenchmarkPlan) ExpandInput() (err error) {
 	if plan.Runs != nil {
-		fmt.Printf("plan.Expand: Runs non-empty, not doing anything\n");
+		err = fmt.Errorf("Runs non-empty, not doing anything\n");
+		return
+	}
+
+	if plan.Input == nil {
+		err = fmt.Errorf("Input nil, nothing to do")
 		return
 	}
 	
 	if plan.Input.SimpleMatrix == nil {
-		fmt.Printf("plan.Expand: SimpleMatrix nil, nothing to do\n");
+		err = fmt.Errorf("Input.SimpleMatrix nil, nothing to do\n");
 		return
 	}
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 43/59] libxl: Add bitmap support
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (40 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 42/59] plan: Allow "templating" from other runs Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 44/59] libxl: Implement CpupoolCreate Ronald Rojas
                   ` (15 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Make the structure compatible so that we can just copy things out or
in.

Use it to complete the Cpupool structure.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 98 insertions(+), 6 deletions(-)

diff --git a/libxl.go b/libxl.go
index 27e7766..3f6ba01 100644
--- a/libxl.go
+++ b/libxl.go
@@ -20,8 +20,8 @@ package main
 
 /*
 #cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
-#include <libxl.h>
 #include <stdlib.h>
+#include <libxl.h>
 */
 import "C"
 
@@ -72,6 +72,7 @@ func (Ctx *Context) Close() (err error) {
 	return
 }
 
+// Builtins
 type Domid uint32
 
 type MemKB uint64
@@ -160,8 +161,66 @@ func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
 //     uint32_t size;          /* number of bytes in map */
 //     uint8_t *map;
 // } libxl_bitmap;
-// void libxl_bitmap_init(libxl_bitmap *map);
-// void libxl_bitmap_dispose(libxl_bitmap *map);
+
+// Implement the Go bitmap type such that the underlying data can
+// easily be copied in and out.  NB that we still have to do copies
+// both directions, because cgo runtime restrictions forbid passing to
+// a C function a pointer to a Go-allocated structure which contains a
+// pointer.
+type Bitmap struct {
+	bitmap []C.uint8_t
+}
+
+func (bm *Bitmap) Alloc(max int) {
+	bm.bitmap = make([]C.uint8_t, (max + 7) / 8)
+}
+
+// Return a Go bitmap which is a copy of the referred C bitmap.
+func bitmapCToGo(cbm *C.libxl_bitmap) (bm Bitmap) {
+	// Alloc a Go slice for the bytes
+	size := int(cbm.size)
+	bm.Alloc(size*8)
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+	// And copy the C array into the Go array
+	copy(bm.bitmap, mapslice)
+
+	return
+}
+
+func (bm *Bitmap) Test(bit int) (bool) {
+	ubit := uint(bit)
+	if (bit > bm.Max()) {
+		return false
+	}
+	
+	return (bm.bitmap[bit / 8] & (1 << (ubit & 7))) != 0
+}
+
+// FIXME: Do we really just want to silently fail here?
+func (bm *Bitmap) Set(bit int) {
+	ubit := uint(bit)
+	if (bit > bm.Max()) {
+		return
+	}
+	
+	bm.bitmap[bit / 8] |= 1 << (ubit & 7)
+}
+
+func (bm *Bitmap) Clear(bit int) {
+	ubit := uint(bit)
+	if (bit > bm.Max()) {
+		return
+	}
+	
+	bm.bitmap[bit / 8] &= ^(1 << (ubit & 7))
+}
+
+func (bm *Bitmap) Max() (int) {
+	return len(bm.bitmap) * 8
+}
 
 // # Consistent with values defined in domctl.h
 // # Except unknown which we have made up
@@ -222,7 +281,7 @@ type CpupoolInfo struct {
 	PoolName string
 	Scheduler Scheduler
 	DomainCount int
-	// Punt on cpumap for now
+	CpuMap Bitmap
 }
 
 // libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
@@ -248,6 +307,7 @@ func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
 		info.PoolName = C.GoString(cpupoolListSlice[i].pool_name)
 		info.Scheduler = Scheduler(cpupoolListSlice[i].sched)
 		info.DomainCount = int(cpupoolListSlice[i].n_dom)
+		info.CpuMap = bitmapCToGo(&cpupoolListSlice[i].cpumap)
 
 		list = append(list, info)
 	}
@@ -268,6 +328,24 @@ func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool
 	return
 }
 
+// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
+//                          libxl_scheduler sched,
+//                          libxl_bitmap cpumap, libxl_uuid *uuid,
+//                          uint32_t *poolid);
+// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
+// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
+// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
+// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                 const libxl_bitmap *cpumap);
+// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
+// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                    const libxl_bitmap *cpumap);
+// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
+// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
+
+	
 func XlTest(Args []string) {
 	var Ctx Context
 
@@ -290,7 +368,21 @@ func XlTest(Args []string) {
 			fmt.Printf("Error: %v\n", err)
 		}
 
-		fmt.Printf("a: %d b: %s c: %d\n", a, b, int(c)) 
+		fmt.Printf("a: %d b: %s c: %d\n", a, b, int(c))
+
+		pool.CpuMap.Set(1)
+		pool.CpuMap.Set(2)
+		pool.CpuMap.Clear(2)
+		
+		fmt.Printf("cpumap: ")
+		for i := 0; i < pool.CpuMap.Max() ; i++ {
+			if pool.CpuMap.Test(i) {
+				fmt.Printf("x")
+			} else {
+				fmt.Printf("-")
+			}
+		}
+		fmt.Printf("\n")
 	} else {
 		fmt.Printf("schedbench not found")
 	}
@@ -300,7 +392,7 @@ func XlTest(Args []string) {
 	if found {
 		fmt.Printf("%v\n", pool)
 	} else {
-		fmt.Printf("schedbnch not found")
+		fmt.Printf("schedbnch not found\n")
 	}
 
 	Ctx.Close()
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 44/59] libxl: Implement CpupoolCreate
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (41 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 43/59] libxl: Add bitmap support Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 45/59] libxl: Implement Destroy, Add/Remove operations Ronald Rojas
                   ` (14 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Implement CpupoolCreate.

For now, follow the lead of "xl cpupool-create", by automatically
generating a new uuid each time a new cpupool is created, and by not
allowing the user to attempt to set the poolid.

This requires us to implement bytmapGotoC, which C-allocates the
appropriate array and copies the Go byte map into it.  This must be
C-allocated because the runtime restricts how Go-allocated structures
can be passed into C function calls.

While we're here, reorganize functions slightly, and change the Bitmap
implementation to automatically extend the array if the size of the
byte array is too small.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 119 +++++++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 85 insertions(+), 34 deletions(-)

diff --git a/libxl.go b/libxl.go
index 3f6ba01..6e17b53 100644
--- a/libxl.go
+++ b/libxl.go
@@ -176,20 +176,38 @@ func (bm *Bitmap) Alloc(max int) {
 }
 
 // Return a Go bitmap which is a copy of the referred C bitmap.
-func bitmapCToGo(cbm *C.libxl_bitmap) (bm Bitmap) {
+func bitmapCToGo(cbm *C.libxl_bitmap) (gbm Bitmap) {
 	// Alloc a Go slice for the bytes
 	size := int(cbm.size)
-	bm.Alloc(size*8)
+	gbm.Alloc(size*8)
 
 	// Make a slice pointing to the C array
 	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
 
 	// And copy the C array into the Go array
-	copy(bm.bitmap, mapslice)
+	copy(gbm.bitmap, mapslice)
 
 	return
 }
 
+// Must be C.libxl_bitmap_dispose'd of afterwards
+func bitmapGotoC(gbm Bitmap, cbm *C.libxl_bitmap) {
+	C.libxl_bitmap_init(cbm)
+
+	size := len(gbm.bitmap)
+	cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
+	cbm.size = C.uint32_t(size)
+	if cbm._map == nil {
+		panic("C.calloc failed!")
+	}
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+	// And copy the Go array into the C array
+	copy(mapslice, gbm.bitmap)
+}
+
 func (bm *Bitmap) Test(bit int) (bool) {
 	ubit := uint(bit)
 	if (bit > bm.Max()) {
@@ -199,14 +217,13 @@ func (bm *Bitmap) Test(bit int) (bool) {
 	return (bm.bitmap[bit / 8] & (1 << (ubit & 7))) != 0
 }
 
-// FIXME: Do we really just want to silently fail here?
 func (bm *Bitmap) Set(bit int) {
-	ubit := uint(bit)
-	if (bit > bm.Max()) {
-		return
+	ibit := bit / 8;
+	if (ibit + 1 > len(bm.bitmap)) {
+		bm.bitmap = append(bm.bitmap, make([]C.uint8_t, ibit+1-len(bm.bitmap))...)
 	}
 	
-	bm.bitmap[bit / 8] |= 1 << (ubit & 7)
+	bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
 }
 
 func (bm *Bitmap) Clear(bit int) {
@@ -234,12 +251,12 @@ func (bm *Bitmap) Max() (int) {
 //     ])
 type Scheduler int
 var (
-	SchedulerUnknown  Scheduler = 0
-	SchedulerSedf     Scheduler = 4
-	SchedulerCredit   Scheduler = 5
-	SchedulerCredit2  Scheduler = 6
-	SchedulerArinc653 Scheduler = 7
-	SchedulerRTDS     Scheduler = 8
+	SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
+	SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
+	SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
+	SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
+	SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
+	SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
 )
 
 // const char *libxl_scheduler_to_string(libxl_scheduler p);
@@ -315,23 +332,38 @@ func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
 	return
 }
 
-func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
-	plist := Ctx.ListCpupool()
+// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
+//                          libxl_scheduler sched,
+//                          libxl_bitmap cpumap, libxl_uuid *uuid,
+//                          uint32_t *poolid);
+// FIXME: uuid
+// FIXME: Setting poolid
+func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
+	poolid := C.uint32_t(0)
+	name := C.CString(Name)
+	defer C.free(unsafe.Pointer(name))
+	
+	// For now, just do what xl does, and make a new uuid every time we create the pool
+	var uuid C.libxl_uuid
+	C.libxl_uuid_generate(&uuid)
 
-	for i := range plist {
-		if plist[i].PoolName == name {
-			found = true
-			info = plist[i]
-			return
-		}
+	var cbm C.libxl_bitmap
+	bitmapGotoC(Cpumap, &cbm)
+	defer C.libxl_bitmap_dispose(&cbm)
+	
+	ret := C.libxl_cpupool_create(Ctx.ctx, name, C.libxl_scheduler(Scheduler),
+		cbm, &uuid, &poolid)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_create failed: %d", ret)
+		return
 	}
+
+	Poolid = uint32(poolid)
+	
 	return
 }
 
-// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
-//                          libxl_scheduler sched,
-//                          libxl_bitmap cpumap, libxl_uuid *uuid,
-//                          uint32_t *poolid);
 // int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
 // int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
 // int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
@@ -345,7 +377,22 @@ func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool
 // int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
 // int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
 
-	
+//
+// Utility functions
+//
+func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		if plist[i].PoolName == name {
+			found = true
+			info = plist[i]
+			return
+		}
+	}
+	return
+}
+
 func XlTest(Args []string) {
 	var Ctx Context
 
@@ -384,15 +431,19 @@ func XlTest(Args []string) {
 		}
 		fmt.Printf("\n")
 	} else {
-		fmt.Printf("schedbench not found")
-	}
+		fmt.Printf("schedbench not found, creating\n")
 
-	pool, found = Ctx.CpupoolFindByName("schedbnch")
+		var Cpumap Bitmap
+		var Poolid uint32
 
-	if found {
-		fmt.Printf("%v\n", pool)
-	} else {
-		fmt.Printf("schedbnch not found\n")
+		Cpumap.Set(15)
+
+		err, Poolid = Ctx.CpupoolCreate("schedbench", SchedulerCredit, Cpumap)
+		if err != nil {
+			fmt.Printf("Error creating cpupool: %v\n", err)
+		} else {
+			fmt.Printf("Pool id: %d\n", Poolid)
+		}
 	}
 
 	Ctx.Close()
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 45/59] libxl: Implement Destroy, Add/Remove operations
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (42 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 44/59] libxl: Implement CpupoolCreate Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 46/59] libxl: Reorganize bitmapGotoC Ronald Rojas
                   ` (13 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Also:

* Implement useful Bitmap operations: SetRange(), ClearRange(),
IsEmpty(), and And().

* Normalize CpupoolInfo element naming.

* Implement CpupoolMakeFree, which will scan through cpupools freeing
  the cpus in the map.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 150 insertions(+), 37 deletions(-)

diff --git a/libxl.go b/libxl.go
index 6e17b53..92064ca 100644
--- a/libxl.go
+++ b/libxl.go
@@ -226,6 +226,12 @@ func (bm *Bitmap) Set(bit int) {
 	bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
 }
 
+func (bm *Bitmap) SetRange(start int, end int) {
+	for i := start; i <= end; i++ {
+		bm.Set(i)
+	}
+}
+
 func (bm *Bitmap) Clear(bit int) {
 	ubit := uint(bit)
 	if (bit > bm.Max()) {
@@ -235,10 +241,42 @@ func (bm *Bitmap) Clear(bit int) {
 	bm.bitmap[bit / 8] &= ^(1 << (ubit & 7))
 }
 
+func (bm *Bitmap) ClearRange(start int, end int) {
+	for i := start; i <= end; i++ {
+		bm.Clear(i)
+	}
+}
+
 func (bm *Bitmap) Max() (int) {
 	return len(bm.bitmap) * 8
 }
 
+func (bm *Bitmap) IsEmpty() (bool) {
+	for i:=0; i<len(bm.bitmap); i++ {
+		if bm.bitmap[i] != 0 {
+			return false
+		}
+	}
+	return true
+}
+
+func (a Bitmap) And(b Bitmap) (c Bitmap) {
+	var max, min int
+	if len(a.bitmap) > len(b.bitmap) {
+		max = len(a.bitmap)
+		min = len(b.bitmap)
+	} else {
+		max = len(b.bitmap)
+		min = len(a.bitmap)
+	}
+	c.bitmap = make([]C.uint8_t, max)
+
+	for i := 0; i < min; i++ {
+		c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
+	}
+	return
+}
+
 // # Consistent with values defined in domctl.h
 // # Except unknown which we have made up
 // libxl_scheduler = Enumeration("scheduler", [
@@ -294,11 +332,11 @@ func SchedulerFromString(name string) (s Scheduler, err error) {
 //     ], dir=DIR_OUT)
 
 type CpupoolInfo struct {
-	PoolId uint32
+	Poolid uint32
 	PoolName string
 	Scheduler Scheduler
 	DomainCount int
-	CpuMap Bitmap
+	Cpumap Bitmap
 }
 
 // libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
@@ -320,11 +358,11 @@ func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
 	for i := range cpupoolListSlice {
 		var info CpupoolInfo
 		
-		info.PoolId = uint32(cpupoolListSlice[i].poolid)
+		info.Poolid = uint32(cpupoolListSlice[i].poolid)
 		info.PoolName = C.GoString(cpupoolListSlice[i].pool_name)
 		info.Scheduler = Scheduler(cpupoolListSlice[i].sched)
 		info.DomainCount = int(cpupoolListSlice[i].n_dom)
-		info.CpuMap = bitmapCToGo(&cpupoolListSlice[i].cpumap)
+		info.Cpumap = bitmapCToGo(&cpupoolListSlice[i].cpumap)
 
 		list = append(list, info)
 	}
@@ -365,15 +403,78 @@ func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitma
 }
 
 // int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
-// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
+func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
+	ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_destroy failed: %d", ret)
+		return
+	}
+
+	return
+}
+
 // int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
-// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
+	ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_cpuadd failed: %d", ret)
+		return
+	}
+
+	return
+}
+
 // int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
 //                                 const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	var cbm C.libxl_bitmap
+	bitmapGotoC(Cpumap, &cbm)
+	defer C.libxl_bitmap_dispose(&cbm)
+	
+	ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_cpuadd_cpumap failed: %d", ret)
+		return
+	}
+
+	return
+}
+
 // int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
-// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
+	ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_cpuremove failed: %d", ret)
+		return
+	}
+
+	return
+}
+
 // int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
 //                                    const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	var cbm C.libxl_bitmap
+	bitmapGotoC(Cpumap, &cbm)
+	defer C.libxl_bitmap_dispose(&cbm)
+	
+	ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_cpuremove_cpumap failed: %d", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
+// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
 // int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
 // int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
 
@@ -393,6 +494,22 @@ func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool
 	return
 }
 
+func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		var Intersection Bitmap
+		Intersection = Cpumap.And(plist[i].Cpumap)
+		if ! Intersection.IsEmpty() {
+			err = Ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, Intersection)
+			if err != nil {
+				return
+			}
+		}
+	}
+	return
+}
+
 func XlTest(Args []string) {
 	var Ctx Context
 
@@ -405,45 +522,41 @@ func XlTest(Args []string) {
 	pool, found := Ctx.CpupoolFindByName("schedbench")
 
 	if found {
-		fmt.Printf("%v\n", pool)
+		fmt.Printf("Found schedbench, destroying\n")
 
-		a := int(pool.Scheduler)
-		b := pool.Scheduler.String()
-		c, err  := SchedulerFromString(b)
+		err = Ctx.CpupoolDestroy(pool.Poolid)
+		if err != nil {
+			fmt.Printf("Couldn't destroy pool: %v\n", err)
+			return
+		}
 
+		fmt.Printf("Returning cpus to pool 0 for fun\n")
+		err = Ctx.CpupoolCpuaddCpumap(0, pool.Cpumap)
 		if err != nil {
-			fmt.Printf("Error: %v\n", err)
+			fmt.Printf("Couldn't add cpus to domain 0: %v\n", err)
+			return
 		}
+	}
 
-		fmt.Printf("a: %d b: %s c: %d\n", a, b, int(c))
+	var Cpumap Bitmap
 
-		pool.CpuMap.Set(1)
-		pool.CpuMap.Set(2)
-		pool.CpuMap.Clear(2)
-		
-		fmt.Printf("cpumap: ")
-		for i := 0; i < pool.CpuMap.Max() ; i++ {
-			if pool.CpuMap.Test(i) {
-				fmt.Printf("x")
-			} else {
-				fmt.Printf("-")
-			}
-		}
-		fmt.Printf("\n")
-	} else {
-		fmt.Printf("schedbench not found, creating\n")
+	Cpumap.SetRange(12, 15)
+
+	fmt.Printf("Freeing cpus\n")
+	err = Ctx.CpupoolMakeFree(Cpumap)
+	if err != nil {
+		fmt.Printf("Couldn't free cpus: %v\n", err)
+		return
+	}
 
-		var Cpumap Bitmap
-		var Poolid uint32
 
-		Cpumap.Set(15)
+	fmt.Printf("Creating new pool\n")
 
-		err, Poolid = Ctx.CpupoolCreate("schedbench", SchedulerCredit, Cpumap)
-		if err != nil {
-			fmt.Printf("Error creating cpupool: %v\n", err)
-		} else {
-			fmt.Printf("Pool id: %d\n", Poolid)
-		}
+	err, Poolid := Ctx.CpupoolCreate("schedbench", SchedulerCredit, Cpumap)
+	if err != nil {
+		fmt.Printf("Error creating cpupool: %v\n", err)
+	} else {
+		fmt.Printf("Pool id: %d\n", Poolid)
 	}
 
 	Ctx.Close()
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 46/59] libxl: Reorganize bitmapGotoC
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (43 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 45/59] libxl: Implement Destroy, Add/Remove operations Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 47/59] libxl: Reorganize code Ronald Rojas
                   ` (12 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

No need to "allocate" the structure elsewhere; passing as a return
value makes usage a lot cleaner.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/libxl.go b/libxl.go
index 92064ca..16f4645 100644
--- a/libxl.go
+++ b/libxl.go
@@ -191,8 +191,8 @@ func bitmapCToGo(cbm *C.libxl_bitmap) (gbm Bitmap) {
 }
 
 // Must be C.libxl_bitmap_dispose'd of afterwards
-func bitmapGotoC(gbm Bitmap, cbm *C.libxl_bitmap) {
-	C.libxl_bitmap_init(cbm)
+func bitmapGotoC(gbm Bitmap) (cbm C.libxl_bitmap) {
+	C.libxl_bitmap_init(&cbm)
 
 	size := len(gbm.bitmap)
 	cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
@@ -206,6 +206,8 @@ func bitmapGotoC(gbm Bitmap, cbm *C.libxl_bitmap) {
 
 	// And copy the Go array into the C array
 	copy(mapslice, gbm.bitmap)
+
+	return
 }
 
 func (bm *Bitmap) Test(bit int) (bool) {
@@ -385,8 +387,7 @@ func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitma
 	var uuid C.libxl_uuid
 	C.libxl_uuid_generate(&uuid)
 
-	var cbm C.libxl_bitmap
-	bitmapGotoC(Cpumap, &cbm)
+	cbm := bitmapGotoC(Cpumap)
 	defer C.libxl_bitmap_dispose(&cbm)
 	
 	ret := C.libxl_cpupool_create(Ctx.ctx, name, C.libxl_scheduler(Scheduler),
@@ -429,8 +430,7 @@ func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
 // int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
 //                                 const libxl_bitmap *cpumap);
 func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
-	var cbm C.libxl_bitmap
-	bitmapGotoC(Cpumap, &cbm)
+	cbm := bitmapGotoC(Cpumap)
 	defer C.libxl_bitmap_dispose(&cbm)
 	
 	ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
@@ -458,8 +458,7 @@ func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
 // int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
 //                                    const libxl_bitmap *cpumap);
 func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
-	var cbm C.libxl_bitmap
-	bitmapGotoC(Cpumap, &cbm)
+	cbm := bitmapGotoC(Cpumap)
 	defer C.libxl_bitmap_dispose(&cbm)
 	
 	ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 47/59] libxl: Reorganize code
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (44 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 46/59] libxl: Reorganize bitmapGotoC Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 48/59] libxl: Add Ctx.CheckOpen Ronald Rojas
                   ` (11 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Put all type and enumeration definitions at the top of the file,
separated into "builtins" and "idl-generated".

Also define Uuid as C.libxl_uud.  (Not sure if this gives us the
functionality we need without having to manually copy things in.)

Finally, get rid of Bitmap.Alloc().  It's redundant now that
Bitmap.Set() automatically extends the array.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 189 ++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 102 insertions(+), 87 deletions(-)

diff --git a/libxl.go b/libxl.go
index 16f4645..e73c06b 100644
--- a/libxl.go
+++ b/libxl.go
@@ -39,10 +39,102 @@ import (
 	"time"
 )
 
+/*
+ * Types: Builtins
+ */
+
+type Domid uint32
+
+type MemKB uint64
+
+// typedef struct {
+//     uint32_t size;          /* number of bytes in map */
+//     uint8_t *map;
+// } libxl_bitmap;
+
+// Implement the Go bitmap type such that the underlying data can
+// easily be copied in and out.  NB that we still have to do copies
+// both directions, because cgo runtime restrictions forbid passing to
+// a C function a pointer to a Go-allocated structure which contains a
+// pointer.
+type Bitmap struct {
+	bitmap []C.uint8_t
+}
+
 type Context struct {
 	ctx *C.libxl_ctx
 }
 
+type Uuid C.libxl_uuid
+
+/*
+ * Types: IDL
+ * 
+ * FIXME: Generate these automatically from the IDL
+ */
+type Dominfo struct {
+	Uuid              Uuid
+	Domid             Domid
+	Running           bool
+	Blocked           bool
+	Paused            bool
+	Shutdown          bool
+	Dying             bool
+	Never_stop        bool
+	
+	Shutdown_reason   int32 // FIXME shutdown_reason enumeration
+	Outstanding_memkb MemKB
+	Current_memkb     MemKB
+	Shared_memkb      MemKB
+	Paged_memkb       MemKB
+	Max_memkb         MemKB
+	Cpu_time          time.Duration
+	Vcpu_max_id       uint32
+	Vcpu_online       uint32
+	Cpupool           uint32
+	Domain_type       int32 //FIXME libxl_domain_type enumeration
+
+}
+
+// # Consistent with values defined in domctl.h
+// # Except unknown which we have made up
+// libxl_scheduler = Enumeration("scheduler", [
+//     (0, "unknown"),
+//     (4, "sedf"),
+//     (5, "credit"),
+//     (6, "credit2"),
+//     (7, "arinc653"),
+//     (8, "rtds"),
+//     ])
+type Scheduler int
+var (
+	SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
+	SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
+	SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
+	SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
+	SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
+	SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
+)
+
+// libxl_cpupoolinfo = Struct("cpupoolinfo", [
+//     ("poolid",      uint32),
+//     ("pool_name",   string),
+//     ("sched",       libxl_scheduler),
+//     ("n_dom",       uint32),
+//     ("cpumap",      libxl_bitmap)
+//     ], dir=DIR_OUT)
+
+type CpupoolInfo struct {
+	Poolid uint32
+	PoolName string
+	Scheduler Scheduler
+	DomainCount int
+	Cpumap Bitmap
+}
+
+/*
+ * Context
+ */
 var Ctx Context
 
 func (Ctx *Context) IsOpen() bool {
@@ -72,43 +164,12 @@ func (Ctx *Context) Close() (err error) {
 	return
 }
 
-// Builtins
-type Domid uint32
-
-type MemKB uint64
-
-// FIXME: Use the idl to generate types
-type Dominfo struct {
-	// FIXME: uuid
-	Domid             Domid
-	Running           bool
-	Blocked           bool
-	Paused            bool
-	Shutdown          bool
-	Dying             bool
-	Never_stop        bool
-	
-	Shutdown_reason   int32 // FIXME shutdown_reason enumeration
-	Outstanding_memkb MemKB
-	Current_memkb     MemKB
-	Shared_memkb      MemKB
-	Paged_memkb       MemKB
-	Max_memkb         MemKB
-	Cpu_time          time.Duration
-	Vcpu_max_id       uint32
-	Vcpu_online       uint32
-	Cpupool           uint32
-	Domain_type       int32 //FIXME libxl_domain_type enumeration
-
-}
-
 func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
 	if Ctx.ctx == nil {
 		err = fmt.Errorf("Context not opened")
 		return
 	}
 
-		
 	var cdi C.libxl_dominfo
 
 	ret := C.libxl_domain_info(Ctx.ctx, unsafe.Pointer(&cdi), C.uint32_t(Id))
@@ -119,8 +180,12 @@ func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
 		return
 	}
 
-	// FIXME -- use introspection to make this more robust
+	// We could consider having this boilerplate generated by the
+	// idl, in a function like this:
+	//
+	// di = translateCdomaininfoToGoDomaininfo(cdi)
 	di = &Dominfo{}
+	di.Uuid = Uuid(cdi.uuid)
 	di.Domid = Domid(cdi.domid)
 	di.Running = bool(cdi.running)
 	di.Blocked = bool(cdi.blocked)
@@ -139,6 +204,7 @@ func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
 	di.Vcpu_online = uint32(cdi.vcpu_online)
 	di.Cpupool = uint32(cdi.cpupool)
 	di.Domain_type = int32(cdi.domain_type)
+
 	return
 }
 
@@ -156,30 +222,15 @@ func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
 	return
 }
 
-
-// typedef struct {
-//     uint32_t size;          /* number of bytes in map */
-//     uint8_t *map;
-// } libxl_bitmap;
-
-// Implement the Go bitmap type such that the underlying data can
-// easily be copied in and out.  NB that we still have to do copies
-// both directions, because cgo runtime restrictions forbid passing to
-// a C function a pointer to a Go-allocated structure which contains a
-// pointer.
-type Bitmap struct {
-	bitmap []C.uint8_t
-}
-
-func (bm *Bitmap) Alloc(max int) {
-	bm.bitmap = make([]C.uint8_t, (max + 7) / 8)
-}
+/*
+ * Bitmap operations
+ */
 
 // Return a Go bitmap which is a copy of the referred C bitmap.
 func bitmapCToGo(cbm *C.libxl_bitmap) (gbm Bitmap) {
 	// Alloc a Go slice for the bytes
 	size := int(cbm.size)
-	gbm.Alloc(size*8)
+	gbm.bitmap = make([]C.uint8_t, size)
 
 	// Make a slice pointing to the C array
 	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
@@ -279,26 +330,6 @@ func (a Bitmap) And(b Bitmap) (c Bitmap) {
 	return
 }
 
-// # Consistent with values defined in domctl.h
-// # Except unknown which we have made up
-// libxl_scheduler = Enumeration("scheduler", [
-//     (0, "unknown"),
-//     (4, "sedf"),
-//     (5, "credit"),
-//     (6, "credit2"),
-//     (7, "arinc653"),
-//     (8, "rtds"),
-//     ])
-type Scheduler int
-var (
-	SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
-	SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
-	SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
-	SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
-	SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
-	SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
-)
-
 // const char *libxl_scheduler_to_string(libxl_scheduler p);
 // int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
 func (s Scheduler) String() (string) {
@@ -325,22 +356,6 @@ func SchedulerFromString(name string) (s Scheduler, err error) {
 	return
 }
 
-// libxl_cpupoolinfo = Struct("cpupoolinfo", [
-//     ("poolid",      uint32),
-//     ("pool_name",   string),
-//     ("sched",       libxl_scheduler),
-//     ("n_dom",       uint32),
-//     ("cpumap",      libxl_bitmap)
-//     ], dir=DIR_OUT)
-
-type CpupoolInfo struct {
-	Poolid uint32
-	PoolName string
-	Scheduler Scheduler
-	DomainCount int
-	Cpumap Bitmap
-}
-
 // libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
 // void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
 func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 48/59] libxl: Add Ctx.CheckOpen
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (45 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 47/59] libxl: Reorganize code Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 49/59] libxl: Implement libxl_cpupool_info and Scheduler.FromString() Ronald Rojas
                   ` (10 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

To standardize the error in the case that Ctx isn't open.  Add checks to all functions
which call libxl functions directly.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 48 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 45 insertions(+), 3 deletions(-)

diff --git a/libxl.go b/libxl.go
index e73c06b..8f16b1d 100644
--- a/libxl.go
+++ b/libxl.go
@@ -164,9 +164,16 @@ func (Ctx *Context) Close() (err error) {
 	return
 }
 
-func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
+func (Ctx *Context) CheckOpen() (err error) {
 	if Ctx.ctx == nil {
 		err = fmt.Errorf("Context not opened")
+	}
+	return
+}
+
+func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
 		return
 	}
 
@@ -209,8 +216,8 @@ func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
 }
 
 func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
-	if Ctx.ctx == nil {
-		err = fmt.Errorf("Context not opened")
+	err = Ctx.CheckOpen()
+	if err != nil {
 		return
 	}
 
@@ -359,6 +366,11 @@ func SchedulerFromString(name string) (s Scheduler, err error) {
 // libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
 // void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
 func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
+	err := Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
 	var nbPool C.int
 
 	c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
@@ -394,6 +406,11 @@ func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
 // FIXME: uuid
 // FIXME: Setting poolid
 func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
 	poolid := C.uint32_t(0)
 	name := C.CString(Name)
 	defer C.free(unsafe.Pointer(name))
@@ -420,6 +437,11 @@ func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitma
 
 // int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
 func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
 	ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
 	// FIXME: Proper error
 	if ret != 0 {
@@ -432,6 +454,11 @@ func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
 
 // int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
 func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
 	ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
 	// FIXME: Proper error
 	if ret != 0 {
@@ -445,6 +472,11 @@ func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
 // int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
 //                                 const libxl_bitmap *cpumap);
 func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
 	cbm := bitmapGotoC(Cpumap)
 	defer C.libxl_bitmap_dispose(&cbm)
 	
@@ -460,6 +492,11 @@ func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error
 
 // int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
 func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
 	ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
 	// FIXME: Proper error
 	if ret != 0 {
@@ -473,6 +510,11 @@ func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
 // int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
 //                                    const libxl_bitmap *cpumap);
 func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
 	cbm := bitmapGotoC(Cpumap)
 	defer C.libxl_bitmap_dispose(&cbm)
 	
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 49/59] libxl: Implement libxl_cpupool_info and Scheduler.FromString()
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (46 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 48/59] libxl: Add Ctx.CheckOpen Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 50/59] libxl: Fix Bitmap.Max(), make Test() / Clear() more robust Ronald Rojas
                   ` (9 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Unify the libxl_cpupoolinfo -> CpupoolInfo translation in a function.

Also make bitmapCToGo pass-by-value rather than pass-by-reference,
since it only has two elements and doesn't need to be modified.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 54 insertions(+), 10 deletions(-)

diff --git a/libxl.go b/libxl.go
index 8f16b1d..dfe4f40 100644
--- a/libxl.go
+++ b/libxl.go
@@ -234,7 +234,7 @@ func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
  */
 
 // Return a Go bitmap which is a copy of the referred C bitmap.
-func bitmapCToGo(cbm *C.libxl_bitmap) (gbm Bitmap) {
+func bitmapCToGo(cbm C.libxl_bitmap) (gbm Bitmap) {
 	// Alloc a Go slice for the bytes
 	size := int(cbm.size)
 	gbm.bitmap = make([]C.uint8_t, size)
@@ -338,7 +338,6 @@ func (a Bitmap) And(b Bitmap) (c Bitmap) {
 }
 
 // const char *libxl_scheduler_to_string(libxl_scheduler p);
-// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
 func (s Scheduler) String() (string) {
 	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
 	// No need to free const return value
@@ -346,6 +345,32 @@ func (s Scheduler) String() (string) {
 	return C.GoString(cs)
 }
 
+// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
+func (s *Scheduler) FromString(gstr string) (err error) {
+	cstr := C.CString(gstr)
+	defer C.free(unsafe.Pointer(cstr))
+
+	var cs C.libxl_scheduler
+	ret := C.libxl_scheduler_from_string(cstr, &cs)
+	if ret != 0 {
+		err = fmt.Errorf("libxl_scheduler_from_string: %d\n", ret)
+		return
+	}
+
+	*s = Scheduler(cs)
+	return
+}
+
+func translateCpupoolInfoCToGo(cci C.libxl_cpupoolinfo) (gci CpupoolInfo) {
+	gci.Poolid = uint32(cci.poolid)
+	gci.PoolName = C.GoString(cci.pool_name)
+	gci.Scheduler = Scheduler(cci.sched)
+	gci.DomainCount = int(cci.n_dom)
+	gci.Cpumap = bitmapCToGo(cci.cpumap)
+
+	return
+}
+
 func SchedulerFromString(name string) (s Scheduler, err error) {
 	cname := C.CString(name)
 	defer C.free(unsafe.Pointer(cname))
@@ -385,20 +410,37 @@ func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
 	cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
 
 	for i := range cpupoolListSlice {
-		var info CpupoolInfo
+		info := translateCpupoolInfoCToGo(cpupoolListSlice[i])
 		
-		info.Poolid = uint32(cpupoolListSlice[i].poolid)
-		info.PoolName = C.GoString(cpupoolListSlice[i].pool_name)
-		info.Scheduler = Scheduler(cpupoolListSlice[i].sched)
-		info.DomainCount = int(cpupoolListSlice[i].n_dom)
-		info.Cpumap = bitmapCToGo(&cpupoolListSlice[i].cpumap)
-
 		list = append(list, info)
 	}
 
 	return
 }
 
+// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
+func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo) {
+	err := Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var c_cpupool C.libxl_cpupoolinfo
+	
+	ret := C.libxl_cpupool_info(Ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_info failed: %d", ret)
+		return
+	}
+	defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
+
+	pool = translateCpupoolInfoCToGo(c_cpupool)
+
+	return
+}
+
+
+
 // int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
 //                          libxl_scheduler sched,
 //                          libxl_bitmap cpumap, libxl_uuid *uuid,
@@ -532,7 +574,6 @@ func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err er
 // int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
 // int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
 // int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
-// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
 
 //
 // Utility functions
@@ -615,5 +656,8 @@ func XlTest(Args []string) {
 		fmt.Printf("Pool id: %d\n", Poolid)
 	}
 
+	pool = Ctx.CpupoolInfo(0)
+	fmt.Printf("Cpupool 0 info: %v\n", pool)
+	
 	Ctx.Close()
 }
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 50/59] libxl: Fix Bitmap.Max(), make Test() / Clear() more robust
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (47 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 49/59] libxl: Implement libxl_cpupool_info and Scheduler.FromString() Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 51/59] controller: Make and/or modify cpupools when possible Ronald Rojas
                   ` (8 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Bitmap.Max() should return the largest currently addressable bit; at the
moment it returns the total number of bits (which is one greater than
the largest addressable bit).

This also implicitly fixes a bug in Test() and Clear() which would cause
an out-of-range error when testing a bit equal to Max().

While we're here, allow Test() and Clear() to handle null bitmaps, the
same way Set() can.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libxl.go b/libxl.go
index dfe4f40..bfcaf0d 100644
--- a/libxl.go
+++ b/libxl.go
@@ -270,7 +270,7 @@ func bitmapGotoC(gbm Bitmap) (cbm C.libxl_bitmap) {
 
 func (bm *Bitmap) Test(bit int) (bool) {
 	ubit := uint(bit)
-	if (bit > bm.Max()) {
+	if (bit > bm.Max() || bm.bitmap == nil) {
 		return false
 	}
 	
@@ -294,7 +294,7 @@ func (bm *Bitmap) SetRange(start int, end int) {
 
 func (bm *Bitmap) Clear(bit int) {
 	ubit := uint(bit)
-	if (bit > bm.Max()) {
+	if (bit > bm.Max() || bm.bitmap == nil) {
 		return
 	}
 	
@@ -308,7 +308,7 @@ func (bm *Bitmap) ClearRange(start int, end int) {
 }
 
 func (bm *Bitmap) Max() (int) {
-	return len(bm.bitmap) * 8
+	return len(bm.bitmap) * 8 - 1
 }
 
 func (bm *Bitmap) IsEmpty() (bool) {
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 51/59] controller: Make and/or modify cpupools when possible
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (48 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 50/59] libxl: Fix Bitmap.Max(), make Test() / Clear() more robust Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 52/59] libxl: Implement Bitmap.String() Ronald Rojas
                   ` (7 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

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@citrix.com>
---
 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@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 52/59] libxl: Implement Bitmap.String()
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (49 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 51/59] controller: Make and/or modify cpupools when possible Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 53/59] controller: Add WorkerConfig.SoftAffinity Ronald Rojas
                   ` (6 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Implement Bitmap.String, which will convert a bitmap into a string
parse-able by libxl.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 libxl.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/libxl.go b/libxl.go
index bfcaf0d..aa5c01c 100644
--- a/libxl.go
+++ b/libxl.go
@@ -337,6 +337,51 @@ func (a Bitmap) And(b Bitmap) (c Bitmap) {
 	return
 }
 
+func (bm Bitmap) String() (s string) {
+	lastOnline := false
+	crange := false
+	printed := false
+	var i int
+	/// --x-xxxxx-x -> 2,4-8,10
+	/// --x-xxxxxxx -> 2,4-10
+	for i = 0; i <= bm.Max(); i++ {
+		if bm.Test(i) {
+			if !lastOnline {
+				// Switching offline -> online, print this cpu
+				if printed {
+					s += ","
+				}
+				s += fmt.Sprintf("%d", i)
+				printed = true
+			} else if !crange {
+				// last was online, but we're not in a range; print -
+				crange = true
+				s += "-"
+			} else {
+				// last was online, we're in a range,  nothing else to do
+			}
+			lastOnline = true
+		} else {
+			if lastOnline {
+				// Switching online->offline; do we need to end a range?
+				if crange {
+					s += fmt.Sprintf("%d", i-1)
+				}
+			}
+			lastOnline = false
+			crange = false
+		}
+	}
+	if lastOnline {
+		// Switching online->offline; do we need to end a range?
+		if crange {
+			s += fmt.Sprintf("%d", i-1)
+		}
+	}
+
+	return
+}
+
 // const char *libxl_scheduler_to_string(libxl_scheduler p);
 func (s Scheduler) String() (string) {
 	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
@@ -608,6 +653,18 @@ func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
 }
 
 func XlTest(Args []string) {
+	var Cpumap Bitmap
+
+	Cpumap.Set(2)
+	Cpumap.SetRange(4, 8)
+	Cpumap.Set(10)
+
+	fmt.Printf("Cpumap: %v\n", Cpumap)
+
+	Cpumap.Set(9)
+
+	fmt.Printf("Cpumap: %v\n", Cpumap)
+
 	var Ctx Context
 
 	err := Ctx.Open()
@@ -635,7 +692,7 @@ func XlTest(Args []string) {
 		}
 	}
 
-	var Cpumap Bitmap
+	Cpumap = Bitmap{}
 
 	Cpumap.SetRange(12, 15)
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 53/59] controller: Add WorkerConfig.SoftAffinity
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (50 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 52/59] libxl: Implement Bitmap.String() Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 54/59] controller/run: Add RunConfig.NumaDisable Ronald Rojas
                   ` (5 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

If the SoftAffinity is present, pass it as "cpus_soft = ..." in the
config file.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go | 1 +
 xenworker.go | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/benchmark.go b/benchmark.go
index bd513fd..d5a0ac8 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -58,6 +58,7 @@ func (l *WorkerParams) SetkHZ(kHZ uint64) {
 
 type WorkerConfig struct {
 	Pool string
+	SoftAffinity string
 }
 
 // Propagate unset values from a higher level
diff --git a/xenworker.go b/xenworker.go
index 10817b5..f2f316f 100644
--- a/xenworker.go
+++ b/xenworker.go
@@ -91,6 +91,10 @@ func (w *XenWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
 		fmt.Fprintf(cfg, "pool = '%s'\n", g.Pool)
 	}
 
+	if g.SoftAffinity != "" {
+		fmt.Fprintf(cfg, "cpus_soft = '%s'\n", g.SoftAffinity)
+	}
+
 	
 	// xl create -p [filename]
 	{
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 54/59] controller/run: Add RunConfig.NumaDisable
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (51 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 53/59] controller: Add WorkerConfig.SoftAffinity Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 55/59] plan: Make the matrix generation more programmatic Ronald Rojas
                   ` (4 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

If RunConfig.NumaDisable is set, get each worker's
WorkerConfig.SoftAffinity to the cpumap of the cpupool the VM is going
to be running in.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 benchmark.go |  4 ++++
 run.go       | 35 ++++++++++++++++++++++++++++++++---
 2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/benchmark.go b/benchmark.go
index d5a0ac8..abe2dfb 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -142,6 +142,7 @@ type RunConfig struct {
 	Scheduler string
 	Pool string
 	Cpus []int
+	NumaDisable *bool `json:",omitempty"`
 }
 
 // Propagate unset values from a higher level
@@ -155,6 +156,9 @@ func (l *RunConfig) PropagateFrom(g RunConfig) {
 	if l.Cpus == nil {
 		l.Cpus = g.Cpus
 	}
+	if l.NumaDisable == nil {
+		l.NumaDisable = g.NumaDisable
+	}
 }
 
 type BenchmarkRun struct {
diff --git a/run.go b/run.go
index 2d0db01..d1c5d95 100644
--- a/run.go
+++ b/run.go
@@ -312,14 +312,43 @@ func (run *BenchmarkRun) Prep() (ready bool, why string) {
 	return 
 }
 
+func (run *BenchmarkRun) GetCpumap() (Cpumap Bitmap) {
+	if run.RunConfig.Pool == "" {
+		fmt.Printf("Run.Prep: No pool set, using 0\n")
+		pool := Ctx.CpupoolInfo(0)
+		Cpumap = pool.Cpumap
+	} else {
+		pool, poolPresent := Ctx.CpupoolFindByName(run.RunConfig.Pool)
+		if poolPresent {
+			Cpumap = pool.Cpumap
+		} else {
+			panic("run.GetCpumap(): Pool "+run.RunConfig.Pool+" not found!")
+		}
+	}
+	return
+}
+
 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
+		conf := &run.WorkerSets[wsi].Config
+		
+		conf.PropagateFrom(run.WorkerConfig)
+		if conf.Pool == "" {
+			conf.Pool = run.RunConfig.Pool
 		}
 		run.WorkerSets[wsi].Params.SetkHZ(CpukHZ)
 		
+		if *run.RunConfig.NumaDisable {
+			if conf.SoftAffinity != "" {
+				err = fmt.Errorf("Cannot disable Numa if SoftAffinity is set!")
+				return
+			}
+			// Disable libxl NUMA by setting the soft
+			// affinity to the set of cpus in the cpupool
+		 	conf.SoftAffinity = run.GetCpumap().String()
+			fmt.Printf("Setting SoftAffinity to %s to disable NUMA placement\n",
+				conf.SoftAffinity)
+		}
 	}
 	
 	Workers, err := NewWorkerList(run.WorkerSets, WorkerXen)
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 55/59] plan: Make the matrix generation more programmatic
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (52 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 54/59] controller/run: Add RunConfig.NumaDisable Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 56/59] controller/plan: Add NumaDisable to SimpleMatrix Ronald Rojas
                   ` (3 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Rather than have nested loops, keep a running list of all the configs
we've created so far.  Then for each existing new element of the
matrix, combine it with all the existing columns.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 plan.go | 50 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/plan.go b/plan.go
index e535603..736d9f3 100644
--- a/plan.go
+++ b/plan.go
@@ -72,7 +72,9 @@ func (plan *BenchmarkPlan) ExpandInput() (err error) {
 		schedulers = append(schedulers, "")
 	}
 
-	// Always do the baselines
+	// Start by making a slice with baselines and each of the counts
+	var a, b []BenchmarkRun
+	
 	for _, wn := range plan.Input.SimpleMatrix.Workers {
 		wp := WorkerPresets[wn]
 		
@@ -85,39 +87,49 @@ func (plan *BenchmarkPlan) ExpandInput() (err error) {
 			WorkerSets:[]WorkerSet{{Params:wp, Count:1}},
 			RuntimeSeconds:10,
 		}
-		
-		for _, s := range schedulers {
-			fmt.Printf("Making baseline %s run, sched %s\n", wn, s)
-			run.RunConfig.Scheduler = s
-			run.Label = wn+" baseline "+s
-			plan.Runs = append(plan.Runs, run)
-		}
+
+		run.Label = wn+" baseline"
+		a = append(a, run)
 	}
-		
+
+
 	for _, c := range plan.Input.SimpleMatrix.Count {
 		run := BenchmarkRun{
 			RuntimeSeconds:10,
 		}
 		
-		var label string
 		for _, wn := range plan.Input.SimpleMatrix.Workers {
 			wp := WorkerPresets[wn]
 			
-			if label != "" {
-				label = label+" + "
+			if run.Label != "" {
+				run.Label = run.Label+" + "
 			}
-			label = fmt.Sprintf("%s%s %d ", label, wn, c)
-			
+			run.Label = fmt.Sprintf("%s%s %d", run.Label, wn, c)
+
 			ws := WorkerSet{Params:wp, Count:c}
 			run.WorkerSets = append(run.WorkerSets, ws)
 		}
-		for _, s := range schedulers {
-			fmt.Printf("Making count %d run, sched %s\n", c, s)
-			run.RunConfig.Scheduler = s
-			run.Label = label+s
-			plan.Runs = append(plan.Runs, run)
+
+		a = append(a, run)
+	}
+
+	// ...then cross it by schedulers
+	if len(schedulers) > 0 {
+		for _, base := range a {
+			for _, s := range schedulers {
+				run := base
+				run.RunConfig.Scheduler = s
+				run.Label = run.Label+" "+s
+				b = append(b, run)
+			}
 		}
+		a = b
+		b = nil
 	}
 
+	for i := range a {
+		fmt.Printf("%s\n", a[i].Label)
+	}
+	plan.Runs = a;
 	return
 }
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 56/59] controller/plan: Add NumaDisable to SimpleMatrix
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (53 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 55/59] plan: Make the matrix generation more programmatic Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 57/59] tools/blktap2: remove unused inclusion of sys/sysctl.l Ronald Rojas
                   ` (2 subsequent siblings)
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap

From: George Dunlap <george.dunlap@citrix.com>

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 plan.go | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/plan.go b/plan.go
index 736d9f3..b8e0c6b 100644
--- a/plan.go
+++ b/plan.go
@@ -26,6 +26,7 @@ type PlanSimpleMatrix struct {
 	Schedulers []string
 	Workers []string
 	Count []int
+	NumaDisable []bool
 }
 
 type PlanInput struct {
@@ -127,6 +128,27 @@ func (plan *BenchmarkPlan) ExpandInput() (err error) {
 		b = nil
 	}
 
+	// ...and NumaDisable
+	if len(plan.Input.SimpleMatrix.NumaDisable) > 0 {
+		for _, base := range a {
+			for _, d := range plan.Input.SimpleMatrix.NumaDisable {
+				run := base
+				// Need to make a copy of this so that
+				// we have a pointer to use as a tristate
+				run.RunConfig.NumaDisable = new(bool)
+				*run.RunConfig.NumaDisable = d
+				if d {
+					run.Label = run.Label+" NumaOff"
+				} else {
+					run.Label = run.Label+" NumaOn "
+				}
+				b = append(b, run)
+			}
+		}
+		a = b
+		b = nil
+	}
+
 	for i := range a {
 		fmt.Printf("%s\n", a[i].Label)
 	}
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 57/59] tools/blktap2: remove unused inclusion of sys/sysctl.l
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (54 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 56/59] controller/plan: Add NumaDisable to SimpleMatrix Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 58/59] remove irrelevant files from old repository Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info Ronald Rojas
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap
  Cc: Alistair Francis

From: Alistair Francis <alistair.francis@xilinx.com>

That header file is not used. Removing it would avoid build error with
musl libc, which doesn't have that header file.

Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
Reviewed-by: Doug Goldstein <cardoe@cardoe.com>
[ wei: rewrote commit message ]
Acked-by: Wei Liu <wei.liu2@citrix.com>
---
 tools/blktap2/drivers/block-remus.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tools/blktap2/drivers/block-remus.c b/tools/blktap2/drivers/block-remus.c
index 079588d..7401800 100644
--- a/tools/blktap2/drivers/block-remus.c
+++ b/tools/blktap2/drivers/block-remus.c
@@ -54,7 +54,6 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/param.h>
-#include <sys/sysctl.h>
 #include <unistd.h>
 #include <sys/stat.h>
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 58/59] remove irrelevant files from old repository
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (55 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 57/59] tools/blktap2: remove unused inclusion of sys/sysctl.l Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29  1:14 ` [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info Ronald Rojas
  57 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap
  Cc: Ronald Rojas

Signed-off-by: Ronald Rojas <ronladred@gmail.com>
---
 Makefile                       |  31 --
 benchmark.go                   | 467 --------------------------
 htmlreport.go                  | 238 --------------
 libxl.go                       | 720 -----------------------------------------
 main.go                        | 146 ---------
 plan.go                        | 157 ---------
 processworker.go               |  98 ------
 run.go                         | 456 --------------------------
 stubs.go                       |  34 --
 tools/golang/xenlight/libxl.go | 720 +++++++++++++++++++++++++++++++++++++++++
 xenworker.go                   | 278 ----------------
 11 files changed, 720 insertions(+), 2625 deletions(-)
 delete mode 100644 Makefile
 delete mode 100644 benchmark.go
 delete mode 100644 htmlreport.go
 delete mode 100644 libxl.go
 delete mode 100644 main.go
 delete mode 100644 plan.go
 delete mode 100644 processworker.go
 delete mode 100644 run.go
 delete mode 100644 stubs.go
 create mode 100644 tools/golang/xenlight/libxl.go
 delete mode 100644 xenworker.go

diff --git a/Makefile b/Makefile
deleted file mode 100644
index 699cc53..0000000
--- a/Makefile
+++ /dev/null
@@ -1,31 +0,0 @@
-BIN = schedbench
-BINALL = $(BIN)
-
-.PHONY: all
-all: $(BIN)
-
-
-
-CGO_CFLAGS = -I/build/hg/xen.git/dist/install/usr/local/include
-
-# FIXME
-XENLIB_PATH ?= /build/hg/xen.git/dist/install/usr/local/lib/
-CGO_LDFLAGS = -L$(XENLIB_PATH) -Wl,-rpath-link=$(XENLIB_PATH) 
-
-schedbench: main.go processworker.go xenworker.go benchmark.go run.go libxl.go htmlreport.go plan.go
-	CGO_LDFLAGS="$(CGO_LDFLAGS)" CGO_CFLAGS="$(CGO_CFLAGS)" go build -ldflags '-linkmode external -extldflags "-static"' -o $@ $^
-
-# If we use a statically linked binary we don't need this; the same
-# binary can be used on any system.  Keep this version (without any
-# run support) support) around for now in case we want to go back to
-# it.
-schedbench-report: main.go benchmark.go stubs.go htmlreport.go plan.go
-	go build -o $@ $^
-
-.PHONY: clean
-clean:
-	rm -f $(BINALL)
-
-.PHONY: dist
-dist:
-	cp $(BIN) $(DISTDIR)
diff --git a/benchmark.go b/benchmark.go
deleted file mode 100644
index abe2dfb..0000000
--- a/benchmark.go
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-import (
-	"fmt"
-	"os"
-	"io/ioutil"
-	"encoding/json"
-	"math"
-	"time"
-)
-
-type WorkerId struct {
-	Set int
-	Id int
-}
-
-func (wid WorkerId) String() (string) {
-	return fmt.Sprintf("%d:%d", wid.Set, wid.Id)
-}
-
-type WorkerReport struct {
-	Id WorkerId
-	Now int
-	Kops int
-	MaxDelta int
-	Cputime time.Duration
-}
-
-type WorkerParams struct {
-	Args []string
-}
-
-func (l *WorkerParams) SetkHZ(kHZ uint64) {
-	if l.Args[0] == "kHZ" {
-		l.Args[1] = fmt.Sprintf("%d", kHZ)
-	} else {
-		l.Args = append([]string{"kHZ", fmt.Sprintf("%d", kHZ)}, l.Args...)
-	}
-}
-
-type WorkerConfig struct {
-	Pool string
-	SoftAffinity string
-}
-
-// Propagate unset values from a higher level
-func (l *WorkerConfig) PropagateFrom(g WorkerConfig) {
-	if l.Pool == "" {
-		l.Pool = g.Pool
-	}
-}
-
-type WorkerSet struct {
-	Params WorkerParams
-	Config WorkerConfig
-	Count int
-}
-
-const (
-	USEC = 1000
-	MSEC = USEC * 1000
-	SEC = MSEC * 1000
-)
-
-func Throughput(lt int, lm int, t int, m int) (tput float64) {
-	time := float64(t - lt) / SEC
-	kops := m - lm
-	
-	tput = float64(kops) / time
-	return
-}
-
-func Utilization(lt int, lct time.Duration, t int, ct time.Duration) (util float64) {
-	util = float64(ct - lct) / float64(t - lt)
-	return
-}
-
-type MinMax struct {
-	Min float64
-	Max float64
-}
-
-func (mm *MinMax) Update(x float64) {
-	if x > mm.Max {
-		mm.Max = x
-	}
-	if x < mm.Min || mm.Min == 0 {
-		mm.Min = x
-	}
-}
-
-type WorkerSummary struct {
-	Raw []WorkerReport
-	MinMaxTput MinMax
-	MinMaxUtil MinMax
-	TotalTput int
-	TotalTime time.Duration
-	TotalCputime time.Duration
-	AvgTput float64
-	AvgUtil float64
-}
-
-type WorkerSetSummary struct {
-	Workers    []WorkerSummary
-	TotalTput     float64
-	AvgAvgTput    float64
-	MinMaxTput    MinMax
-	MinMaxAvgTput MinMax
-	AvgStdDevTput float64
-
-	TotalUtil     float64
-	MinMaxUtil    MinMax
-	MinMaxAvgUtil MinMax
-	AvgAvgUtil    float64
-	AvgStdDevUtil float64
-}
-
-type BenchmarkRunData struct {
-	Raw []WorkerReport       `json:",omitempty"`
-	Summary []WorkerSetSummary  `json:",omitempty"`
-}
-
-type RunConfig struct {
-	Scheduler string
-	Pool string
-	Cpus []int
-	NumaDisable *bool `json:",omitempty"`
-}
-
-// 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
-	}
-	if l.NumaDisable == nil {
-		l.NumaDisable = g.NumaDisable
-	}
-}
-
-type BenchmarkRun struct {
-	Label string
-	WorkerSets []WorkerSet
-	WorkerConfig
-	RunConfig
-	RuntimeSeconds int
-	Completed bool
-	Results BenchmarkRunData 
-}
-
-type BenchmarkPlan struct {
-	Input *PlanInput     `json:",omitempty"`
-	filename string      `json:",omitempty"`
-	WorkerType int       `json:",omitempty"`
-	// 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"`
-}
-
-func (run *BenchmarkRun) checkSummary() (done bool, err error) {
-	if run.Results.Summary != nil {
-		done = true
-		return 
-	}
-	
-	return
-}
-
-func (run *BenchmarkRun) Process() (err error) {
-	done, err := run.checkSummary()
-	if done || err != nil {
-		return
-	}
-
-	run.Results.Summary = make([]WorkerSetSummary, len(run.WorkerSets))
-
-	type Data struct{
-		startTime int
-		startCputime time.Duration
-		lastTime int
-		lastKops int
-		lastCputime time.Duration
-	}
-	
-	data := make(map[WorkerId]*Data)
-
-	// FIXME: Filter out results which started before all have started
-	for i := range run.Results.Raw {
-		e := run.Results.Raw[i]
-
-		if e.Id.Set > len(run.Results.Summary) {
-			return fmt.Errorf("Internal error: e.Id.Set %d > len(Results.Summary) %d\n",
-				e.Id.Set, len(run.Results.Summary))
-		}
-		
-		if run.Results.Summary[e.Id.Set].Workers == nil {
-			run.Results.Summary[e.Id.Set].Workers = make([]WorkerSummary,
-				run.WorkerSets[e.Id.Set].Count)
-		}
-
-		ws := &run.Results.Summary[e.Id.Set]
-
-		if e.Id.Id > len(ws.Workers) {
-			return fmt.Errorf("Internal error: e.Id.Id %d > len(Results.Summary[].Workers) %d\n",
-				e.Id.Id, len(ws.Workers))
-		}
-
-		s := &ws.Workers[e.Id.Id]
-
-		s.Raw = append(s.Raw, e)
-		
-		d := data[e.Id]
-		if d == nil {
-			d = &Data{}
-			data[e.Id] = d
-		}
-			
-		if d.startTime == 0 {
-			d.startTime = e.Now
-			d.startCputime = e.Cputime
-		} else {
-			tput := Throughput(d.lastTime, d.lastKops, e.Now, e.Kops)
-			util := Utilization(d.lastTime, d.lastCputime, e.Now, e.Cputime)
-
-			s.MinMaxTput.Update(tput)
-			s.MinMaxUtil.Update(util)
-			ws.MinMaxTput.Update(tput)
-			ws.MinMaxUtil.Update(util)
-		}
-		d.lastTime = e.Now
-		d.lastKops = e.Kops
-		d.lastCputime = e.Cputime
-	}
-
-	for Id, d := range data {
-		ws := &run.Results.Summary[Id.Set]
-		s := &ws.Workers[Id.Id]
-
-		s.TotalTput = d.lastKops
-		s.TotalTime = time.Duration(d.lastTime - d.startTime)
-		s.TotalCputime = d.lastCputime - d.startCputime
-		
-		s.AvgTput = Throughput(d.startTime, 0, d.lastTime, d.lastKops)
-		s.AvgUtil = Utilization(d.startTime, d.startCputime, d.lastTime, d.lastCputime)
-
-		ws.MinMaxAvgTput.Update(s.AvgTput)
-		ws.MinMaxAvgUtil.Update(s.AvgUtil)
-	}
-
-	// Calculate the average-of-averages for each set
-	for set := range run.Results.Summary {
-		ws := &run.Results.Summary[set]
-		
-		var totalTput float64
-		var totalUtil float64
-		var count int
-		for id := range ws.Workers {
-			totalTput += ws.Workers[id].AvgTput
-			totalUtil += ws.Workers[id].AvgUtil
-			count++
-		}
-
-		// FIXME -- Is this legit?
-		ws.TotalTput = totalTput
-		ws.TotalUtil = totalUtil
-		ws.AvgAvgTput = totalTput / float64(count)
-		ws.AvgAvgUtil = totalUtil / float64(count)
-	}
-
-	// Then calculate the standard deviation
-	for set := range run.Results.Summary {
-		ws := &run.Results.Summary[set]
-		
-		var totalAvgTput float64
-		var totalAvgUtil float64
-		var count int
-		
-		for id := range ws.Workers {
-			d1 := ws.Workers[id].AvgTput - ws.AvgAvgTput
-			d2 := ws.Workers[id].AvgUtil - ws.AvgAvgUtil
-			totalAvgTput += d1 * d1
-			totalAvgUtil += d2 * d2
-			count++
-		}
-		v1 := totalAvgTput / float64(count)
-		v2 := totalAvgUtil / float64(count)
-		ws.AvgStdDevTput = math.Sqrt(v1)
-		ws.AvgStdDevUtil = math.Sqrt(v2)
-	}
-
-	return
-}
-
-func (run *BenchmarkRun) TextReport(level int) (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 ==\n", run.Label)
-
-	for set := range run.WorkerSets {
-		ws := &run.WorkerSets[set]
-		params := ""
-		for _, s := range ws.Params.Args {
-			params = fmt.Sprintf("%s %s", params, s)
-		}
-		fmt.Printf("Set %d: %s\n", set, params)
-	}
-
-	fmt.Printf("\n%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s\n", "set", "ttotal", "tavgavg", "tstdev", "tavgmax", "tavgmin", "ttotmax", "ttotmin", "utotal", "uavgavg", "ustdev", "uavgmax", "uavgmin", "utotmax", "utotmin")
-	for set := range run.WorkerSets {
-		ws := &run.Results.Summary[set]
-		fmt.Printf("%8d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n",
-			set,
-			ws.TotalTput, ws.AvgAvgTput, ws.AvgStdDevTput, ws.MinMaxAvgTput.Max,
-			ws.MinMaxAvgTput.Min, ws.MinMaxTput.Max, ws.MinMaxTput.Min,
-			ws.TotalUtil, ws.AvgAvgUtil, ws.AvgStdDevUtil, ws.MinMaxAvgUtil.Max,
-			ws.MinMaxAvgUtil.Min, ws.MinMaxUtil.Max, ws.MinMaxUtil.Min)
-	}
-
-	if level >= 1 {
- 		fmt.Printf("\n%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s\n", "workerid", "toput", "time", "cpu", "tavg", "tmin", "tmax", "uavg", "umin", "umax")
-		for set := range run.Results.Summary {
-			for id := range run.Results.Summary[set].Workers {
-				s := run.Results.Summary[set].Workers[id]
-				fmt.Printf("%2d:%2d    %10d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n",
-					set, id,
-					s.TotalTput, s.TotalTime.Seconds(), s.TotalCputime.Seconds(),
-					s.AvgTput, s.MinMaxTput.Min, s.MinMaxTput.Max,
-					s.AvgUtil, s.MinMaxUtil.Min, s.MinMaxUtil.Max)
-
-				if level >= 2 {
-					var le WorkerReport
-					for _, e := range s.Raw {
-						var dtime float64
-						var dCputime time.Duration
-						var dKops int
-						time := float64(e.Now) / SEC
-						if e.Now > le.Now {
-							dtime = float64(e.Now - le.Now) / SEC
-							dCputime = e.Cputime - le.Cputime
-							dKops = e.Kops - le.Kops
-
-						}
-						fmt.Printf ("   [%8.3f] (%8.3f) %8.3f (%8.3f) %8d (%8d) %12d\n",
-							time, dtime,
-							e.Cputime.Seconds(), dCputime.Seconds(),
-							e.Kops, dKops, e.MaxDelta)
-						le = e
-					}
-				}
-
-			}
-		}
-	}
-
-	fmt.Printf("\n\n")
-
-	return
-}
-
-func LoadBenchmark(filename string) (plan BenchmarkPlan, err error) {
-	plan.filename = filename
-	
-	var b []byte
-	b, err = ioutil.ReadFile(filename)
-	if err != nil {
-		return
-	}
-	
-	err = json.Unmarshal(b, &plan)
-	if err != nil {
-		return
-	}
-
-	return
-}
-
-func (plan *BenchmarkPlan) Save() (err error) {
-	if plan.filename == "" {
-		err = fmt.Errorf("Invalid filename")
-		return
-	}
-	
-	var b []byte
-	b, err = json.Marshal(*plan)
-	if err != nil {
-		return
-	}
-
-	backupFilename := fmt.Sprintf(".%s.tmp", plan.filename)
-	err = os.Rename(plan.filename, backupFilename)
-	if err != nil {
-		if os.IsNotExist(err) {
-			backupFilename = ""
-		} else {
-			return
-		}
-	}
-
-	err = ioutil.WriteFile(plan.filename, b, 0666)
-	if err != nil {
-		if backupFilename != "" {
-			os.Rename(backupFilename, plan.filename)
-		}
-		return
-	}
-
-	if backupFilename != "" {
-		os.Remove(backupFilename)
-	}
-	return
-}
-
-func (plan *BenchmarkPlan) TextReport(level int) (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(level)
-		if err != nil {
-			return
-		}
-	}
-
-	return
-}
-
diff --git a/htmlreport.go b/htmlreport.go
deleted file mode 100644
index 545582d..0000000
--- a/htmlreport.go
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-import (
-	"fmt"
-	"os"
-	"io"
-	"encoding/json"
-)
-
-type OptionAxis struct {
-	Title string `json:"title,omitempty"`
-	// Always include this one so that we can start graphs at 0
-	MinValue float64 `json:"minValue"`
-	MaxValue float64 `json:"maxValue,omitempty"`
-}
-
-type Options struct {
-	Title string     `json:"title,omitempty"`
-	HAxis OptionAxis `json:"hAxis"`
-	VAxis OptionAxis `json:"vAxis"`
-	Legend string    `json:"legend,omitempty"`
-}
-
-type Point struct {
-	x float64
-	y float64
-}
-
-type RunRaw struct {
-	Tag string
-	Title string
-	hTitle string
-	vTitle string
-	Points [][]Point
-}
-
-func (options *Options) OutputJavascript(w io.Writer, tag string) (err error) {
-	var optionsJson []byte
-	optionsJson, err = json.Marshal(options)
-	if err != nil {
-		return
-	}
-
-	fmt.Fprintf(w, "        var %sopt = ", tag)
-	fmt.Fprint(w, string(optionsJson))
-	fmt.Fprintln(w, ";")
-
-	return
-}
-
-func (p *Point) OutputJson(w io.Writer, id int, max int) (err error) {
-	fmt.Fprintf(w, "            [%f", p.x)
-	for i := 0; i < max; i++ {
-		if i == id {
-			fmt.Fprintf(w, ", %f", p.y)
-		} else {
-			fmt.Fprintf(w, ", null")
-		}
-	}
-	fmt.Fprint(w, "],\n")
-	return
-}
-
-func (d *RunRaw) OutputHTML(w io.Writer) (err error) {
-	fmt.Fprintf(w, "    <div class='scatterplot' id='scatterplot%s'></div>\n", d.Tag)
-	return
-}
-
-func (d *RunRaw) OutputJavascript(w io.Writer) (err error) {
-	var options Options
-
-	options.Title = d.Title
-	options.HAxis.Title = d.hTitle
-	options.VAxis.Title = d.vTitle
-
-	err = options.OutputJavascript(w, d.Tag)
-	if err != nil {
-		return
-	}
-
-	fmt.Printf("        var %sdata = new google.visualization.DataTable();\n", d.Tag)
-	fmt.Printf("        %sdata.addColumn('number', 'Time');\n", d.Tag)
-	for i := range d.Points {
-		fmt.Printf("        %sdata.addColumn('number', 'Worker %d');\n", d.Tag, i)
-	}
-	fmt.Printf("        %sdata.addRows([\n", d.Tag)
-
-	// Can't use json here because we need to be able to use 'null' for non-existent values
-	for i := range d.Points {
-		for j := range d.Points[i] {
-			err = d.Points[i][j].OutputJson(w, i, len(d.Points))
-			if err != nil {
-				return
-			}
-		}
-	}
-	fmt.Print("          ]);\n")
-	
-	fmt.Printf("        var %schart = new google.visualization.ScatterChart(document.getElementById('scatterplot%s'));\n", d.Tag, d.Tag);
-	fmt.Printf("        %schart.draw(%sdata, %sopt);\n\n", d.Tag, d.Tag, d.Tag)
-	
-	return
-}
-
-type HTMLReport struct {
-	Raw []RunRaw
-}
-
-
-func (rpt *HTMLReport) Output(w io.Writer) (err error) {
-	// Print start -> json charts
-	fmt.Fprint(w,
-		`<html>
-  <head>
-    <style>
-      .scatterplot {
-      margin:auto;
-      width: 100vw;
-      height: 60vw;
-      }
-
-      .empty {
-      margin: auto;
-      }
-    </style>
-    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
-    <script type="text/javascript">
-      google.charts.load('current', {'packages':['corechart']});
-      google.charts.setOnLoadCallback(drawCharts);
-      function drawCharts() {
-`);
-	// Print json chart code
-	for i := range rpt.Raw {
-		err = rpt.Raw[i].OutputJavascript(w)
-		if err != nil {
-			return
-		}
-	}
-	// Print json -> html
-	fmt.Fprint(w,
-		`      }
-    </script>
-  </head>
-  <body>
-`);
-	// Print html
-	for i := range rpt.Raw {
-		err = rpt.Raw[i].OutputHTML(w)
-		if err != nil {
-			return
-		}
-	}
-	// Print html -> end
-	fmt.Fprint(w,
-		`  </body>
-</html>
-`);
-	return
-}
-
-func (rpt *HTMLReport) AddRun(run *BenchmarkRun) (err error) {
-	var tPut RunRaw
-	var Util RunRaw
-
-	tPut.Title = fmt.Sprintf("Run %s Individual Throughput", run.Label)
-	tPut.hTitle = "Time (s)"
-	tPut.vTitle = "Throughput (kOps)"
-	Util.Title = fmt.Sprintf("Run %s Individual Utilization", run.Label)
-	Util.hTitle = "Time (s)"
-	Util.vTitle = "Utilization"
-	for set := range run.Results.Summary {
-		var idTput []Point
-		var idUtil []Point
-		for id := range run.Results.Summary[set].Workers {
-			var le WorkerReport
-			for _, e := range run.Results.Summary[set].Workers[id].Raw {
-				if e.Kops > 0 {
-					time := float64(e.Now) / SEC
-					tput := Throughput(e.Now, e.Kops, le.Now, le.Kops)
-					util := Utilization(e.Now, e.Cputime, le.Now, le.Cputime)
-					idTput = append(idTput, Point{x:time, y:tput})
-					idUtil = append(idUtil, Point{x:time, y:util})
-				}
-				le = e
-			}
-		}
-		tPut.Points = append(tPut.Points, idTput)
-		Util.Points = append(Util.Points, idUtil)
-	}
-	tPut.Tag = fmt.Sprintf("raw%d", len(rpt.Raw))
-	rpt.Raw = append(rpt.Raw, tPut)
-	Util.Tag = fmt.Sprintf("raw%d", len(rpt.Raw))
-	rpt.Raw = append(rpt.Raw, Util)
-	return
-}
-
-func (plan *BenchmarkPlan) HTMLReport() (err error) {
-	rpt := HTMLReport{}
-
-	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 = rpt.AddRun(r)
-		if err != nil {
-			return
-		}
-	}
-	err = rpt.Output(os.Stdout)
-
-	return
-}
diff --git a/libxl.go b/libxl.go
deleted file mode 100644
index aa5c01c..0000000
--- a/libxl.go
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-/*
-#cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
-#include <stdlib.h>
-#include <libxl.h>
-*/
-import "C"
-
-/*
- * Other flags that may be needed at some point: 
- *  -lnl-route-3 -lnl-3
- *
- * To get back to simple dynamic linking:
-#cgo LDFLAGS: -lxenlight -lyajl
-*/
-
-import (
-	"unsafe"
-	"fmt"
-	"time"
-)
-
-/*
- * Types: Builtins
- */
-
-type Domid uint32
-
-type MemKB uint64
-
-// typedef struct {
-//     uint32_t size;          /* number of bytes in map */
-//     uint8_t *map;
-// } libxl_bitmap;
-
-// Implement the Go bitmap type such that the underlying data can
-// easily be copied in and out.  NB that we still have to do copies
-// both directions, because cgo runtime restrictions forbid passing to
-// a C function a pointer to a Go-allocated structure which contains a
-// pointer.
-type Bitmap struct {
-	bitmap []C.uint8_t
-}
-
-type Context struct {
-	ctx *C.libxl_ctx
-}
-
-type Uuid C.libxl_uuid
-
-/*
- * Types: IDL
- * 
- * FIXME: Generate these automatically from the IDL
- */
-type Dominfo struct {
-	Uuid              Uuid
-	Domid             Domid
-	Running           bool
-	Blocked           bool
-	Paused            bool
-	Shutdown          bool
-	Dying             bool
-	Never_stop        bool
-	
-	Shutdown_reason   int32 // FIXME shutdown_reason enumeration
-	Outstanding_memkb MemKB
-	Current_memkb     MemKB
-	Shared_memkb      MemKB
-	Paged_memkb       MemKB
-	Max_memkb         MemKB
-	Cpu_time          time.Duration
-	Vcpu_max_id       uint32
-	Vcpu_online       uint32
-	Cpupool           uint32
-	Domain_type       int32 //FIXME libxl_domain_type enumeration
-
-}
-
-// # Consistent with values defined in domctl.h
-// # Except unknown which we have made up
-// libxl_scheduler = Enumeration("scheduler", [
-//     (0, "unknown"),
-//     (4, "sedf"),
-//     (5, "credit"),
-//     (6, "credit2"),
-//     (7, "arinc653"),
-//     (8, "rtds"),
-//     ])
-type Scheduler int
-var (
-	SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
-	SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
-	SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
-	SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
-	SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
-	SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
-)
-
-// libxl_cpupoolinfo = Struct("cpupoolinfo", [
-//     ("poolid",      uint32),
-//     ("pool_name",   string),
-//     ("sched",       libxl_scheduler),
-//     ("n_dom",       uint32),
-//     ("cpumap",      libxl_bitmap)
-//     ], dir=DIR_OUT)
-
-type CpupoolInfo struct {
-	Poolid uint32
-	PoolName string
-	Scheduler Scheduler
-	DomainCount int
-	Cpumap Bitmap
-}
-
-/*
- * Context
- */
-var Ctx Context
-
-func (Ctx *Context) IsOpen() bool {
-	return Ctx.ctx != nil
-}
-
-func (Ctx *Context) Open() (err error) {
-	if Ctx.ctx != nil {
-		return
-	}
-	
-	ret := C.libxl_ctx_alloc(unsafe.Pointer(&Ctx.ctx), C.LIBXL_VERSION, 0, nil)
-
-	if ret != 0 {
-		err = fmt.Errorf("Allocating libxl context: %d", ret)
-	}
-	return
-}
-
-func (Ctx *Context) Close() (err error) {
-	ret := C.libxl_ctx_free(unsafe.Pointer(Ctx.ctx))
-	Ctx.ctx = nil
-
-	if ret != 0 {
-		err = fmt.Errorf("Freeing libxl context: %d", ret)
-	}
-	return
-}
-
-func (Ctx *Context) CheckOpen() (err error) {
-	if Ctx.ctx == nil {
-		err = fmt.Errorf("Context not opened")
-	}
-	return
-}
-
-func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	var cdi C.libxl_dominfo
-
-	ret := C.libxl_domain_info(Ctx.ctx, unsafe.Pointer(&cdi), C.uint32_t(Id))
-
-	// FIXME: IsDomainNotPresentError
-	if ret != 0 {
-		err = fmt.Errorf("libxl_domain_info failed: %d", ret)
-		return
-	}
-
-	// We could consider having this boilerplate generated by the
-	// idl, in a function like this:
-	//
-	// di = translateCdomaininfoToGoDomaininfo(cdi)
-	di = &Dominfo{}
-	di.Uuid = Uuid(cdi.uuid)
-	di.Domid = Domid(cdi.domid)
-	di.Running = bool(cdi.running)
-	di.Blocked = bool(cdi.blocked)
-	di.Paused = bool(cdi.paused)
-	di.Shutdown = bool(cdi.shutdown)
-	di.Dying = bool(cdi.dying)
-	di.Never_stop = bool(cdi.never_stop)
-	di.Shutdown_reason = int32(cdi.shutdown_reason)
-	di.Outstanding_memkb = MemKB(cdi.outstanding_memkb)
-	di.Current_memkb = MemKB(cdi.current_memkb)
-	di.Shared_memkb = MemKB(cdi.shared_memkb)
-	di.Paged_memkb = MemKB(cdi.paged_memkb)
-	di.Max_memkb = MemKB(cdi.max_memkb)
-	di.Cpu_time = time.Duration(cdi.cpu_time)
-	di.Vcpu_max_id = uint32(cdi.vcpu_max_id)
-	di.Vcpu_online = uint32(cdi.vcpu_online)
-	di.Cpupool = uint32(cdi.cpupool)
-	di.Domain_type = int32(cdi.domain_type)
-
-	return
-}
-
-func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	ret := C.libxl_domain_unpause(Ctx.ctx, C.uint32_t(Id))
-
-	if ret != 0 {
-		err = fmt.Errorf("libxl_domain_unpause failed: %d", ret)
-	}
-	return
-}
-
-/*
- * Bitmap operations
- */
-
-// Return a Go bitmap which is a copy of the referred C bitmap.
-func bitmapCToGo(cbm C.libxl_bitmap) (gbm Bitmap) {
-	// Alloc a Go slice for the bytes
-	size := int(cbm.size)
-	gbm.bitmap = make([]C.uint8_t, size)
-
-	// Make a slice pointing to the C array
-	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
-
-	// And copy the C array into the Go array
-	copy(gbm.bitmap, mapslice)
-
-	return
-}
-
-// Must be C.libxl_bitmap_dispose'd of afterwards
-func bitmapGotoC(gbm Bitmap) (cbm C.libxl_bitmap) {
-	C.libxl_bitmap_init(&cbm)
-
-	size := len(gbm.bitmap)
-	cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
-	cbm.size = C.uint32_t(size)
-	if cbm._map == nil {
-		panic("C.calloc failed!")
-	}
-
-	// Make a slice pointing to the C array
-	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
-
-	// And copy the Go array into the C array
-	copy(mapslice, gbm.bitmap)
-
-	return
-}
-
-func (bm *Bitmap) Test(bit int) (bool) {
-	ubit := uint(bit)
-	if (bit > bm.Max() || bm.bitmap == nil) {
-		return false
-	}
-	
-	return (bm.bitmap[bit / 8] & (1 << (ubit & 7))) != 0
-}
-
-func (bm *Bitmap) Set(bit int) {
-	ibit := bit / 8;
-	if (ibit + 1 > len(bm.bitmap)) {
-		bm.bitmap = append(bm.bitmap, make([]C.uint8_t, ibit+1-len(bm.bitmap))...)
-	}
-	
-	bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
-}
-
-func (bm *Bitmap) SetRange(start int, end int) {
-	for i := start; i <= end; i++ {
-		bm.Set(i)
-	}
-}
-
-func (bm *Bitmap) Clear(bit int) {
-	ubit := uint(bit)
-	if (bit > bm.Max() || bm.bitmap == nil) {
-		return
-	}
-	
-	bm.bitmap[bit / 8] &= ^(1 << (ubit & 7))
-}
-
-func (bm *Bitmap) ClearRange(start int, end int) {
-	for i := start; i <= end; i++ {
-		bm.Clear(i)
-	}
-}
-
-func (bm *Bitmap) Max() (int) {
-	return len(bm.bitmap) * 8 - 1
-}
-
-func (bm *Bitmap) IsEmpty() (bool) {
-	for i:=0; i<len(bm.bitmap); i++ {
-		if bm.bitmap[i] != 0 {
-			return false
-		}
-	}
-	return true
-}
-
-func (a Bitmap) And(b Bitmap) (c Bitmap) {
-	var max, min int
-	if len(a.bitmap) > len(b.bitmap) {
-		max = len(a.bitmap)
-		min = len(b.bitmap)
-	} else {
-		max = len(b.bitmap)
-		min = len(a.bitmap)
-	}
-	c.bitmap = make([]C.uint8_t, max)
-
-	for i := 0; i < min; i++ {
-		c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
-	}
-	return
-}
-
-func (bm Bitmap) String() (s string) {
-	lastOnline := false
-	crange := false
-	printed := false
-	var i int
-	/// --x-xxxxx-x -> 2,4-8,10
-	/// --x-xxxxxxx -> 2,4-10
-	for i = 0; i <= bm.Max(); i++ {
-		if bm.Test(i) {
-			if !lastOnline {
-				// Switching offline -> online, print this cpu
-				if printed {
-					s += ","
-				}
-				s += fmt.Sprintf("%d", i)
-				printed = true
-			} else if !crange {
-				// last was online, but we're not in a range; print -
-				crange = true
-				s += "-"
-			} else {
-				// last was online, we're in a range,  nothing else to do
-			}
-			lastOnline = true
-		} else {
-			if lastOnline {
-				// Switching online->offline; do we need to end a range?
-				if crange {
-					s += fmt.Sprintf("%d", i-1)
-				}
-			}
-			lastOnline = false
-			crange = false
-		}
-	}
-	if lastOnline {
-		// Switching online->offline; do we need to end a range?
-		if crange {
-			s += fmt.Sprintf("%d", i-1)
-		}
-	}
-
-	return
-}
-
-// const char *libxl_scheduler_to_string(libxl_scheduler p);
-func (s Scheduler) String() (string) {
-	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
-	// No need to free const return value
-
-	return C.GoString(cs)
-}
-
-// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
-func (s *Scheduler) FromString(gstr string) (err error) {
-	cstr := C.CString(gstr)
-	defer C.free(unsafe.Pointer(cstr))
-
-	var cs C.libxl_scheduler
-	ret := C.libxl_scheduler_from_string(cstr, &cs)
-	if ret != 0 {
-		err = fmt.Errorf("libxl_scheduler_from_string: %d\n", ret)
-		return
-	}
-
-	*s = Scheduler(cs)
-	return
-}
-
-func translateCpupoolInfoCToGo(cci C.libxl_cpupoolinfo) (gci CpupoolInfo) {
-	gci.Poolid = uint32(cci.poolid)
-	gci.PoolName = C.GoString(cci.pool_name)
-	gci.Scheduler = Scheduler(cci.sched)
-	gci.DomainCount = int(cci.n_dom)
-	gci.Cpumap = bitmapCToGo(cci.cpumap)
-
-	return
-}
-
-func SchedulerFromString(name string) (s Scheduler, err error) {
-	cname := C.CString(name)
-	defer C.free(unsafe.Pointer(cname))
-
-	var cs C.libxl_scheduler
-
-	ret := C.libxl_scheduler_from_string(cname, &cs)
-	if ret != 0 {
-		err = fmt.Errorf("libxl_scheduler_from_string failed: %d", ret)
-		return
-	}
-
-	s = Scheduler(cs)
-
-	return
-}
-
-// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
-// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
-func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
-	err := Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	var nbPool C.int
-
-	c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
-
-	defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
-
-	if int(nbPool) == 0 {
-		return
-	}
-
-	// Magic
-	cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
-
-	for i := range cpupoolListSlice {
-		info := translateCpupoolInfoCToGo(cpupoolListSlice[i])
-		
-		list = append(list, info)
-	}
-
-	return
-}
-
-// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
-func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo) {
-	err := Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	var c_cpupool C.libxl_cpupoolinfo
-	
-	ret := C.libxl_cpupool_info(Ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_info failed: %d", ret)
-		return
-	}
-	defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
-
-	pool = translateCpupoolInfoCToGo(c_cpupool)
-
-	return
-}
-
-
-
-// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
-//                          libxl_scheduler sched,
-//                          libxl_bitmap cpumap, libxl_uuid *uuid,
-//                          uint32_t *poolid);
-// FIXME: uuid
-// FIXME: Setting poolid
-func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	poolid := C.uint32_t(0)
-	name := C.CString(Name)
-	defer C.free(unsafe.Pointer(name))
-	
-	// For now, just do what xl does, and make a new uuid every time we create the pool
-	var uuid C.libxl_uuid
-	C.libxl_uuid_generate(&uuid)
-
-	cbm := bitmapGotoC(Cpumap)
-	defer C.libxl_bitmap_dispose(&cbm)
-	
-	ret := C.libxl_cpupool_create(Ctx.ctx, name, C.libxl_scheduler(Scheduler),
-		cbm, &uuid, &poolid)
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_create failed: %d", ret)
-		return
-	}
-
-	Poolid = uint32(poolid)
-	
-	return
-}
-
-// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
-func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_destroy failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
-func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_cpuadd failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
-//                                 const libxl_bitmap *cpumap);
-func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	cbm := bitmapGotoC(Cpumap)
-	defer C.libxl_bitmap_dispose(&cbm)
-	
-	ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_cpuadd_cpumap failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
-func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_cpuremove failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
-//                                    const libxl_bitmap *cpumap);
-func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	cbm := bitmapGotoC(Cpumap)
-	defer C.libxl_bitmap_dispose(&cbm)
-	
-	ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_cpuremove_cpumap failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
-// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
-// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
-// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
-
-//
-// Utility functions
-//
-func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
-	plist := Ctx.ListCpupool()
-
-	for i := range plist {
-		if plist[i].PoolName == name {
-			found = true
-			info = plist[i]
-			return
-		}
-	}
-	return
-}
-
-func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
-	plist := Ctx.ListCpupool()
-
-	for i := range plist {
-		var Intersection Bitmap
-		Intersection = Cpumap.And(plist[i].Cpumap)
-		if ! Intersection.IsEmpty() {
-			err = Ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, Intersection)
-			if err != nil {
-				return
-			}
-		}
-	}
-	return
-}
-
-func XlTest(Args []string) {
-	var Cpumap Bitmap
-
-	Cpumap.Set(2)
-	Cpumap.SetRange(4, 8)
-	Cpumap.Set(10)
-
-	fmt.Printf("Cpumap: %v\n", Cpumap)
-
-	Cpumap.Set(9)
-
-	fmt.Printf("Cpumap: %v\n", Cpumap)
-
-	var Ctx Context
-
-	err := Ctx.Open()
-	if err != nil {
-		fmt.Printf("Opening context: %v\n", err)
-		return
-	}
-
-	pool, found := Ctx.CpupoolFindByName("schedbench")
-
-	if found {
-		fmt.Printf("Found schedbench, destroying\n")
-
-		err = Ctx.CpupoolDestroy(pool.Poolid)
-		if err != nil {
-			fmt.Printf("Couldn't destroy pool: %v\n", err)
-			return
-		}
-
-		fmt.Printf("Returning cpus to pool 0 for fun\n")
-		err = Ctx.CpupoolCpuaddCpumap(0, pool.Cpumap)
-		if err != nil {
-			fmt.Printf("Couldn't add cpus to domain 0: %v\n", err)
-			return
-		}
-	}
-
-	Cpumap = Bitmap{}
-
-	Cpumap.SetRange(12, 15)
-
-	fmt.Printf("Freeing cpus\n")
-	err = Ctx.CpupoolMakeFree(Cpumap)
-	if err != nil {
-		fmt.Printf("Couldn't free cpus: %v\n", err)
-		return
-	}
-
-
-	fmt.Printf("Creating new pool\n")
-
-	err, Poolid := Ctx.CpupoolCreate("schedbench", SchedulerCredit, Cpumap)
-	if err != nil {
-		fmt.Printf("Error creating cpupool: %v\n", err)
-	} else {
-		fmt.Printf("Pool id: %d\n", Poolid)
-	}
-
-	pool = Ctx.CpupoolInfo(0)
-	fmt.Printf("Cpupool 0 info: %v\n", pool)
-	
-	Ctx.Close()
-}
diff --git a/main.go b/main.go
deleted file mode 100644
index ead6ab0..0000000
--- a/main.go
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-package main
-
-import (
-	"fmt"
-	"os"
-	"strconv"
-)
-
-func main() {
-	Args := os.Args
-
-	Args = Args[1:]
-	filename := "test.bench"
-	template := ""
-	verbosity := 0
-
-	for len(Args) > 0 {
-		switch(Args[0]) {
-		case "-f":
-			if len(Args) < 2 {
-				fmt.Println("Need arg for -f")
-				os.Exit(1)
-			}
-			filename = Args[1]
-			Args = Args[2:]
-		case "-t":
-			if len(Args) < 2 {
-				fmt.Println("Need arg for -t")
-				os.Exit(1)
-			}
-			template = Args[1]
-			Args = Args[2:]
-		case "-v":
-			if len(Args) < 2 {
-				fmt.Println("Need arg for -v")
-				os.Exit(1)
-			}
-			verbosity, _ = strconv.Atoi(Args[1])
-			Args = Args[2:]
-		case "plan":
-			// Load either the template benchmark or the filename
-			loadfile := filename
-			if template != "" {
-				loadfile = template
-			}
-			plan, err := LoadBenchmark(loadfile)
-			if err != nil {
-				fmt.Printf("Loading benchmark %s: %v\n",
-					loadfile, err)
-				os.Exit(1)
-			}
-
-			if template != "" {
-				plan.filename = filename
-				err = plan.ClearRuns()
-				if err != nil {
-					fmt.Printf("Clearing runs: %v\n",
-						err)
-					os.Exit(1)
-				}
-			}
-			
-			err = plan.ExpandInput()
-			if err != nil {
-				fmt.Printf("Expanding plan: %v\n", err)
-				os.Exit(1)
-			}
-
-			err = plan.Save()
-			if err != nil {
-				fmt.Printf("Saving plan %s: %v\n", filename, err)
-				os.Exit(1)
-			}
-			fmt.Printf("Created plan in %s\n", filename)
-			Args = Args[1:]
-		case "run":
-			plan, err := LoadBenchmark(filename)
-			if err != nil {
-				fmt.Println("Loading benchmark ", filename, " ", err)
-				os.Exit(1)
-			}
-			
-			err = plan.Run()
-			if err != nil {
-				fmt.Println("Running benchmark run:", err)
-				os.Exit(1)
-			}
-			Args = Args[1:]
-			
-		case "report":
-			Args = Args[1:]
-			plan, err := LoadBenchmark(filename)
-			if err != nil {
-				fmt.Println("Loading benchmark ", filename, " ", err)
-				os.Exit(1)
-			}
-			
-			err = plan.TextReport(verbosity)
-			if err != nil {
-				fmt.Println("Running benchmark run:", err)
-				os.Exit(1)
-			}
-		case "htmlreport":
-			plan, err := LoadBenchmark(filename)
-			if err != nil {
-				fmt.Println("Loading benchmark ", filename, " ", err)
-				os.Exit(1)
-			}
-			
-			err = plan.HTMLReport()
-			if err != nil {
-				fmt.Println("Running benchmark run:", err)
-				os.Exit(1)
-			}
-			Args = Args[1:]
-
-		case "xltest":
-			XlTest(Args)
-			Args = nil
-			
-		default:
-			fmt.Println("Unknown argument: ", Args[0])
-			os.Exit(1)
-		}
-	}
-}
-
diff --git a/plan.go b/plan.go
deleted file mode 100644
index b8e0c6b..0000000
--- a/plan.go
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-import (
-	"fmt"
-)
-
-type PlanSimpleMatrix struct {
-	Schedulers []string
-	Workers []string
-	Count []int
-	NumaDisable []bool
-}
-
-type PlanInput struct {
-	WorkerPresets map[string]WorkerParams
-	SimpleMatrix *PlanSimpleMatrix
-}
-
-var WorkerPresets = map[string]WorkerParams{
-	"P001":WorkerParams{[]string{"burnwait", "70", "200000"}},
-}
-
-func (plan *BenchmarkPlan) ClearRuns() (err error) {
-	plan.Runs = nil
-
-	return
-}
-
-func (plan *BenchmarkPlan) ExpandInput() (err error) {
-	if plan.Runs != nil {
-		err = fmt.Errorf("Runs non-empty, not doing anything\n");
-		return
-	}
-
-	if plan.Input == nil {
-		err = fmt.Errorf("Input nil, nothing to do")
-		return
-	}
-	
-	if plan.Input.SimpleMatrix == nil {
-		err = fmt.Errorf("Input.SimpleMatrix nil, nothing to do\n");
-		return
-	}
-
-	for k := range plan.Input.WorkerPresets {
-		WorkerPresets[k] = plan.Input.WorkerPresets[k];
-	}
-
-	// Use named schedulers, or default to "" (which will use the
-	// current one)
-	var schedulers []string
-	if plan.Input.SimpleMatrix.Schedulers != nil {
-		schedulers = plan.Input.SimpleMatrix.Schedulers
-	} else {
-		schedulers = append(schedulers, "")
-	}
-
-	// Start by making a slice with baselines and each of the counts
-	var a, b []BenchmarkRun
-	
-	for _, wn := range plan.Input.SimpleMatrix.Workers {
-		wp := WorkerPresets[wn]
-		
-		if wp.Args == nil {
-			err = fmt.Errorf("Invalid worker preset: %s", wn)
-			return
-		}
-		
-		run := BenchmarkRun{
-			WorkerSets:[]WorkerSet{{Params:wp, Count:1}},
-			RuntimeSeconds:10,
-		}
-
-		run.Label = wn+" baseline"
-		a = append(a, run)
-	}
-
-
-	for _, c := range plan.Input.SimpleMatrix.Count {
-		run := BenchmarkRun{
-			RuntimeSeconds:10,
-		}
-		
-		for _, wn := range plan.Input.SimpleMatrix.Workers {
-			wp := WorkerPresets[wn]
-			
-			if run.Label != "" {
-				run.Label = run.Label+" + "
-			}
-			run.Label = fmt.Sprintf("%s%s %d", run.Label, wn, c)
-
-			ws := WorkerSet{Params:wp, Count:c}
-			run.WorkerSets = append(run.WorkerSets, ws)
-		}
-
-		a = append(a, run)
-	}
-
-	// ...then cross it by schedulers
-	if len(schedulers) > 0 {
-		for _, base := range a {
-			for _, s := range schedulers {
-				run := base
-				run.RunConfig.Scheduler = s
-				run.Label = run.Label+" "+s
-				b = append(b, run)
-			}
-		}
-		a = b
-		b = nil
-	}
-
-	// ...and NumaDisable
-	if len(plan.Input.SimpleMatrix.NumaDisable) > 0 {
-		for _, base := range a {
-			for _, d := range plan.Input.SimpleMatrix.NumaDisable {
-				run := base
-				// Need to make a copy of this so that
-				// we have a pointer to use as a tristate
-				run.RunConfig.NumaDisable = new(bool)
-				*run.RunConfig.NumaDisable = d
-				if d {
-					run.Label = run.Label+" NumaOff"
-				} else {
-					run.Label = run.Label+" NumaOn "
-				}
-				b = append(b, run)
-			}
-		}
-		a = b
-		b = nil
-	}
-
-	for i := range a {
-		fmt.Printf("%s\n", a[i].Label)
-	}
-	plan.Runs = a;
-	return
-}
diff --git a/processworker.go b/processworker.go
deleted file mode 100644
index 8c27f15..0000000
--- a/processworker.go
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-import (
-	"fmt"
-	"os/exec"
-	"encoding/json"
-	"bufio"
-	"io"
-	
-)
-
-type ProcessWorker struct {
-	id WorkerId
-	c *exec.Cmd
-	stdout io.ReadCloser
-	jsonStarted bool
-	Log []string
-}
-
-func (w *ProcessWorker) SetId(i WorkerId) {
-	w.id = i
-}
-
-func (w *ProcessWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
-	w.c = exec.Command("./worker-proc", p.Args...)
-
-	w.stdout, err = w.c.StdoutPipe()
-	if err != nil {
-		fmt.Print("Conneting to stdout: ", err)
-		return
-	}
-
-	return
-}
-
-func (w *ProcessWorker) Shutdown() {
-	w.c.Process.Kill()
-}
-
-func (w *ProcessWorker) DumpLog(f io.Writer) (err error) {
-	b := bufio.NewWriter(f)
-	defer b.Flush()
-	for _, line := range w.Log {
-		_, err = fmt.Println(b, line)
-		if err != nil {
-			return
-		}
-	}
-	return
-}
-
-func (w *ProcessWorker) Process(report chan WorkerReport, done chan WorkerId) {
-	w.c.Start()
-
-	scanner := bufio.NewScanner(w.stdout)
-
-	for scanner.Scan() {
-		s := scanner.Text()
-		
-		//fmt.Println("Got these bytes: ", s);
-		w.Log = append(w.Log, s)
-
-		if w.jsonStarted {
-			var r WorkerReport
-			json.Unmarshal([]byte(s), &r)
-			r.Id = w.id
-			report <- r
-		} else {
-			if s == "START JSON" {
-				//fmt.Println("Got token to start parsing json")
-				w.jsonStarted = true
-			}
-		}
-	}
-
-	done <- w.id
-
-	w.c.Wait()
-}
-
diff --git a/run.go b/run.go
deleted file mode 100644
index d1c5d95..0000000
--- a/run.go
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-import (
-	"fmt"
-	"os"
-	"os/signal"
-	"time"
-	"regexp"
-	"strconv"
-	"bufio"
-	"io"
-)
-
-type WorkerState struct {
-	w Worker
-	LastReport WorkerReport
-}
-
-type Worker interface {
-	SetId(WorkerId)
-	Init(WorkerParams, WorkerConfig) error
-	Shutdown()
-	Process(chan WorkerReport, chan WorkerId)
-	DumpLog(io.Writer) error
-}
-
-func Report(ws *WorkerState, r WorkerReport) {
-	//fmt.Println(r)
-
-	lr := ws.LastReport
-
-	if (lr.Now > 0) {
-		time := float64(r.Now) / SEC
-		dtime := float64(r.Now - lr.Now) / SEC
-		kops := r.Kops - lr.Kops
-
-		tput := Throughput(lr.Now, lr.Kops, r.Now, r.Kops)
-
-		util := Utilization(lr.Now, lr.Cputime, r.Now, r.Cputime)
-		
-		fmt.Printf("%v %8.3f [%8.3f] cpu %8.3f [%8.3f] Kops: %8d [%8d] Tput: %4.2f Util: %4.2f\n",
-			r.Id, time, dtime, r.Cputime.Seconds(), r.Cputime.Seconds() - lr.Cputime.Seconds(),
-			r.Kops, kops, tput, util);
-	}
-
-	ws.LastReport = r
-}
-
-type WorkerList map[WorkerId]*WorkerState
-
-func (ws *WorkerList) Start(report chan WorkerReport, done chan WorkerId) (i int) {
-	i = 0
-	for j := range *ws {
-		go (*ws)[j].w.Process(report, done)
-		i++
-	}
-	return
-}
-
-func (ws *WorkerList) Stop() {
-	for i := range *ws {
-		(*ws)[i].w.Shutdown()
-	}
-}
-
-const (
-	WorkerProcess = iota
-	WorkerXen = iota
-)
-
-func NewWorkerList(WorkerSets []WorkerSet, workerType int) (wl WorkerList, err error) {
-	wl = WorkerList(make(map[WorkerId]*WorkerState))
-
-	for wsi := range WorkerSets {
-		for i := 0; i < WorkerSets[wsi].Count; i = i+1 {
-			Id := WorkerId{Set:wsi,Id:i}
-
-			ws := wl[Id]
-
-			if ws != nil {
-				panic("Duplicate worker for id!")
-			}
-			
-			ws = &WorkerState{}
-			
-			switch workerType {
-			case WorkerProcess:
-				ws.w = &ProcessWorker{}
-			case WorkerXen:
-				ws.w = &XenWorker{}
-			default:
-				err = fmt.Errorf("Unknown type: %d", workerType)
-				return
-			}
-			
-			ws.w.SetId(Id)
-		
-			ws.w.Init(WorkerSets[wsi].Params, WorkerSets[wsi].Config)
-
-			wl[Id] = ws
-		}
-	}
-	return
-}
-
-var CpukHZ uint64
-
-func getCpuHz() (err error) {
-	if CpukHZ == 0 {
-		var cpuinfo *os.File
-		cpuinfo, err = os.Open("/proc/cpuinfo")
-		if err != nil {
-			return
-		}
-		re := regexp.MustCompile("^cpu MHz\\s*: ([0-9.]+)$")
-		scanner := bufio.NewScanner(cpuinfo)
-		for scanner.Scan() {
-			s := scanner.Text()
-			m := re.FindStringSubmatch(s)
-			if m != nil {
-				var MHZ float64
-				MHZ, err = strconv.ParseFloat(m[1], 64)
-				if err != nil {
-					return
-				}
-				CpukHZ = uint64(MHZ*1000)
-				break
-			}
-		}
-		if CpukHZ == 0 {
-			err = fmt.Errorf("Couldn't find cpu MHz")
-			return
-		} else {
-			fmt.Println("CpukHZ: ", CpukHZ)
-			
-		}
-	}
-	return
-}
-
-// 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 {
-				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
-		}
-
-		// 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 
-}
-
-func (run *BenchmarkRun) GetCpumap() (Cpumap Bitmap) {
-	if run.RunConfig.Pool == "" {
-		fmt.Printf("Run.Prep: No pool set, using 0\n")
-		pool := Ctx.CpupoolInfo(0)
-		Cpumap = pool.Cpumap
-	} else {
-		pool, poolPresent := Ctx.CpupoolFindByName(run.RunConfig.Pool)
-		if poolPresent {
-			Cpumap = pool.Cpumap
-		} else {
-			panic("run.GetCpumap(): Pool "+run.RunConfig.Pool+" not found!")
-		}
-	}
-	return
-}
-
-func (run *BenchmarkRun) Run() (err error) {
-	for wsi := range run.WorkerSets {
-		conf := &run.WorkerSets[wsi].Config
-		
-		conf.PropagateFrom(run.WorkerConfig)
-		if conf.Pool == "" {
-			conf.Pool = run.RunConfig.Pool
-		}
-		run.WorkerSets[wsi].Params.SetkHZ(CpukHZ)
-		
-		if *run.RunConfig.NumaDisable {
-			if conf.SoftAffinity != "" {
-				err = fmt.Errorf("Cannot disable Numa if SoftAffinity is set!")
-				return
-			}
-			// Disable libxl NUMA by setting the soft
-			// affinity to the set of cpus in the cpupool
-		 	conf.SoftAffinity = run.GetCpumap().String()
-			fmt.Printf("Setting SoftAffinity to %s to disable NUMA placement\n",
-				conf.SoftAffinity)
-		}
-	}
-	
-	Workers, err := NewWorkerList(run.WorkerSets, WorkerXen)
-	if err != nil {
-		fmt.Println("Error creating workers: %v", err)
-		return
-
-	}
-	
-	report := make(chan WorkerReport)
-	done := make(chan WorkerId)
-	signals := make(chan os.Signal, 1)
-
-	signal.Notify(signals, os.Interrupt)
-	
-	i := Workers.Start(report, done)
-
-	// 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
-	timeout := time.After(time.Duration(run.RuntimeSeconds) * time.Second);
-	stopped := false
-	for i > 0 {
-		select {
-		case r := <-report:
-			if ! stopped {
-				run.Results.Raw = append(run.Results.Raw, r)
-				Report(Workers[r.Id], r)
-			}
-		case did := <-done:
-			if ! stopped {
-				fmt.Println("WARNING: Worker", did, "left early, shutting down workers")
-				Workers.Stop()
-				stopped = true
-				err = fmt.Errorf("Worker %v exited early", did)
-				Workers[did].w.DumpLog(os.Stdout)
-			}
-			i--;
-			fmt.Printf("Worker %v exited; %d workers left\n", did, i);
-		case <-timeout:
-			if ! stopped {
-				Workers.Stop()
-				stopped = true
-				run.Completed = true
-			}
-		case <-signals:
-			if ! stopped {
-				fmt.Println("SIGINT receieved, shutting down workers")
-				Workers.Stop()
-				stopped = true
-				if run.RuntimeSeconds == 0 {
-					run.Completed = true
-				}
-				err = fmt.Errorf("Interrupted")
-			} else {
-				fmt.Println("SIGINT received after stop, exiting without cleaning up")
-				return
-			}
-		}
-	}
-	return
-}
-
-func (plan *BenchmarkPlan) Run() (err error) {
-
-	err = getCpuHz()
-	if err != nil {
-		return
-	}
-
-	if plan.WorkerType == WorkerXen {
-		err = Ctx.Open()
-		if err != nil {
-			return
-		}
-	}
-	
-	for i := range plan.Runs {
-		r := &plan.Runs[i];
-		if ! r.Completed { 
-			r.WorkerConfig.PropagateFrom(plan.WorkerConfig)
-			r.RunConfig.PropagateFrom(plan.RunConfig)
-			ready, why := r.Prep()
-			if ready {
-				fmt.Printf("Running test [%d] %s\n", i, r.Label)
-				err = r.Run()
-				if err != nil {
-					return
-				}
-			} else {
-				fmt.Printf("Test [%d]: %s skipped (%s)\n", i, r.Label, why)
-			}
-		}
-		if r.Completed {
-			fmt.Printf("Test [%d] %s completed\n", i, r.Label)
-			err = plan.Save()
-			if err != nil {
-				fmt.Println("Error saving: ", err)
-				return
-			}
-		}
-	}
-	return
-}
-
diff --git a/stubs.go b/stubs.go
deleted file mode 100644
index 78987ad..0000000
--- a/stubs.go
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-import (
-	"fmt"
-)
-
-func (plan *BenchmarkPlan) Run() (err error) {
-	err = fmt.Errorf("Not implemented")
-
-	return
-}
-
-func XlTest(Args []string) {
-	return
-}
-
diff --git a/tools/golang/xenlight/libxl.go b/tools/golang/xenlight/libxl.go
new file mode 100644
index 0000000..aa5c01c
--- /dev/null
+++ b/tools/golang/xenlight/libxl.go
@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+package main
+
+/*
+#cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
+#include <stdlib.h>
+#include <libxl.h>
+*/
+import "C"
+
+/*
+ * Other flags that may be needed at some point: 
+ *  -lnl-route-3 -lnl-3
+ *
+ * To get back to simple dynamic linking:
+#cgo LDFLAGS: -lxenlight -lyajl
+*/
+
+import (
+	"unsafe"
+	"fmt"
+	"time"
+)
+
+/*
+ * Types: Builtins
+ */
+
+type Domid uint32
+
+type MemKB uint64
+
+// typedef struct {
+//     uint32_t size;          /* number of bytes in map */
+//     uint8_t *map;
+// } libxl_bitmap;
+
+// Implement the Go bitmap type such that the underlying data can
+// easily be copied in and out.  NB that we still have to do copies
+// both directions, because cgo runtime restrictions forbid passing to
+// a C function a pointer to a Go-allocated structure which contains a
+// pointer.
+type Bitmap struct {
+	bitmap []C.uint8_t
+}
+
+type Context struct {
+	ctx *C.libxl_ctx
+}
+
+type Uuid C.libxl_uuid
+
+/*
+ * Types: IDL
+ * 
+ * FIXME: Generate these automatically from the IDL
+ */
+type Dominfo struct {
+	Uuid              Uuid
+	Domid             Domid
+	Running           bool
+	Blocked           bool
+	Paused            bool
+	Shutdown          bool
+	Dying             bool
+	Never_stop        bool
+	
+	Shutdown_reason   int32 // FIXME shutdown_reason enumeration
+	Outstanding_memkb MemKB
+	Current_memkb     MemKB
+	Shared_memkb      MemKB
+	Paged_memkb       MemKB
+	Max_memkb         MemKB
+	Cpu_time          time.Duration
+	Vcpu_max_id       uint32
+	Vcpu_online       uint32
+	Cpupool           uint32
+	Domain_type       int32 //FIXME libxl_domain_type enumeration
+
+}
+
+// # Consistent with values defined in domctl.h
+// # Except unknown which we have made up
+// libxl_scheduler = Enumeration("scheduler", [
+//     (0, "unknown"),
+//     (4, "sedf"),
+//     (5, "credit"),
+//     (6, "credit2"),
+//     (7, "arinc653"),
+//     (8, "rtds"),
+//     ])
+type Scheduler int
+var (
+	SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
+	SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
+	SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
+	SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
+	SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
+	SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
+)
+
+// libxl_cpupoolinfo = Struct("cpupoolinfo", [
+//     ("poolid",      uint32),
+//     ("pool_name",   string),
+//     ("sched",       libxl_scheduler),
+//     ("n_dom",       uint32),
+//     ("cpumap",      libxl_bitmap)
+//     ], dir=DIR_OUT)
+
+type CpupoolInfo struct {
+	Poolid uint32
+	PoolName string
+	Scheduler Scheduler
+	DomainCount int
+	Cpumap Bitmap
+}
+
+/*
+ * Context
+ */
+var Ctx Context
+
+func (Ctx *Context) IsOpen() bool {
+	return Ctx.ctx != nil
+}
+
+func (Ctx *Context) Open() (err error) {
+	if Ctx.ctx != nil {
+		return
+	}
+	
+	ret := C.libxl_ctx_alloc(unsafe.Pointer(&Ctx.ctx), C.LIBXL_VERSION, 0, nil)
+
+	if ret != 0 {
+		err = fmt.Errorf("Allocating libxl context: %d", ret)
+	}
+	return
+}
+
+func (Ctx *Context) Close() (err error) {
+	ret := C.libxl_ctx_free(unsafe.Pointer(Ctx.ctx))
+	Ctx.ctx = nil
+
+	if ret != 0 {
+		err = fmt.Errorf("Freeing libxl context: %d", ret)
+	}
+	return
+}
+
+func (Ctx *Context) CheckOpen() (err error) {
+	if Ctx.ctx == nil {
+		err = fmt.Errorf("Context not opened")
+	}
+	return
+}
+
+func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var cdi C.libxl_dominfo
+
+	ret := C.libxl_domain_info(Ctx.ctx, unsafe.Pointer(&cdi), C.uint32_t(Id))
+
+	// FIXME: IsDomainNotPresentError
+	if ret != 0 {
+		err = fmt.Errorf("libxl_domain_info failed: %d", ret)
+		return
+	}
+
+	// We could consider having this boilerplate generated by the
+	// idl, in a function like this:
+	//
+	// di = translateCdomaininfoToGoDomaininfo(cdi)
+	di = &Dominfo{}
+	di.Uuid = Uuid(cdi.uuid)
+	di.Domid = Domid(cdi.domid)
+	di.Running = bool(cdi.running)
+	di.Blocked = bool(cdi.blocked)
+	di.Paused = bool(cdi.paused)
+	di.Shutdown = bool(cdi.shutdown)
+	di.Dying = bool(cdi.dying)
+	di.Never_stop = bool(cdi.never_stop)
+	di.Shutdown_reason = int32(cdi.shutdown_reason)
+	di.Outstanding_memkb = MemKB(cdi.outstanding_memkb)
+	di.Current_memkb = MemKB(cdi.current_memkb)
+	di.Shared_memkb = MemKB(cdi.shared_memkb)
+	di.Paged_memkb = MemKB(cdi.paged_memkb)
+	di.Max_memkb = MemKB(cdi.max_memkb)
+	di.Cpu_time = time.Duration(cdi.cpu_time)
+	di.Vcpu_max_id = uint32(cdi.vcpu_max_id)
+	di.Vcpu_online = uint32(cdi.vcpu_online)
+	di.Cpupool = uint32(cdi.cpupool)
+	di.Domain_type = int32(cdi.domain_type)
+
+	return
+}
+
+func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_domain_unpause(Ctx.ctx, C.uint32_t(Id))
+
+	if ret != 0 {
+		err = fmt.Errorf("libxl_domain_unpause failed: %d", ret)
+	}
+	return
+}
+
+/*
+ * Bitmap operations
+ */
+
+// Return a Go bitmap which is a copy of the referred C bitmap.
+func bitmapCToGo(cbm C.libxl_bitmap) (gbm Bitmap) {
+	// Alloc a Go slice for the bytes
+	size := int(cbm.size)
+	gbm.bitmap = make([]C.uint8_t, size)
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+	// And copy the C array into the Go array
+	copy(gbm.bitmap, mapslice)
+
+	return
+}
+
+// Must be C.libxl_bitmap_dispose'd of afterwards
+func bitmapGotoC(gbm Bitmap) (cbm C.libxl_bitmap) {
+	C.libxl_bitmap_init(&cbm)
+
+	size := len(gbm.bitmap)
+	cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
+	cbm.size = C.uint32_t(size)
+	if cbm._map == nil {
+		panic("C.calloc failed!")
+	}
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+	// And copy the Go array into the C array
+	copy(mapslice, gbm.bitmap)
+
+	return
+}
+
+func (bm *Bitmap) Test(bit int) (bool) {
+	ubit := uint(bit)
+	if (bit > bm.Max() || bm.bitmap == nil) {
+		return false
+	}
+	
+	return (bm.bitmap[bit / 8] & (1 << (ubit & 7))) != 0
+}
+
+func (bm *Bitmap) Set(bit int) {
+	ibit := bit / 8;
+	if (ibit + 1 > len(bm.bitmap)) {
+		bm.bitmap = append(bm.bitmap, make([]C.uint8_t, ibit+1-len(bm.bitmap))...)
+	}
+	
+	bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
+}
+
+func (bm *Bitmap) SetRange(start int, end int) {
+	for i := start; i <= end; i++ {
+		bm.Set(i)
+	}
+}
+
+func (bm *Bitmap) Clear(bit int) {
+	ubit := uint(bit)
+	if (bit > bm.Max() || bm.bitmap == nil) {
+		return
+	}
+	
+	bm.bitmap[bit / 8] &= ^(1 << (ubit & 7))
+}
+
+func (bm *Bitmap) ClearRange(start int, end int) {
+	for i := start; i <= end; i++ {
+		bm.Clear(i)
+	}
+}
+
+func (bm *Bitmap) Max() (int) {
+	return len(bm.bitmap) * 8 - 1
+}
+
+func (bm *Bitmap) IsEmpty() (bool) {
+	for i:=0; i<len(bm.bitmap); i++ {
+		if bm.bitmap[i] != 0 {
+			return false
+		}
+	}
+	return true
+}
+
+func (a Bitmap) And(b Bitmap) (c Bitmap) {
+	var max, min int
+	if len(a.bitmap) > len(b.bitmap) {
+		max = len(a.bitmap)
+		min = len(b.bitmap)
+	} else {
+		max = len(b.bitmap)
+		min = len(a.bitmap)
+	}
+	c.bitmap = make([]C.uint8_t, max)
+
+	for i := 0; i < min; i++ {
+		c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
+	}
+	return
+}
+
+func (bm Bitmap) String() (s string) {
+	lastOnline := false
+	crange := false
+	printed := false
+	var i int
+	/// --x-xxxxx-x -> 2,4-8,10
+	/// --x-xxxxxxx -> 2,4-10
+	for i = 0; i <= bm.Max(); i++ {
+		if bm.Test(i) {
+			if !lastOnline {
+				// Switching offline -> online, print this cpu
+				if printed {
+					s += ","
+				}
+				s += fmt.Sprintf("%d", i)
+				printed = true
+			} else if !crange {
+				// last was online, but we're not in a range; print -
+				crange = true
+				s += "-"
+			} else {
+				// last was online, we're in a range,  nothing else to do
+			}
+			lastOnline = true
+		} else {
+			if lastOnline {
+				// Switching online->offline; do we need to end a range?
+				if crange {
+					s += fmt.Sprintf("%d", i-1)
+				}
+			}
+			lastOnline = false
+			crange = false
+		}
+	}
+	if lastOnline {
+		// Switching online->offline; do we need to end a range?
+		if crange {
+			s += fmt.Sprintf("%d", i-1)
+		}
+	}
+
+	return
+}
+
+// const char *libxl_scheduler_to_string(libxl_scheduler p);
+func (s Scheduler) String() (string) {
+	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
+	// No need to free const return value
+
+	return C.GoString(cs)
+}
+
+// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
+func (s *Scheduler) FromString(gstr string) (err error) {
+	cstr := C.CString(gstr)
+	defer C.free(unsafe.Pointer(cstr))
+
+	var cs C.libxl_scheduler
+	ret := C.libxl_scheduler_from_string(cstr, &cs)
+	if ret != 0 {
+		err = fmt.Errorf("libxl_scheduler_from_string: %d\n", ret)
+		return
+	}
+
+	*s = Scheduler(cs)
+	return
+}
+
+func translateCpupoolInfoCToGo(cci C.libxl_cpupoolinfo) (gci CpupoolInfo) {
+	gci.Poolid = uint32(cci.poolid)
+	gci.PoolName = C.GoString(cci.pool_name)
+	gci.Scheduler = Scheduler(cci.sched)
+	gci.DomainCount = int(cci.n_dom)
+	gci.Cpumap = bitmapCToGo(cci.cpumap)
+
+	return
+}
+
+func SchedulerFromString(name string) (s Scheduler, err error) {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+
+	var cs C.libxl_scheduler
+
+	ret := C.libxl_scheduler_from_string(cname, &cs)
+	if ret != 0 {
+		err = fmt.Errorf("libxl_scheduler_from_string failed: %d", ret)
+		return
+	}
+
+	s = Scheduler(cs)
+
+	return
+}
+
+// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
+// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
+func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
+	err := Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var nbPool C.int
+
+	c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
+
+	defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
+
+	if int(nbPool) == 0 {
+		return
+	}
+
+	// Magic
+	cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
+
+	for i := range cpupoolListSlice {
+		info := translateCpupoolInfoCToGo(cpupoolListSlice[i])
+		
+		list = append(list, info)
+	}
+
+	return
+}
+
+// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
+func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo) {
+	err := Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var c_cpupool C.libxl_cpupoolinfo
+	
+	ret := C.libxl_cpupool_info(Ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_info failed: %d", ret)
+		return
+	}
+	defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
+
+	pool = translateCpupoolInfoCToGo(c_cpupool)
+
+	return
+}
+
+
+
+// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
+//                          libxl_scheduler sched,
+//                          libxl_bitmap cpumap, libxl_uuid *uuid,
+//                          uint32_t *poolid);
+// FIXME: uuid
+// FIXME: Setting poolid
+func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	poolid := C.uint32_t(0)
+	name := C.CString(Name)
+	defer C.free(unsafe.Pointer(name))
+	
+	// For now, just do what xl does, and make a new uuid every time we create the pool
+	var uuid C.libxl_uuid
+	C.libxl_uuid_generate(&uuid)
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+	
+	ret := C.libxl_cpupool_create(Ctx.ctx, name, C.libxl_scheduler(Scheduler),
+		cbm, &uuid, &poolid)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_create failed: %d", ret)
+		return
+	}
+
+	Poolid = uint32(poolid)
+	
+	return
+}
+
+// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
+func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_destroy failed: %d", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
+func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_cpuadd failed: %d", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                 const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+	
+	ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_cpuadd_cpumap failed: %d", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
+func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_cpuremove failed: %d", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                    const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+	
+	ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = fmt.Errorf("libxl_cpupool_cpuremove_cpumap failed: %d", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
+// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
+
+//
+// Utility functions
+//
+func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		if plist[i].PoolName == name {
+			found = true
+			info = plist[i]
+			return
+		}
+	}
+	return
+}
+
+func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		var Intersection Bitmap
+		Intersection = Cpumap.And(plist[i].Cpumap)
+		if ! Intersection.IsEmpty() {
+			err = Ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, Intersection)
+			if err != nil {
+				return
+			}
+		}
+	}
+	return
+}
+
+func XlTest(Args []string) {
+	var Cpumap Bitmap
+
+	Cpumap.Set(2)
+	Cpumap.SetRange(4, 8)
+	Cpumap.Set(10)
+
+	fmt.Printf("Cpumap: %v\n", Cpumap)
+
+	Cpumap.Set(9)
+
+	fmt.Printf("Cpumap: %v\n", Cpumap)
+
+	var Ctx Context
+
+	err := Ctx.Open()
+	if err != nil {
+		fmt.Printf("Opening context: %v\n", err)
+		return
+	}
+
+	pool, found := Ctx.CpupoolFindByName("schedbench")
+
+	if found {
+		fmt.Printf("Found schedbench, destroying\n")
+
+		err = Ctx.CpupoolDestroy(pool.Poolid)
+		if err != nil {
+			fmt.Printf("Couldn't destroy pool: %v\n", err)
+			return
+		}
+
+		fmt.Printf("Returning cpus to pool 0 for fun\n")
+		err = Ctx.CpupoolCpuaddCpumap(0, pool.Cpumap)
+		if err != nil {
+			fmt.Printf("Couldn't add cpus to domain 0: %v\n", err)
+			return
+		}
+	}
+
+	Cpumap = Bitmap{}
+
+	Cpumap.SetRange(12, 15)
+
+	fmt.Printf("Freeing cpus\n")
+	err = Ctx.CpupoolMakeFree(Cpumap)
+	if err != nil {
+		fmt.Printf("Couldn't free cpus: %v\n", err)
+		return
+	}
+
+
+	fmt.Printf("Creating new pool\n")
+
+	err, Poolid := Ctx.CpupoolCreate("schedbench", SchedulerCredit, Cpumap)
+	if err != nil {
+		fmt.Printf("Error creating cpupool: %v\n", err)
+	} else {
+		fmt.Printf("Pool id: %d\n", Poolid)
+	}
+
+	pool = Ctx.CpupoolInfo(0)
+	fmt.Printf("Cpupool 0 info: %v\n", pool)
+	
+	Ctx.Close()
+}
diff --git a/xenworker.go b/xenworker.go
deleted file mode 100644
index f2f316f..0000000
--- a/xenworker.go
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-	"encoding/json"
-	"bufio"
-	"io"
-)
-
-type XenWorker struct {
-	id WorkerId
-	Ctx Context
-	vmname string
-	domid int
-	consoleCmd *exec.Cmd
-	console io.ReadCloser
-	jsonStarted bool
-	Log []string
-}
-
-// We have to capitalize the element names so that the json class can
-// get access to it; so annotate the elements so they come out lower
-// case
-type RumpRunConfigBlk struct {
-	Source string     `json:"source"`
-	Path string       `json:"path"`
-	Fstype string     `json:"fstype"` 
-	Mountpoint string `json:"mountpoint"`
-}
-
-type RumpRunConfig struct {
-	Blk RumpRunConfigBlk `json:"blk"`
-	Cmdline string       `json:"cmdline"`
-	Hostname string      `json:"hostname"`
-}
-
-func (w *XenWorker) SetId(i WorkerId) {
-	w.id = i
-	w.vmname = fmt.Sprintf("worker-%v", i)
-	w.domid = -1 // INVALID DOMID
-}
-
-func (w *XenWorker) Init(p WorkerParams, g WorkerConfig) (err error) {
-	if err != nil {
-		return
-	}
-	
-	mock := false
-	
-	// Make xl config file
-	//  name=worker-$(id)
-
-	cfgName := os.TempDir()+"/schedbench-"+w.vmname+".cfg"
-
-	cfg, err := os.Create(cfgName)
-	//defer os.Remove(cfgName)
-
-	if err != nil {
-		fmt.Printf("Error creating configfile %s: %v\n", cfgName, err)
-		return
-	}
-
-	fmt.Fprintf(cfg, "name = '%s'\n", w.vmname)
-	fmt.Fprintf(cfg, "kernel = 'worker-xen.img'\n")
-	fmt.Fprintf(cfg, "memory = 32\n")
-	fmt.Fprintf(cfg, "vcpus = 1\n")
-	fmt.Fprintf(cfg, "on_crash = 'destroy'\n")
-	fmt.Fprintf(cfg, "tsc_mode = 'native'\n")
-
-	if g.Pool != "" {
-		fmt.Fprintf(cfg, "pool = '%s'\n", g.Pool)
-	}
-
-	if g.SoftAffinity != "" {
-		fmt.Fprintf(cfg, "cpus_soft = '%s'\n", g.SoftAffinity)
-	}
-
-	
-	// xl create -p [filename]
-	{
-		args := []string{"xl", "create", "-p", cfgName}
-		if mock {
-			args = append([]string{"echo"}, args...)
-		}
-		e := exec.Command(args[0], args[1:]...)
-		
-		e.Stdout = os.Stdout
-		e.Stderr = os.Stderr
-
-		err = e.Run()
-		if err != nil {
-			fmt.Printf("Error creating domain: %v\n", err)
-			return
-		}
-	}
-
-	// Get domid
-	{
-		var domidString []byte
-		var args []string
-		
-		if mock {
-			args = []string{"echo", "232"}
-		} else {
-			args = []string{"xl", "domid", w.vmname}
-		}
-		e := exec.Command(args[0], args[1:]...)
-
-		domidString, err = e.Output()
-		if err != nil {
-			fmt.Printf("Error getting domid: %v\n", err)
-			return
-		}
-
-		_, err = fmt.Sscanf(string(domidString), "%d\n", &w.domid)
-		if err != nil {
-			fmt.Printf("Error converting domid: %v\n", err)
-			return
-		}
-
-		//fmt.Printf(" %s domid %d\n", w.vmname, w.domid)
-	}
-	
-	// Set xenstore config
-	{
-		rcfg := RumpRunConfig{
-			Blk:RumpRunConfigBlk{Source:"dev",
-				Path:"virtual",
-				Fstype:"kernfs",
-				Mountpoint:"/kern"},
-			Hostname:w.vmname}
-		
-		rcfg.Cmdline = "worker-xen.img"
-		for _, a := range p.Args {
-			rcfg.Cmdline += fmt.Sprintf(" %s", a)
-		}
-
-		var rcfgBytes []byte
-	
-		rcfgBytes, err = json.Marshal(rcfg)
-		if err != nil {
-			fmt.Printf("Error marshalling rumprun json: %v\n", err)
-			return
-		}
-
-		//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)
-		
-		args := []string{"xenstore-write", rcfgPath, string(rcfgBytes)}
-		if mock {
-			args = append([]string{"echo"}, args...)
-		}
-		e := exec.Command(args[0], args[1:]...)
-		
-		e.Stdout = os.Stdout
-		e.Stderr = os.Stderr
-
-		err = e.Run()
-		if err != nil {
-			fmt.Printf("Error writing json into xenstore: %v\n", err)
-			return
-		}
-	}
-	
-
-	// Run console command, attach to w.console
-	{
-		args := []string{"xl", "console", w.vmname}
-		if mock {
-			args = append([]string{"echo"}, args...)
-		}
-		w.consoleCmd = exec.Command(args[0], args[1:]...)
-
-		w.console, err = w.consoleCmd.StdoutPipe()
-		if err != nil {
-			fmt.Print("Conneting to stdout: ", err)
-			return
-		}
-
-		w.consoleCmd.Start()
-	}
-	
-	return
-}
-
-// FIXME: Return an error
-func (w *XenWorker) Shutdown() {
-	// xl destroy [vmname]
-	e := exec.Command("xl", "destroy", w.vmname)
-
-	e.Stdout = os.Stdout
-	e.Stderr = os.Stderr
-
-	err := e.Run()
-	if err != nil {
-		fmt.Printf("Error destroying domain: %v\n", err)
-		return
-	}
-}
-
-func (w *XenWorker) DumpLog(f io.Writer) (err error) {
-	b := bufio.NewWriter(f)
-	defer b.Flush()
-	for _, line := range w.Log {
-		_, err = fmt.Fprintln(b, line)
-		if err != nil {
-			return
-		}
-	}
-	return
-}
-
-
-
-// FIXME: Return an error
-func (w *XenWorker) Process(report chan WorkerReport, done chan WorkerId) {
-	// // xl unpause [vmname]
-	//err := xg.Ctx.DomainUnpause(Domid(w.domid))
-	err := Ctx.DomainUnpause(Domid(w.domid))
-	if err != nil {
-		fmt.Printf("Error unpausing domain: %v\n", err)
-		return
-	}
-
-	scanner := bufio.NewScanner(w.console)
-
-	for scanner.Scan() {
-		s := scanner.Text()
-
-		w.Log = append(w.Log, s)
-		
-		//fmt.Println("Got these bytes: ", s);
-
-		if w.jsonStarted {
-			var r WorkerReport
-			json.Unmarshal([]byte(s), &r)
-			r.Id = w.id
-			di, err := Ctx.DomainInfo(Domid(w.domid))
-			// Ignore errors for now
-			if err == nil {
-				r.Cputime = di.Cpu_time
-			}
-			report <- r
-		} else {
-			if s == "START JSON" {
-				//fmt.Println("Got token to start parsing json")
-				w.jsonStarted = true
-			}
-		}
-	}
-
-	done <- w.id
-
-	w.consoleCmd.Wait()
-}
-
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info
  2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
                   ` (56 preceding siblings ...)
  2016-12-29  1:14 ` [PATCH RFC 58/59] remove irrelevant files from old repository Ronald Rojas
@ 2016-12-29  1:14 ` Ronald Rojas
  2016-12-29 10:34   ` George Dunlap
  2016-12-29 13:45   ` George Dunlap
  57 siblings, 2 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29  1:14 UTC (permalink / raw)
  To: xen-devel, Ian Jackson, Wei Liu, George Dunlap, George Dunlap
  Cc: Ronald Rojas

Create interface to interact with libxl_verions_info
and libxl_physinfo. Also introduce proper error
handling.

Signed-off-by: Ronald Rojas <ronladred@gmail.com>
---
 tools/golang/xenlight/libxl.go    |  720 --------------------------
 tools/golang/xenlight/xenlight.go | 1000 +++++++++++++++++++++++++++++++++++++
 2 files changed, 1000 insertions(+), 720 deletions(-)
 delete mode 100644 tools/golang/xenlight/libxl.go
 create mode 100644 tools/golang/xenlight/xenlight.go

diff --git a/tools/golang/xenlight/libxl.go b/tools/golang/xenlight/libxl.go
deleted file mode 100644
index aa5c01c..0000000
--- a/tools/golang/xenlight/libxl.go
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License only.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-package main
-
-/*
-#cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
-#include <stdlib.h>
-#include <libxl.h>
-*/
-import "C"
-
-/*
- * Other flags that may be needed at some point: 
- *  -lnl-route-3 -lnl-3
- *
- * To get back to simple dynamic linking:
-#cgo LDFLAGS: -lxenlight -lyajl
-*/
-
-import (
-	"unsafe"
-	"fmt"
-	"time"
-)
-
-/*
- * Types: Builtins
- */
-
-type Domid uint32
-
-type MemKB uint64
-
-// typedef struct {
-//     uint32_t size;          /* number of bytes in map */
-//     uint8_t *map;
-// } libxl_bitmap;
-
-// Implement the Go bitmap type such that the underlying data can
-// easily be copied in and out.  NB that we still have to do copies
-// both directions, because cgo runtime restrictions forbid passing to
-// a C function a pointer to a Go-allocated structure which contains a
-// pointer.
-type Bitmap struct {
-	bitmap []C.uint8_t
-}
-
-type Context struct {
-	ctx *C.libxl_ctx
-}
-
-type Uuid C.libxl_uuid
-
-/*
- * Types: IDL
- * 
- * FIXME: Generate these automatically from the IDL
- */
-type Dominfo struct {
-	Uuid              Uuid
-	Domid             Domid
-	Running           bool
-	Blocked           bool
-	Paused            bool
-	Shutdown          bool
-	Dying             bool
-	Never_stop        bool
-	
-	Shutdown_reason   int32 // FIXME shutdown_reason enumeration
-	Outstanding_memkb MemKB
-	Current_memkb     MemKB
-	Shared_memkb      MemKB
-	Paged_memkb       MemKB
-	Max_memkb         MemKB
-	Cpu_time          time.Duration
-	Vcpu_max_id       uint32
-	Vcpu_online       uint32
-	Cpupool           uint32
-	Domain_type       int32 //FIXME libxl_domain_type enumeration
-
-}
-
-// # Consistent with values defined in domctl.h
-// # Except unknown which we have made up
-// libxl_scheduler = Enumeration("scheduler", [
-//     (0, "unknown"),
-//     (4, "sedf"),
-//     (5, "credit"),
-//     (6, "credit2"),
-//     (7, "arinc653"),
-//     (8, "rtds"),
-//     ])
-type Scheduler int
-var (
-	SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
-	SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
-	SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
-	SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
-	SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
-	SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
-)
-
-// libxl_cpupoolinfo = Struct("cpupoolinfo", [
-//     ("poolid",      uint32),
-//     ("pool_name",   string),
-//     ("sched",       libxl_scheduler),
-//     ("n_dom",       uint32),
-//     ("cpumap",      libxl_bitmap)
-//     ], dir=DIR_OUT)
-
-type CpupoolInfo struct {
-	Poolid uint32
-	PoolName string
-	Scheduler Scheduler
-	DomainCount int
-	Cpumap Bitmap
-}
-
-/*
- * Context
- */
-var Ctx Context
-
-func (Ctx *Context) IsOpen() bool {
-	return Ctx.ctx != nil
-}
-
-func (Ctx *Context) Open() (err error) {
-	if Ctx.ctx != nil {
-		return
-	}
-	
-	ret := C.libxl_ctx_alloc(unsafe.Pointer(&Ctx.ctx), C.LIBXL_VERSION, 0, nil)
-
-	if ret != 0 {
-		err = fmt.Errorf("Allocating libxl context: %d", ret)
-	}
-	return
-}
-
-func (Ctx *Context) Close() (err error) {
-	ret := C.libxl_ctx_free(unsafe.Pointer(Ctx.ctx))
-	Ctx.ctx = nil
-
-	if ret != 0 {
-		err = fmt.Errorf("Freeing libxl context: %d", ret)
-	}
-	return
-}
-
-func (Ctx *Context) CheckOpen() (err error) {
-	if Ctx.ctx == nil {
-		err = fmt.Errorf("Context not opened")
-	}
-	return
-}
-
-func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	var cdi C.libxl_dominfo
-
-	ret := C.libxl_domain_info(Ctx.ctx, unsafe.Pointer(&cdi), C.uint32_t(Id))
-
-	// FIXME: IsDomainNotPresentError
-	if ret != 0 {
-		err = fmt.Errorf("libxl_domain_info failed: %d", ret)
-		return
-	}
-
-	// We could consider having this boilerplate generated by the
-	// idl, in a function like this:
-	//
-	// di = translateCdomaininfoToGoDomaininfo(cdi)
-	di = &Dominfo{}
-	di.Uuid = Uuid(cdi.uuid)
-	di.Domid = Domid(cdi.domid)
-	di.Running = bool(cdi.running)
-	di.Blocked = bool(cdi.blocked)
-	di.Paused = bool(cdi.paused)
-	di.Shutdown = bool(cdi.shutdown)
-	di.Dying = bool(cdi.dying)
-	di.Never_stop = bool(cdi.never_stop)
-	di.Shutdown_reason = int32(cdi.shutdown_reason)
-	di.Outstanding_memkb = MemKB(cdi.outstanding_memkb)
-	di.Current_memkb = MemKB(cdi.current_memkb)
-	di.Shared_memkb = MemKB(cdi.shared_memkb)
-	di.Paged_memkb = MemKB(cdi.paged_memkb)
-	di.Max_memkb = MemKB(cdi.max_memkb)
-	di.Cpu_time = time.Duration(cdi.cpu_time)
-	di.Vcpu_max_id = uint32(cdi.vcpu_max_id)
-	di.Vcpu_online = uint32(cdi.vcpu_online)
-	di.Cpupool = uint32(cdi.cpupool)
-	di.Domain_type = int32(cdi.domain_type)
-
-	return
-}
-
-func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	ret := C.libxl_domain_unpause(Ctx.ctx, C.uint32_t(Id))
-
-	if ret != 0 {
-		err = fmt.Errorf("libxl_domain_unpause failed: %d", ret)
-	}
-	return
-}
-
-/*
- * Bitmap operations
- */
-
-// Return a Go bitmap which is a copy of the referred C bitmap.
-func bitmapCToGo(cbm C.libxl_bitmap) (gbm Bitmap) {
-	// Alloc a Go slice for the bytes
-	size := int(cbm.size)
-	gbm.bitmap = make([]C.uint8_t, size)
-
-	// Make a slice pointing to the C array
-	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
-
-	// And copy the C array into the Go array
-	copy(gbm.bitmap, mapslice)
-
-	return
-}
-
-// Must be C.libxl_bitmap_dispose'd of afterwards
-func bitmapGotoC(gbm Bitmap) (cbm C.libxl_bitmap) {
-	C.libxl_bitmap_init(&cbm)
-
-	size := len(gbm.bitmap)
-	cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
-	cbm.size = C.uint32_t(size)
-	if cbm._map == nil {
-		panic("C.calloc failed!")
-	}
-
-	// Make a slice pointing to the C array
-	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
-
-	// And copy the Go array into the C array
-	copy(mapslice, gbm.bitmap)
-
-	return
-}
-
-func (bm *Bitmap) Test(bit int) (bool) {
-	ubit := uint(bit)
-	if (bit > bm.Max() || bm.bitmap == nil) {
-		return false
-	}
-	
-	return (bm.bitmap[bit / 8] & (1 << (ubit & 7))) != 0
-}
-
-func (bm *Bitmap) Set(bit int) {
-	ibit := bit / 8;
-	if (ibit + 1 > len(bm.bitmap)) {
-		bm.bitmap = append(bm.bitmap, make([]C.uint8_t, ibit+1-len(bm.bitmap))...)
-	}
-	
-	bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
-}
-
-func (bm *Bitmap) SetRange(start int, end int) {
-	for i := start; i <= end; i++ {
-		bm.Set(i)
-	}
-}
-
-func (bm *Bitmap) Clear(bit int) {
-	ubit := uint(bit)
-	if (bit > bm.Max() || bm.bitmap == nil) {
-		return
-	}
-	
-	bm.bitmap[bit / 8] &= ^(1 << (ubit & 7))
-}
-
-func (bm *Bitmap) ClearRange(start int, end int) {
-	for i := start; i <= end; i++ {
-		bm.Clear(i)
-	}
-}
-
-func (bm *Bitmap) Max() (int) {
-	return len(bm.bitmap) * 8 - 1
-}
-
-func (bm *Bitmap) IsEmpty() (bool) {
-	for i:=0; i<len(bm.bitmap); i++ {
-		if bm.bitmap[i] != 0 {
-			return false
-		}
-	}
-	return true
-}
-
-func (a Bitmap) And(b Bitmap) (c Bitmap) {
-	var max, min int
-	if len(a.bitmap) > len(b.bitmap) {
-		max = len(a.bitmap)
-		min = len(b.bitmap)
-	} else {
-		max = len(b.bitmap)
-		min = len(a.bitmap)
-	}
-	c.bitmap = make([]C.uint8_t, max)
-
-	for i := 0; i < min; i++ {
-		c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
-	}
-	return
-}
-
-func (bm Bitmap) String() (s string) {
-	lastOnline := false
-	crange := false
-	printed := false
-	var i int
-	/// --x-xxxxx-x -> 2,4-8,10
-	/// --x-xxxxxxx -> 2,4-10
-	for i = 0; i <= bm.Max(); i++ {
-		if bm.Test(i) {
-			if !lastOnline {
-				// Switching offline -> online, print this cpu
-				if printed {
-					s += ","
-				}
-				s += fmt.Sprintf("%d", i)
-				printed = true
-			} else if !crange {
-				// last was online, but we're not in a range; print -
-				crange = true
-				s += "-"
-			} else {
-				// last was online, we're in a range,  nothing else to do
-			}
-			lastOnline = true
-		} else {
-			if lastOnline {
-				// Switching online->offline; do we need to end a range?
-				if crange {
-					s += fmt.Sprintf("%d", i-1)
-				}
-			}
-			lastOnline = false
-			crange = false
-		}
-	}
-	if lastOnline {
-		// Switching online->offline; do we need to end a range?
-		if crange {
-			s += fmt.Sprintf("%d", i-1)
-		}
-	}
-
-	return
-}
-
-// const char *libxl_scheduler_to_string(libxl_scheduler p);
-func (s Scheduler) String() (string) {
-	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
-	// No need to free const return value
-
-	return C.GoString(cs)
-}
-
-// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
-func (s *Scheduler) FromString(gstr string) (err error) {
-	cstr := C.CString(gstr)
-	defer C.free(unsafe.Pointer(cstr))
-
-	var cs C.libxl_scheduler
-	ret := C.libxl_scheduler_from_string(cstr, &cs)
-	if ret != 0 {
-		err = fmt.Errorf("libxl_scheduler_from_string: %d\n", ret)
-		return
-	}
-
-	*s = Scheduler(cs)
-	return
-}
-
-func translateCpupoolInfoCToGo(cci C.libxl_cpupoolinfo) (gci CpupoolInfo) {
-	gci.Poolid = uint32(cci.poolid)
-	gci.PoolName = C.GoString(cci.pool_name)
-	gci.Scheduler = Scheduler(cci.sched)
-	gci.DomainCount = int(cci.n_dom)
-	gci.Cpumap = bitmapCToGo(cci.cpumap)
-
-	return
-}
-
-func SchedulerFromString(name string) (s Scheduler, err error) {
-	cname := C.CString(name)
-	defer C.free(unsafe.Pointer(cname))
-
-	var cs C.libxl_scheduler
-
-	ret := C.libxl_scheduler_from_string(cname, &cs)
-	if ret != 0 {
-		err = fmt.Errorf("libxl_scheduler_from_string failed: %d", ret)
-		return
-	}
-
-	s = Scheduler(cs)
-
-	return
-}
-
-// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
-// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
-func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
-	err := Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	var nbPool C.int
-
-	c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
-
-	defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
-
-	if int(nbPool) == 0 {
-		return
-	}
-
-	// Magic
-	cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
-
-	for i := range cpupoolListSlice {
-		info := translateCpupoolInfoCToGo(cpupoolListSlice[i])
-		
-		list = append(list, info)
-	}
-
-	return
-}
-
-// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
-func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo) {
-	err := Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	var c_cpupool C.libxl_cpupoolinfo
-	
-	ret := C.libxl_cpupool_info(Ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_info failed: %d", ret)
-		return
-	}
-	defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
-
-	pool = translateCpupoolInfoCToGo(c_cpupool)
-
-	return
-}
-
-
-
-// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
-//                          libxl_scheduler sched,
-//                          libxl_bitmap cpumap, libxl_uuid *uuid,
-//                          uint32_t *poolid);
-// FIXME: uuid
-// FIXME: Setting poolid
-func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	poolid := C.uint32_t(0)
-	name := C.CString(Name)
-	defer C.free(unsafe.Pointer(name))
-	
-	// For now, just do what xl does, and make a new uuid every time we create the pool
-	var uuid C.libxl_uuid
-	C.libxl_uuid_generate(&uuid)
-
-	cbm := bitmapGotoC(Cpumap)
-	defer C.libxl_bitmap_dispose(&cbm)
-	
-	ret := C.libxl_cpupool_create(Ctx.ctx, name, C.libxl_scheduler(Scheduler),
-		cbm, &uuid, &poolid)
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_create failed: %d", ret)
-		return
-	}
-
-	Poolid = uint32(poolid)
-	
-	return
-}
-
-// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
-func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_destroy failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
-func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_cpuadd failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
-//                                 const libxl_bitmap *cpumap);
-func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	cbm := bitmapGotoC(Cpumap)
-	defer C.libxl_bitmap_dispose(&cbm)
-	
-	ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_cpuadd_cpumap failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
-func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_cpuremove failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
-//                                    const libxl_bitmap *cpumap);
-func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
-	err = Ctx.CheckOpen()
-	if err != nil {
-		return
-	}
-
-	cbm := bitmapGotoC(Cpumap)
-	defer C.libxl_bitmap_dispose(&cbm)
-	
-	ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
-	// FIXME: Proper error
-	if ret != 0 {
-		err = fmt.Errorf("libxl_cpupool_cpuremove_cpumap failed: %d", ret)
-		return
-	}
-
-	return
-}
-
-// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
-// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
-// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
-// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
-
-//
-// Utility functions
-//
-func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
-	plist := Ctx.ListCpupool()
-
-	for i := range plist {
-		if plist[i].PoolName == name {
-			found = true
-			info = plist[i]
-			return
-		}
-	}
-	return
-}
-
-func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
-	plist := Ctx.ListCpupool()
-
-	for i := range plist {
-		var Intersection Bitmap
-		Intersection = Cpumap.And(plist[i].Cpumap)
-		if ! Intersection.IsEmpty() {
-			err = Ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, Intersection)
-			if err != nil {
-				return
-			}
-		}
-	}
-	return
-}
-
-func XlTest(Args []string) {
-	var Cpumap Bitmap
-
-	Cpumap.Set(2)
-	Cpumap.SetRange(4, 8)
-	Cpumap.Set(10)
-
-	fmt.Printf("Cpumap: %v\n", Cpumap)
-
-	Cpumap.Set(9)
-
-	fmt.Printf("Cpumap: %v\n", Cpumap)
-
-	var Ctx Context
-
-	err := Ctx.Open()
-	if err != nil {
-		fmt.Printf("Opening context: %v\n", err)
-		return
-	}
-
-	pool, found := Ctx.CpupoolFindByName("schedbench")
-
-	if found {
-		fmt.Printf("Found schedbench, destroying\n")
-
-		err = Ctx.CpupoolDestroy(pool.Poolid)
-		if err != nil {
-			fmt.Printf("Couldn't destroy pool: %v\n", err)
-			return
-		}
-
-		fmt.Printf("Returning cpus to pool 0 for fun\n")
-		err = Ctx.CpupoolCpuaddCpumap(0, pool.Cpumap)
-		if err != nil {
-			fmt.Printf("Couldn't add cpus to domain 0: %v\n", err)
-			return
-		}
-	}
-
-	Cpumap = Bitmap{}
-
-	Cpumap.SetRange(12, 15)
-
-	fmt.Printf("Freeing cpus\n")
-	err = Ctx.CpupoolMakeFree(Cpumap)
-	if err != nil {
-		fmt.Printf("Couldn't free cpus: %v\n", err)
-		return
-	}
-
-
-	fmt.Printf("Creating new pool\n")
-
-	err, Poolid := Ctx.CpupoolCreate("schedbench", SchedulerCredit, Cpumap)
-	if err != nil {
-		fmt.Printf("Error creating cpupool: %v\n", err)
-	} else {
-		fmt.Printf("Pool id: %d\n", Poolid)
-	}
-
-	pool = Ctx.CpupoolInfo(0)
-	fmt.Printf("Cpupool 0 info: %v\n", pool)
-	
-	Ctx.Close()
-}
diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
new file mode 100644
index 0000000..b0eb6f8
--- /dev/null
+++ b/tools/golang/xenlight/xenlight.go
@@ -0,0 +1,1000 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+package xenlight
+
+/*
+#cgo LDFLAGS: -lxenlight -lyajl
+#include <stdlib.h>
+#include <libxl.h>
+*/
+import "C"
+
+/*
+ * Other flags that may be needed at some point:
+ *  -lnl-route-3 -lnl-3
+#cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
+ *
+ * To get back to simple dynamic linking:
+*/
+
+import (
+	"fmt"
+	"time"
+	"unsafe"
+)
+
+/*
+ * Errors
+ */
+const (
+	ErrorNonspecific                  = int(C.ERROR_NONSPECIFIC)
+	ErrorVersion                      = int(C.ERROR_VERSION)
+	ErrorFail                         = int(C.ERROR_FAIL)
+	ErrorNi                           = int(C.ERROR_NI)
+	ErrorNomem                        = int(C.ERROR_NOMEM)
+	ErrorInval                        = int(C.ERROR_INVAL)
+	ErrorBadfail                      = int(C.ERROR_BADFAIL)
+	ErrorGuestTimedout                = int(C.ERROR_GUEST_TIMEDOUT)
+	ErrorTimedout                     = int(C.ERROR_TIMEDOUT)
+	ErrorNoparavirt                   = int(C.ERROR_NOPARAVIRT)
+	ErrorNotReady                     = int(C.ERROR_NOT_READY)
+	ErrorOseventRegFail               = int(C.ERROR_OSEVENT_REG_FAIL)
+	ErrorBufferfull                   = int(C.ERROR_BUFFERFULL)
+	ErrorUnknownChild                 = int(C.ERROR_UNKNOWN_CHILD)
+	ErrorLockFail                     = int(C.ERROR_LOCK_FAIL)
+	ErrorJsonConfigEmpty              = int(C.ERROR_JSON_CONFIG_EMPTY)
+	ErrorDeviceExists                 = int(C.ERROR_DEVICE_EXISTS)
+	ErrorCheckpointDevopsDoesNotMatch = int(C.ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH)
+	ErrorCheckpointDeviceNotSupported = int(C.ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED)
+	ErrorVnumaConfigInvalid           = int(C.ERROR_VNUMA_CONFIG_INVALID)
+	ErrorDomainNotfound               = int(C.ERROR_DOMAIN_NOTFOUND)
+	ErrorAborted                      = int(C.ERROR_ABORTED)
+	ErrorNotfound                     = int(C.ERROR_NOTFOUND)
+	ErrorDomainDestroyed              = int(C.ERROR_DOMAIN_DESTROYED)
+	ErrorFeatureRemoved               = int(C.ERROR_FEATURE_REMOVED)
+)
+
+/*
+ * Types: Builtins
+ */
+
+type Domid uint32
+
+type MemKB uint64
+
+type Hwcap struct {
+	Hwcap []C.uint32_t
+}
+
+// typedef struct {
+//     uint32_t size;          /* number of bytes in map */
+//     uint8_t *map;
+// } libxl_bitmap;
+
+// Implement the Go bitmap type such that the underlying data can
+// easily be copied in and out.  NB that we still have to do copies
+// both directions, because cgo runtime restrictions forbid passing to
+// a C function a pointer to a Go-allocated structure which contains a
+// pointer.
+type Bitmap struct {
+	bitmap []C.uint8_t
+}
+
+type Context struct {
+	ctx *C.libxl_ctx
+}
+
+type Uuid C.libxl_uuid
+
+/*
+ * Types: IDL
+ *
+ * FIXME: Generate these automatically from the IDL
+ */
+type Dominfo struct {
+	Uuid       Uuid
+	Domid      Domid
+	Running    bool
+	Blocked    bool
+	Paused     bool
+	Shutdown   bool
+	Dying      bool
+	Never_stop bool
+
+	Shutdown_reason   int32 // FIXME shutdown_reason enumeration
+	Outstanding_memkb MemKB
+	Current_memkb     MemKB
+	Shared_memkb      MemKB
+	Paged_memkb       MemKB
+	Max_memkb         MemKB
+	Cpu_time          time.Duration
+	Vcpu_max_id       uint32
+	Vcpu_online       uint32
+	Cpupool           uint32
+	Domain_type       int32 //FIXME libxl_domain_type enumeration
+
+}
+
+type Physinfo struct {
+	Threads_per_core uint32
+	Cores_per_socket uint32
+
+	Max_cpu_id uint32
+	Nr_cpus    uint32
+	Cpu_khz    uint32
+
+	Total_pages         uint64
+	Free_pages          uint64
+	Scrub_pages         uint64
+	Outstanding_pages   uint64
+	Sharing_freed_pages uint64
+	Sharing_used_frames uint64
+
+	Nr_nodes uint32
+	Hw_cap   Hwcap
+
+	Cap_hvm          bool
+	Cap_hvm_directio bool
+}
+
+type VersionInfo struct {
+	Xen_version_major int
+	Xen_version_minor int
+	Xen_version_extra string
+	Compiler          string
+	Compile_by        string
+	Compile_domain    string
+	Compile_date      string
+	Capabilities      string
+	Changeset         string
+	Virt_start        uint64
+	Pagesize          int
+	Commandline       string
+	Build_id          string
+}
+
+// # Consistent with values defined in domctl.h
+// # Except unknown which we have made up
+// libxl_scheduler = Enumeration("scheduler", [
+//     (0, "unknown"),
+//     (4, "sedf"),
+//     (5, "credit"),
+//     (6, "credit2"),
+//     (7, "arinc653"),
+//     (8, "rtds"),
+//     ])
+type Scheduler int
+
+var (
+	SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
+	SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
+	SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
+	SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
+	SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
+	SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
+)
+
+// libxl_cpupoolinfo = Struct("cpupoolinfo", [
+//     ("poolid",      uint32),
+//     ("pool_name",   string),
+//     ("sched",       libxl_scheduler),
+//     ("n_dom",       uint32),
+//     ("cpumap",      libxl_bitmap)
+//     ], dir=DIR_OUT)
+
+type CpupoolInfo struct {
+	Poolid      uint32
+	PoolName    string
+	Scheduler   Scheduler
+	DomainCount int
+	Cpumap      Bitmap
+}
+
+/*
+ * Context
+ */
+var Ctx Context
+
+func (Ctx *Context) IsOpen() bool {
+	return Ctx.ctx != nil
+}
+
+func (Ctx *Context) Open() (err error) {
+	if Ctx.ctx != nil {
+		return
+	}
+
+	ret := C.libxl_ctx_alloc(unsafe.Pointer(&Ctx.ctx), C.LIBXL_VERSION, 0, nil)
+
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("Allocating libxl context: ", ret)
+	}
+	return
+}
+
+func (Ctx *Context) Close() (err error) {
+	ret := C.libxl_ctx_free(unsafe.Pointer(Ctx.ctx))
+	Ctx.ctx = nil
+
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("Freeing libxl context: ", ret)
+	}
+	return
+}
+
+func (Ctx *Context) CheckOpen() (err error) {
+	if Ctx.ctx == nil {
+		err = fmt.Errorf("Context not opened")
+	}
+	return
+}
+
+func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var cdi C.libxl_dominfo
+
+	ret := C.libxl_domain_info(Ctx.ctx, unsafe.Pointer(&cdi), C.uint32_t(Id))
+
+	// FIXME: proper error
+	if ret != 0 {
+		err = createError("libxl_domain_info failed: ", ret)
+		return
+	}
+
+	// We could consider having this boilerplate generated by the
+	// idl, in a function like this:
+	//
+	// di = translateCdomaininfoToGoDomaininfo(cdi)
+	di = &Dominfo{}
+	di.Uuid = Uuid(cdi.uuid)
+	di.Domid = Domid(cdi.domid)
+	di.Running = bool(cdi.running)
+	di.Blocked = bool(cdi.blocked)
+	di.Paused = bool(cdi.paused)
+	di.Shutdown = bool(cdi.shutdown)
+	di.Dying = bool(cdi.dying)
+	di.Never_stop = bool(cdi.never_stop)
+	di.Shutdown_reason = int32(cdi.shutdown_reason)
+	di.Outstanding_memkb = MemKB(cdi.outstanding_memkb)
+	di.Current_memkb = MemKB(cdi.current_memkb)
+	di.Shared_memkb = MemKB(cdi.shared_memkb)
+	di.Paged_memkb = MemKB(cdi.paged_memkb)
+	di.Max_memkb = MemKB(cdi.max_memkb)
+	di.Cpu_time = time.Duration(cdi.cpu_time)
+	di.Vcpu_max_id = uint32(cdi.vcpu_max_id)
+	di.Vcpu_online = uint32(cdi.vcpu_online)
+	di.Cpupool = uint32(cdi.cpupool)
+	di.Domain_type = int32(cdi.domain_type)
+
+	return
+}
+
+func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_domain_unpause(Ctx.ctx, C.uint32_t(Id))
+
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("libxl_domain_unpause failed: ", ret)
+	}
+	return
+}
+
+/*
+ * Bitmap operations
+ */
+
+// Return a Go bitmap which is a copy of the referred C bitmap.
+func bitmapCToGo(cbm C.libxl_bitmap) (gbm Bitmap) {
+	// Alloc a Go slice for the bytes
+	size := int(cbm.size)
+	gbm.bitmap = make([]C.uint8_t, size)
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+	// And copy the C array into the Go array
+	copy(gbm.bitmap, mapslice)
+
+	return
+}
+
+// Must be C.libxl_bitmap_dispose'd of afterwards
+func bitmapGotoC(gbm Bitmap) (cbm C.libxl_bitmap) {
+	C.libxl_bitmap_init(&cbm)
+
+	size := len(gbm.bitmap)
+	cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
+	cbm.size = C.uint32_t(size)
+	if cbm._map == nil {
+		panic("C.calloc failed!")
+	}
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+	// And copy the Go array into the C array
+	copy(mapslice, gbm.bitmap)
+
+	return
+}
+
+func (bm *Bitmap) Test(bit int) bool {
+	ubit := uint(bit)
+	if bit > bm.Max() || bm.bitmap == nil {
+		return false
+	}
+
+	return (bm.bitmap[bit/8] & (1 << (ubit & 7))) != 0
+}
+
+func (bm *Bitmap) Set(bit int) {
+	ibit := bit / 8
+	if ibit+1 > len(bm.bitmap) {
+		bm.bitmap = append(bm.bitmap, make([]C.uint8_t, ibit+1-len(bm.bitmap))...)
+	}
+
+	bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
+}
+
+func (bm *Bitmap) SetRange(start int, end int) {
+	for i := start; i <= end; i++ {
+		bm.Set(i)
+	}
+}
+
+func (bm *Bitmap) Clear(bit int) {
+	ubit := uint(bit)
+	if bit > bm.Max() || bm.bitmap == nil {
+		return
+	}
+
+	bm.bitmap[bit/8] &= ^(1 << (ubit & 7))
+}
+
+func (bm *Bitmap) ClearRange(start int, end int) {
+	for i := start; i <= end; i++ {
+		bm.Clear(i)
+	}
+}
+
+func (bm *Bitmap) Max() int {
+	return len(bm.bitmap)*8 - 1
+}
+
+func (bm *Bitmap) IsEmpty() bool {
+	for i := 0; i < len(bm.bitmap); i++ {
+		if bm.bitmap[i] != 0 {
+			return false
+		}
+	}
+	return true
+}
+
+func (a Bitmap) And(b Bitmap) (c Bitmap) {
+	var max, min int
+	if len(a.bitmap) > len(b.bitmap) {
+		max = len(a.bitmap)
+		min = len(b.bitmap)
+	} else {
+		max = len(b.bitmap)
+		min = len(a.bitmap)
+	}
+	c.bitmap = make([]C.uint8_t, max)
+
+	for i := 0; i < min; i++ {
+		c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
+	}
+	return
+}
+
+func (bm Bitmap) String() (s string) {
+	lastOnline := false
+	crange := false
+	printed := false
+	var i int
+	/// --x-xxxxx-x -> 2,4-8,10
+	/// --x-xxxxxxx -> 2,4-10
+	for i = 0; i <= bm.Max(); i++ {
+		if bm.Test(i) {
+			if !lastOnline {
+				// Switching offline -> online, print this cpu
+				if printed {
+					s += ","
+				}
+				s += fmt.Sprintf("%d", i)
+				printed = true
+			} else if !crange {
+				// last was online, but we're not in a range; print -
+				crange = true
+				s += "-"
+			} else {
+				// last was online, we're in a range,  nothing else to do
+			}
+			lastOnline = true
+		} else {
+			if lastOnline {
+				// Switching online->offline; do we need to end a range?
+				if crange {
+					s += fmt.Sprintf("%d", i-1)
+				}
+			}
+			lastOnline = false
+			crange = false
+		}
+	}
+	if lastOnline {
+		// Switching online->offline; do we need to end a range?
+		if crange {
+			s += fmt.Sprintf("%d", i-1)
+		}
+	}
+
+	return
+}
+
+// const char *libxl_scheduler_to_string(libxl_scheduler p);
+func (s Scheduler) String() string {
+	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
+	// No need to free const return value
+
+	return C.GoString(cs)
+}
+
+// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
+func (s *Scheduler) FromString(gstr string) (err error) {
+	cstr := C.CString(gstr)
+	defer C.free(unsafe.Pointer(cstr))
+
+	var cs C.libxl_scheduler
+	ret := C.libxl_scheduler_from_string(cstr, &cs)
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("libxl_scheduler_from_string: ", ret)
+		return
+	}
+
+	*s = Scheduler(cs)
+	return
+}
+
+func translateCpupoolInfoCToGo(cci C.libxl_cpupoolinfo) (gci CpupoolInfo) {
+	gci.Poolid = uint32(cci.poolid)
+	gci.PoolName = C.GoString(cci.pool_name)
+	gci.Scheduler = Scheduler(cci.sched)
+	gci.DomainCount = int(cci.n_dom)
+	gci.Cpumap = bitmapCToGo(cci.cpumap)
+
+	return
+}
+
+func SchedulerFromString(name string) (s Scheduler, err error) {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+
+	var cs C.libxl_scheduler
+
+	ret := C.libxl_scheduler_from_string(cname, &cs)
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("libxl_scheduler_from_string failed: ", ret)
+		return
+	}
+
+	s = Scheduler(cs)
+
+	return
+}
+
+// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
+// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
+func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
+	err := Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var nbPool C.int
+
+	c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
+
+	defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
+
+	if int(nbPool) == 0 {
+		return
+	}
+
+	// Magic
+	cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
+
+	for i := range cpupoolListSlice {
+		info := translateCpupoolInfoCToGo(cpupoolListSlice[i])
+
+		list = append(list, info)
+	}
+
+	return
+}
+
+// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
+func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo) {
+	err := Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var c_cpupool C.libxl_cpupoolinfo
+
+	ret := C.libxl_cpupool_info(Ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
+	//FIXME: proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_info failed: ", ret)
+		return
+	}
+	defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
+
+	pool = translateCpupoolInfoCToGo(c_cpupool)
+
+	return
+}
+
+// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
+//                          libxl_scheduler sched,
+//                          libxl_bitmap cpumap, libxl_uuid *uuid,
+//                          uint32_t *poolid);
+// FIXME: uuid
+// FIXME: Setting poolid
+func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	poolid := C.uint32_t(0)
+	name := C.CString(Name)
+	defer C.free(unsafe.Pointer(name))
+
+	// For now, just do what xl does, and make a new uuid every time we create the pool
+	var uuid C.libxl_uuid
+	C.libxl_uuid_generate(&uuid)
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+
+	ret := C.libxl_cpupool_create(Ctx.ctx, name, C.libxl_scheduler(Scheduler),
+		cbm, &uuid, &poolid)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_create failed: ", ret)
+		return
+	}
+
+	Poolid = uint32(poolid)
+
+	return
+}
+
+// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
+func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_destroy failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
+func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_cpuadd failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                 const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+
+	ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_cpuadd_cpumap failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
+func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_cpuremove failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                    const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+
+	ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_cpuremove_cpumap failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
+// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
+
+//
+// Utility functions
+//
+func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		if plist[i].PoolName == name {
+			found = true
+			info = plist[i]
+			return
+		}
+	}
+	return
+}
+
+func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		var Intersection Bitmap
+		Intersection = Cpumap.And(plist[i].Cpumap)
+		if !Intersection.IsEmpty() {
+			err = Ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, Intersection)
+			if err != nil {
+				return
+			}
+		}
+	}
+	return
+}
+
+func XlTest(Args []string) {
+	var Cpumap Bitmap
+
+	Cpumap.Set(2)
+	Cpumap.SetRange(4, 8)
+	Cpumap.Set(10)
+
+	fmt.Printf("Cpumap: %v\n", Cpumap)
+
+	Cpumap.Set(9)
+
+	fmt.Printf("Cpumap: %v\n", Cpumap)
+
+	var Ctx Context
+
+	err := Ctx.Open()
+	if err != nil {
+		fmt.Printf("Opening context: %v\n", err)
+		return
+	}
+
+	pool, found := Ctx.CpupoolFindByName("schedbench")
+
+	if found {
+		fmt.Printf("Found schedbench, destroying\n")
+
+		err = Ctx.CpupoolDestroy(pool.Poolid)
+		if err != nil {
+			fmt.Printf("Couldn't destroy pool: %v\n", err)
+			return
+		}
+
+		fmt.Printf("Returning cpus to pool 0 for fun\n")
+		err = Ctx.CpupoolCpuaddCpumap(0, pool.Cpumap)
+		if err != nil {
+			fmt.Printf("Couldn't add cpus to domain 0: %v\n", err)
+			return
+		}
+	}
+
+	Cpumap = Bitmap{}
+
+	Cpumap.SetRange(12, 15)
+
+	fmt.Printf("Freeing cpus\n")
+	err = Ctx.CpupoolMakeFree(Cpumap)
+	if err != nil {
+		fmt.Printf("Couldn't free cpus: %v\n", err)
+		return
+	}
+
+	fmt.Printf("Creating new pool\n")
+
+	err, Poolid := Ctx.CpupoolCreate("schedbench", SchedulerCredit, Cpumap)
+	if err != nil {
+		fmt.Printf("Error creating cpupool: %v\n", err)
+	} else {
+		fmt.Printf("Pool id: %d\n", Poolid)
+	}
+
+	pool = Ctx.CpupoolInfo(0)
+	fmt.Printf("Cpupool 0 info: %v\n", pool)
+
+	Ctx.Close()
+}
+
+//int libxl_get_max_cpus(libxl_ctx *ctx);
+func (Ctx *Context) GetMaxCpus() (maxCpus int, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_get_max_cpus(Ctx.ctx)
+	//FIXME: proper error
+	if ret < 0 {
+		err = createError("libxl_get_max_cpus failed: ", ret)
+		return
+	}
+	maxCpus = int(ret)
+	return
+}
+
+//int libxl_get_online_cpus(libxl_ctx *ctx);
+func (Ctx *Context) GetOnlineCpus() (onCpus int, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_get_online_cpus(Ctx.ctx)
+	//FIXME: proper error
+	if ret < 0 {
+		err = createError("libxl_get_online_cpus failed: ", ret)
+		return
+	}
+	onCpus = int(ret)
+	return
+}
+
+//int libxl_get_max_nodes(libxl_ctx *ctx);
+func (Ctx *Context) GetMaxNodes() (maxNodes int, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+	ret := C.libxl_get_max_nodes(Ctx.ctx)
+	//FIXME: proper error
+	if ret < 0 {
+		err = createError("libxl_get_max_nodes failed: ", ret)
+		return
+	}
+	maxNodes = int(ret)
+	return
+}
+
+//int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb);
+func (Ctx *Context) GetFreeMemory() (memkb uint64, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+	var cmem C.uint64_t
+	ret := C.libxl_get_free_memory(Ctx.ctx, &cmem)
+
+	if ret < 0 {
+		err = createError("libxl_get_free_memory failed: ", ret)
+		return
+	}
+
+	memkb = uint64(ret)
+	return
+
+}
+
+//int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
+func (Ctx *Context) GetPhysinfo() (physinfo *Physinfo, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+	var cphys C.libxl_physinfo
+
+	ret := C.libxl_get_physinfo(Ctx.ctx, &cphys)
+
+	//FIXME: proper error
+	if ret < 0 {
+		err = createError("libxl_get_physinfo failed: ", ret)
+		return
+	}
+	physinfo = &Physinfo{}
+	physinfo.Threads_per_core = uint32(cphys.threads_per_core)
+	physinfo.Cores_per_socket = uint32(cphys.cores_per_socket)
+	physinfo.Max_cpu_id = uint32(cphys.max_cpu_id)
+	physinfo.Nr_cpus = uint32(cphys.nr_cpus)
+	physinfo.Cpu_khz = uint32(cphys.cpu_khz)
+	physinfo.Total_pages = uint64(cphys.total_pages)
+	physinfo.Free_pages = uint64(cphys.free_pages)
+	physinfo.Scrub_pages = uint64(cphys.scrub_pages)
+	physinfo.Outstanding_pages = uint64(cphys.scrub_pages)
+	physinfo.Sharing_freed_pages = uint64(cphys.sharing_freed_pages)
+	physinfo.Sharing_used_frames = uint64(cphys.sharing_used_frames)
+	physinfo.Nr_nodes = uint32(cphys.nr_nodes)
+	physinfo.Hw_cap = hwcapCToGo(cphys.hw_cap)
+	physinfo.Cap_hvm = bool(cphys.cap_hvm)
+	physinfo.Cap_hvm_directio = bool(cphys.cap_hvm_directio)
+
+	return
+}
+
+//const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx);
+func (Ctx *Context) GetVersionInfo() (info *VersionInfo, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var cinfo *C.libxl_version_info
+
+	cinfo = C.libxl_get_version_info(Ctx.ctx)
+
+	info = &VersionInfo{}
+	info.Xen_version_major = int(cinfo.xen_version_major)
+	info.Xen_version_minor = int(cinfo.xen_version_minor)
+	info.Xen_version_extra = C.GoString(cinfo.xen_version_extra)
+	info.Compiler = C.GoString(cinfo.compiler)
+	info.Compile_by = C.GoString(cinfo.compile_by)
+	info.Compile_domain = C.GoString(cinfo.compile_domain)
+	info.Compile_date = C.GoString(cinfo.compile_date)
+	info.Capabilities = C.GoString(cinfo.capabilities)
+	info.Changeset = C.GoString(cinfo.changeset)
+	info.Virt_start = uint64(cinfo.virt_start)
+	info.Pagesize = int(cinfo.pagesize)
+
+	return
+}
+func hwcapCToGo(chwcap C.libxl_hwcap) (ghwcap Hwcap) {
+	// Alloc a Go slice for the bytes
+	size := 8
+	ghwcap.Hwcap = make([]C.uint32_t, size)
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint32_t)(unsafe.Pointer(&chwcap[0]))[:size:size]
+
+	// And copy the C array into the Go array
+	copy(ghwcap.Hwcap, mapslice)
+
+	return
+}
+
+func createError(method string, cerrNum C.int) (err error) {
+	method += " %s"
+	errNum := int(cerrNum)
+	switch errNum {
+	case ErrorNonspecific:
+		err = fmt.Errorf(method, "ERROR_NONSPECIFIC")
+	case ErrorVersion:
+		err = fmt.Errorf(method, "ERROR_VERSION")
+	case ErrorFail:
+		err = fmt.Errorf(method, "ERROR_FAIL")
+	case ErrorNi:
+		err = fmt.Errorf(method, "ERROR_NI")
+	case ErrorNomem:
+		err = fmt.Errorf(method, "ERROR_NOMEM")
+	case ErrorInval:
+		err = fmt.Errorf(method, "ERROR_INVAL")
+	case ErrorBadfail:
+		err = fmt.Errorf(method, "ERROR_BADFAIL")
+	case ErrorGuestTimedout:
+		err = fmt.Errorf(method, "ERROR_GUEST_TIMEDOUT")
+	case ErrorNoparavirt:
+		err = fmt.Errorf(method, "ERROR_NOPARAVIRT")
+	case ErrorNotReady:
+		err = fmt.Errorf(method, "ERROR_NOT_READY")
+	case ErrorOseventRegFail:
+		err = fmt.Errorf(method, "ERROR_OSEVENT_REG_FAIL")
+	case ErrorBufferfull:
+		err = fmt.Errorf(method, "ERROR_BUFFERFULL")
+	case ErrorUnknownChild:
+		err = fmt.Errorf(method, "ERROR_UNKNOWN_CHILD")
+	case ErrorLockFail:
+		err = fmt.Errorf(method, "ERROR_LOCK_FAIL")
+	case ErrorJsonConfigEmpty:
+		err = fmt.Errorf(method, "ERROR_JSON_CONFIG_EMPTY")
+	case ErrorDeviceExists:
+		err = fmt.Errorf(method, "ERROR_DEVICE_EXISTS")
+	case ErrorCheckpointDevopsDoesNotMatch:
+		err = fmt.Errorf(method, "ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH")
+	case ErrorCheckpointDeviceNotSupported:
+		err = fmt.Errorf(method, "ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED")
+	case ErrorVnumaConfigInvalid:
+		err = fmt.Errorf(method, "ERROR_VNUMA_CONFIG_INVALID")
+	case ErrorDomainNotfound:
+		err = fmt.Errorf(method, "ERROR_DOMAIN_NOTFOUND")
+	case ErrorAborted:
+		err = fmt.Errorf(method, "ERROR_ABORTED")
+	case ErrorNotfound:
+		err = fmt.Errorf(method, "ERROR_NOTFOUND")
+	case ErrorDomainDestroyed:
+		err = fmt.Errorf(method, "ERROR_DOMAIN_DESTROYED")
+	case ErrorFeatureRemoved:
+		err = fmt.Errorf(method, "ERROR_FEATURE_REMOVED")
+	default:
+		err = fmt.Errorf(method, "error not found")
+	}
+	return
+
+}
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info
  2016-12-29  1:14 ` [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info Ronald Rojas
@ 2016-12-29 10:34   ` George Dunlap
  2016-12-29 10:52     ` Wei Liu
  2016-12-29 13:45   ` George Dunlap
  1 sibling, 1 reply; 67+ messages in thread
From: George Dunlap @ 2016-12-29 10:34 UTC (permalink / raw)
  To: Ronald Rojas, xen-devel, Ian Jackson, Wei Liu, George Dunlap

On 29/12/16 01:14, Ronald Rojas wrote:
> Create interface to interact with libxl_verions_info
> and libxl_physinfo. Also introduce proper error
> handling.
> 
> Signed-off-by: Ronald Rojas <ronladred@gmail.com>

Hey Ronald,

When you send a series to a public open-source project, you want it to
be a sort of idealized set of changes that make it easy to "see the
forest for the trees", as it were, not the actual local development
path.  We don't need the full development history of libxl.go -- a
simple dump will be fine; and we definitely don't need all the other
stuff from schedbench in the xen.git history. :-)

All you needed to do to "import" my existing libxl code from schedbench was:

$ cd xen.git
$ cp ../schedbench.git/controller/libxl.go tools/golang/xenlight/xenlight.go
$ git add tools/golang/xenlight/xenlight.go

:-)

Also, in this patch it looks from the description like you are
incrementally adding a bit of new functionality: but since you also at
the same time rename the file from "libxl.go" to "xenlight.go", it's
difficult to tell what's going on.  In the future, mechanical changes
(like renaming a file or code motion) should be kept separate from
patches that add or modify functionality, so that it's easy to see
what's going on.

Let me take a look at what you've got.

 -George


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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH RFC 13/59] Add GPL headers / COPYING file (v2 only)
  2016-12-29  1:14 ` [PATCH RFC 13/59] Add GPL headers / COPYING file (v2 only) Ronald Rojas
@ 2016-12-29 10:51   ` Wei Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Wei Liu @ 2016-12-29 10:51 UTC (permalink / raw)
  To: Ronald Rojas
  Cc: Wei Liu, George Dunlap, Ian Jackson, George Dunlap, xen-devel

On Wed, Dec 28, 2016 at 08:14:06PM -0500, Ronald Rojas wrote:
> From: George Dunlap <george.dunlap@citrix.com>
> 
> Signed-off-by: George Dunlap <george.dunlap@citrix.com>
> ---
>  benchmark.go     | 18 ++++++++++++++++++
>  main.go          | 19 +++++++++++++++++++
>  processworker.go | 18 ++++++++++++++++++
>  xenworker.go     | 18 ++++++++++++++++++
>  4 files changed, 73 insertions(+)
> 
> diff --git a/benchmark.go b/benchmark.go
> index ec62c3d..2a78d26 100644
> --- a/benchmark.go
> +++ b/benchmark.go
> @@ -1,3 +1,21 @@
> +/*
> + * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License only.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + * 
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */

Considering this library is likely to be linked with other code base,
maybe LGPL is better?

Wei.

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info
  2016-12-29 10:34   ` George Dunlap
@ 2016-12-29 10:52     ` Wei Liu
  2016-12-29 13:49       ` Ronald Rojas
  0 siblings, 1 reply; 67+ messages in thread
From: Wei Liu @ 2016-12-29 10:52 UTC (permalink / raw)
  To: George Dunlap
  Cc: Ronald Rojas, George Dunlap, Ian Jackson, Wei Liu, xen-devel

On Thu, Dec 29, 2016 at 10:34:34AM +0000, George Dunlap wrote:
> On 29/12/16 01:14, Ronald Rojas wrote:
> > Create interface to interact with libxl_verions_info
> > and libxl_physinfo. Also introduce proper error
> > handling.
> > 
> > Signed-off-by: Ronald Rojas <ronladred@gmail.com>
> 
> Hey Ronald,
> 
> When you send a series to a public open-source project, you want it to
> be a sort of idealized set of changes that make it easy to "see the
> forest for the trees", as it were, not the actual local development
> path.  We don't need the full development history of libxl.go -- a
> simple dump will be fine; and we definitely don't need all the other
> stuff from schedbench in the xen.git history. :-)
> 
> All you needed to do to "import" my existing libxl code from schedbench was:
> 
> $ cd xen.git
> $ cp ../schedbench.git/controller/libxl.go tools/golang/xenlight/xenlight.go
> $ git add tools/golang/xenlight/xenlight.go
> 

+1 for this.

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info
  2016-12-29  1:14 ` [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info Ronald Rojas
  2016-12-29 10:34   ` George Dunlap
@ 2016-12-29 13:45   ` George Dunlap
  2016-12-29 20:20     ` George Dunlap
  2017-01-03 17:45     ` Ronald Rojas
  1 sibling, 2 replies; 67+ messages in thread
From: George Dunlap @ 2016-12-29 13:45 UTC (permalink / raw)
  To: Ronald Rojas, xen-devel, Ian Jackson, Wei Liu, George Dunlap

Hey Ronald!  Looks like you're getting going pretty well here.

At a high level: I think I began by saying that this would probably all
be a single patch.  But I think it would probably be easier to review
the different decisions made at each point by filling out the file bit
by bit, and explaining what's going on at each point.

I think also it would be helpful to have somewhere -- either in a
comment or in a text file -- a description of the general approach to
converting the libxl C style into xenlight golang style.  For instance,
saying that for functions, we'll take the function name
(libxl_cpupool_remove), remove the libxl_ prefix (since the packages are
namespaced already) and convert it to CamelCase by capitalizing the first

I'll take a stab at breaking it down in an example order that makes some
sense to me, and then you can see what you think.

Futher comments...

On 29/12/16 01:14, Ronald Rojas wrote:
> diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
> new file mode 100644
> index 0000000..b0eb6f8
> --- /dev/null
> +++ b/tools/golang/xenlight/xenlight.go
> @@ -0,0 +1,1000 @@
> +/*
> + * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; version 2 of the
> + * License only.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */
> +package xenlight
> +
> +/*
> +#cgo LDFLAGS: -lxenlight -lyajl
> +#include <stdlib.h>
> +#include <libxl.h>
> +*/
> +import "C"

I see you switched back to dynamic linking -- any particular reason?

We probably need to put a "// FIXME" here saying that we need to
generate these compile-time dependencies using pkg-config.

> +
> +/*
> + * Other flags that may be needed at some point:
> + *  -lnl-route-3 -lnl-3
> +#cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
> + *
> + * To get back to simple dynamic linking:
> +*/

Comment needs updating (to "To use static linking").

> +
> +import (
> +	"fmt"
> +	"time"
> +	"unsafe"
> +)
> +
> +/*
> + * Errors
> + */
> +const (
> +	ErrorNonspecific                  = int(C.ERROR_NONSPECIFIC)
> +	ErrorVersion                      = int(C.ERROR_VERSION)
> +	ErrorFail                         = int(C.ERROR_FAIL)
> +	ErrorNi                           = int(C.ERROR_NI)
> +	ErrorNomem                        = int(C.ERROR_NOMEM)
> +	ErrorInval                        = int(C.ERROR_INVAL)
> +	ErrorBadfail                      = int(C.ERROR_BADFAIL)
> +	ErrorGuestTimedout                = int(C.ERROR_GUEST_TIMEDOUT)
> +	ErrorTimedout                     = int(C.ERROR_TIMEDOUT)
> +	ErrorNoparavirt                   = int(C.ERROR_NOPARAVIRT)
> +	ErrorNotReady                     = int(C.ERROR_NOT_READY)
> +	ErrorOseventRegFail               = int(C.ERROR_OSEVENT_REG_FAIL)
> +	ErrorBufferfull                   = int(C.ERROR_BUFFERFULL)
> +	ErrorUnknownChild                 = int(C.ERROR_UNKNOWN_CHILD)
> +	ErrorLockFail                     = int(C.ERROR_LOCK_FAIL)
> +	ErrorJsonConfigEmpty              = int(C.ERROR_JSON_CONFIG_EMPTY)
> +	ErrorDeviceExists                 = int(C.ERROR_DEVICE_EXISTS)
> +	ErrorCheckpointDevopsDoesNotMatch = int(C.ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH)
> +	ErrorCheckpointDeviceNotSupported = int(C.ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED)
> +	ErrorVnumaConfigInvalid           = int(C.ERROR_VNUMA_CONFIG_INVALID)
> +	ErrorDomainNotfound               = int(C.ERROR_DOMAIN_NOTFOUND)
> +	ErrorAborted                      = int(C.ERROR_ABORTED)
> +	ErrorNotfound                     = int(C.ERROR_NOTFOUND)
> +	ErrorDomainDestroyed              = int(C.ERROR_DOMAIN_DESTROYED)
> +	ErrorFeatureRemoved               = int(C.ERROR_FEATURE_REMOVED)
> +)

The problem with this at the moment is that we don't actually return any
of these errors -- instead we return a newly-generated error which
contains text.

This pair of blog posts describes some approaches taken by different
kinds of libraries to returning errors, and why:

https://www.goinggo.net/2014/10/error-handling-in-go-part-i.html
https://www.goinggo.net/2014/11/error-handling-in-go-part-ii.html

Another approach is taken by the go syscall package:

https://golang.org/pkg/syscall/#Errno

(See also https://golang.org/src/syscall/syscall_unix.go, lines 93-100,
and https://golang.org/src/syscall/zerrors_linux_amd64.go, at lines 1204
and 1381.)

The approach taken by libraries in the second blog allows you to pass
back a lot more information about what happened; but I think at the
moment, given the limited number of things that libxl returns, that's
probably overkill.

Which leaves us either taking the approach of something like bufio, and
making things like this:

const (
   ErrorNonspecific = errors.New("xenlight: Non-specific error")
   ...
)

Or taking the approach of the syscall package, and defining a type:

type xlerror int

func (e xlerror) Error() {

}

And making a (private) errors[] array, and re-impleminting Error() from
the syscall package.

I think I would probably go with the syscall library's approach, since
(like it) we are handed a set of pre-existing error numbers.

What do you think?

OK, there's more to look at but I think that's enough for now.

 -George


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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info
  2016-12-29 10:52     ` Wei Liu
@ 2016-12-29 13:49       ` Ronald Rojas
  0 siblings, 0 replies; 67+ messages in thread
From: Ronald Rojas @ 2016-12-29 13:49 UTC (permalink / raw)
  To: Wei Liu; +Cc: George Dunlap, Ian Jackson, George Dunlap, xen-devel

On Thu, Dec 29, 2016 at 10:52:42AM +0000, Wei Liu wrote:
> On Thu, Dec 29, 2016 at 10:34:34AM +0000, George Dunlap wrote:
> > On 29/12/16 01:14, Ronald Rojas wrote:
> > > Create interface to interact with libxl_verions_info
> > > and libxl_physinfo. Also introduce proper error
> > > handling.
> > > 
> > > Signed-off-by: Ronald Rojas <ronladred@gmail.com>
> > 
> > Hey Ronald,
> > 
> > When you send a series to a public open-source project, you want it to
> > be a sort of idealized set of changes that make it easy to "see the
> > forest for the trees", as it were, not the actual local development
> > path.  We don't need the full development history of libxl.go -- a
> > simple dump will be fine; and we definitely don't need all the other
> > stuff from schedbench in the xen.git history. :-)
> > 
> > All you needed to do to "import" my existing libxl code from schedbench was:
> > 
> > $ cd xen.git
> > $ cp ../schedbench.git/controller/libxl.go tools/golang/xenlight/xenlight.go
> > $ git add tools/golang/xenlight/xenlight.go

This is much easier then what I was doing. I did it another way 
because I thought you would have wanted to keep the git commit 
history. I can resubmit the patch into 2 commits so it'll be 
easier to read. 1 for importing the code from schedbench and 
then the changes that I made afterward. How does that sound?
> > 
> 
> +1 for this.

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info
  2016-12-29 13:45   ` George Dunlap
@ 2016-12-29 20:20     ` George Dunlap
  2017-01-03 17:45     ` Ronald Rojas
  1 sibling, 0 replies; 67+ messages in thread
From: George Dunlap @ 2016-12-29 20:20 UTC (permalink / raw)
  To: Ronald Rojas, xen-devel, Ian Jackson, Wei Liu, George Dunlap

[-- Attachment #1: Type: text/plain, Size: 803 bytes --]

On Thu, Dec 29, 2016 at 1:45 PM, George Dunlap <george.dunlap@citrix.com> wrote:
> At a high level: I think I began by saying that this would probably all
> be a single patch.  But I think it would probably be easier to review
> the different decisions made at each point by filling out the file bit
> by bit, and explaining what's going on at each point.

[snip]

> I'll take a stab at breaking it down in an example order that makes some
> sense to me, and then you can see what you think.

Here's one way you might break down this series that would make it
easier to review.

I've re-ordered the file somewhat, and there's a slight bug in the
build process so I can't compile it; and many of the descriptions need
to be expanded.  But it should give you the idea of what I'm talking
about.

 -George

[-- Attachment #2: 0001-tools-xenlight-Create-stub-package.patch --]
[-- Type: text/plain, Size: 4519 bytes --]

From c96a7c71c69c440fd87e77b5e11f7ecdf3263e83 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
Date: Thu, 29 Dec 2016 19:22:41 +0000
Subject: [PATCH 1/7] tools/xenlight: Create stub package

Create a basic Makefile to build and install libxenlight Golang
bindings.  Also add a stub package which only opens libxl context.

Include a global xenlight.Ctx variable which can be used as the
default context by the entire program if desired.

For now, return simple errors.  Proper error handling will be added in
the next patch.

Signed-off-by: Ronald Rojas <ronladred@gmail.com>
---
 tools/Makefile                    | 16 ++++++++
 tools/golang/Makefile             | 29 ++++++++++++++
 tools/golang/xenlight/xenlight.go | 80 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+)
 create mode 100644 tools/golang/Makefile
 create mode 100644 tools/golang/xenlight/xenlight.go

diff --git a/tools/Makefile b/tools/Makefile
index 77e0723..4c34421 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -12,6 +12,8 @@ SUBDIRS-y += misc
 SUBDIRS-y += examples
 SUBDIRS-y += hotplug
 SUBDIRS-y += xentrace
+SUBDIRS-y += golang
+#FIXME: Have golang controlled by a configure variable
 SUBDIRS-$(CONFIG_XCUTILS) += xcutils
 SUBDIRS-$(CONFIG_X86) += firmware
 SUBDIRS-y += console
@@ -312,6 +314,20 @@ subdir-install-debugger/gdbsx: .phony
 subdir-all-debugger/gdbsx: .phony
 	$(MAKE) -C debugger/gdbsx all
 
+subdir-all-golang/xenlight: .phony
+	$(MAKE) -C golang all
+
+subdir-clean-golang/xenlight: .phony
+	$(MAKE) -C golang clean
+
+subdir-install-golang/xenlight: .phony
+	$(MAKE) -C golang install
+
+subdir-build-golang/xenlight: .phony
+	$(MAKE) -C golang build
+
+subdir-distclean-golang/xenlight: .phony
+	$(MAKE) -C golang distclean
 
 subdir-clean-debugger/kdd subdir-distclean-debugger/kdd: .phony
 	$(MAKE) -C debugger/kdd clean
diff --git a/tools/golang/Makefile b/tools/golang/Makefile
new file mode 100644
index 0000000..96589c8
--- /dev/null
+++ b/tools/golang/Makefile
@@ -0,0 +1,29 @@
+XEN_ROOT=$(CURDIR)/../..
+GOLANG_SRC=$(GOPATH)/src/xenproject.org/xenlight
+include $(XEN_ROOT)/tools/Rules.mk
+
+BINARY = xenlight.a
+GO ?= go
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build: xenlight/xenlight.a
+
+.PHONY: install
+install: build
+	$(INSTALL_DIR) $(DESTDIR)$(GOLANG_SRC)
+	$(INSTALL_DATA) xenlight/xenlight.go $(DESTDIR)$(GOLANG_SRC)
+
+.PHONY: clean
+clean:
+	$(RM) xenlight/$(BINARY)
+
+.PHONY: distclean
+distclean: clean
+
+xenlight/xenlight.a: xenlight/xenlight.go
+	$(GO) build -o $@ $<
+
+-include $(DEPS)
diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
new file mode 100644
index 0000000..b162abb
--- /dev/null
+++ b/tools/golang/xenlight/xenlight.go
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+package xenlight
+
+/*
+#cgo LDFLAGS: -lxenlight -lyajl
+#include <stdlib.h>
+#include <libxl.h>
+*/
+import "C"
+
+import (
+	"fmt"
+	"time"
+	"unsafe"
+)
+
+/*
+ * Types: Builtins
+ */
+type Context struct {
+	ctx *C.libxl_ctx
+}
+
+/*
+ * Context
+ */
+var Ctx Context
+
+func (Ctx *Context) IsOpen() bool {
+	return Ctx.ctx != nil
+}
+
+func (Ctx *Context) Open() (err error) {
+	if Ctx.ctx != nil {
+		return
+	}
+
+	ret := C.libxl_ctx_alloc(unsafe.Pointer(&Ctx.ctx), C.LIBXL_VERSION, 0, nil)
+
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("Allocating libxl context: ", ret)
+	}
+	return
+}
+
+func (Ctx *Context) Close() (err error) {
+	ret := C.libxl_ctx_free(unsafe.Pointer(Ctx.ctx))
+	Ctx.ctx = nil
+
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("Freeing libxl context: ", ret)
+	}
+	return
+}
+
+func (Ctx *Context) CheckOpen() (err error) {
+	if Ctx.ctx == nil {
+		err = fmt.Errorf("Context not opened")
+	}
+	return
+}
-- 
2.1.4


[-- Attachment #3: 0002-tools-golang-Add-error-constants-and-standard-handli.patch --]
[-- Type: text/plain, Size: 4454 bytes --]

From b57339b6f42dd1997d8aef3580dfb7411a56a99f Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
Date: Thu, 29 Dec 2016 19:36:15 +0000
Subject: [PATCH 2/7] tools/golang: Add error constants and standard handling

You're going to change this so I won't bother writing a description -- write
here though a description of what the patch does and a brief account of why.
---
 tools/golang/xenlight/xenlight.go | 90 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index b162abb..677e5a5 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -32,6 +32,96 @@ import (
 )
 
 /*
+ * Errors
+ */
+const (
+	ErrorNonspecific                  = int(C.ERROR_NONSPECIFIC)
+	ErrorVersion                      = int(C.ERROR_VERSION)
+	ErrorFail                         = int(C.ERROR_FAIL)
+	ErrorNi                           = int(C.ERROR_NI)
+	ErrorNomem                        = int(C.ERROR_NOMEM)
+	ErrorInval                        = int(C.ERROR_INVAL)
+	ErrorBadfail                      = int(C.ERROR_BADFAIL)
+	ErrorGuestTimedout                = int(C.ERROR_GUEST_TIMEDOUT)
+	ErrorTimedout                     = int(C.ERROR_TIMEDOUT)
+	ErrorNoparavirt                   = int(C.ERROR_NOPARAVIRT)
+	ErrorNotReady                     = int(C.ERROR_NOT_READY)
+	ErrorOseventRegFail               = int(C.ERROR_OSEVENT_REG_FAIL)
+	ErrorBufferfull                   = int(C.ERROR_BUFFERFULL)
+	ErrorUnknownChild                 = int(C.ERROR_UNKNOWN_CHILD)
+	ErrorLockFail                     = int(C.ERROR_LOCK_FAIL)
+	ErrorJsonConfigEmpty              = int(C.ERROR_JSON_CONFIG_EMPTY)
+	ErrorDeviceExists                 = int(C.ERROR_DEVICE_EXISTS)
+	ErrorCheckpointDevopsDoesNotMatch = int(C.ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH)
+	ErrorCheckpointDeviceNotSupported = int(C.ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED)
+	ErrorVnumaConfigInvalid           = int(C.ERROR_VNUMA_CONFIG_INVALID)
+	ErrorDomainNotfound               = int(C.ERROR_DOMAIN_NOTFOUND)
+	ErrorAborted                      = int(C.ERROR_ABORTED)
+	ErrorNotfound                     = int(C.ERROR_NOTFOUND)
+	ErrorDomainDestroyed              = int(C.ERROR_DOMAIN_DESTROYED)
+	ErrorFeatureRemoved               = int(C.ERROR_FEATURE_REMOVED)
+)
+
+func createError(method string, cerrNum C.int) (err error) {
+	method += " %s"
+	errNum := int(cerrNum)
+	switch errNum {
+	case ErrorNonspecific:
+		err = fmt.Errorf(method, "ERROR_NONSPECIFIC")
+	case ErrorVersion:
+		err = fmt.Errorf(method, "ERROR_VERSION")
+	case ErrorFail:
+		err = fmt.Errorf(method, "ERROR_FAIL")
+	case ErrorNi:
+		err = fmt.Errorf(method, "ERROR_NI")
+	case ErrorNomem:
+		err = fmt.Errorf(method, "ERROR_NOMEM")
+	case ErrorInval:
+		err = fmt.Errorf(method, "ERROR_INVAL")
+	case ErrorBadfail:
+		err = fmt.Errorf(method, "ERROR_BADFAIL")
+	case ErrorGuestTimedout:
+		err = fmt.Errorf(method, "ERROR_GUEST_TIMEDOUT")
+	case ErrorNoparavirt:
+		err = fmt.Errorf(method, "ERROR_NOPARAVIRT")
+	case ErrorNotReady:
+		err = fmt.Errorf(method, "ERROR_NOT_READY")
+	case ErrorOseventRegFail:
+		err = fmt.Errorf(method, "ERROR_OSEVENT_REG_FAIL")
+	case ErrorBufferfull:
+		err = fmt.Errorf(method, "ERROR_BUFFERFULL")
+	case ErrorUnknownChild:
+		err = fmt.Errorf(method, "ERROR_UNKNOWN_CHILD")
+	case ErrorLockFail:
+		err = fmt.Errorf(method, "ERROR_LOCK_FAIL")
+	case ErrorJsonConfigEmpty:
+		err = fmt.Errorf(method, "ERROR_JSON_CONFIG_EMPTY")
+	case ErrorDeviceExists:
+		err = fmt.Errorf(method, "ERROR_DEVICE_EXISTS")
+	case ErrorCheckpointDevopsDoesNotMatch:
+		err = fmt.Errorf(method, "ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH")
+	case ErrorCheckpointDeviceNotSupported:
+		err = fmt.Errorf(method, "ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED")
+	case ErrorVnumaConfigInvalid:
+		err = fmt.Errorf(method, "ERROR_VNUMA_CONFIG_INVALID")
+	case ErrorDomainNotfound:
+		err = fmt.Errorf(method, "ERROR_DOMAIN_NOTFOUND")
+	case ErrorAborted:
+		err = fmt.Errorf(method, "ERROR_ABORTED")
+	case ErrorNotfound:
+		err = fmt.Errorf(method, "ERROR_NOTFOUND")
+	case ErrorDomainDestroyed:
+		err = fmt.Errorf(method, "ERROR_DOMAIN_DESTROYED")
+	case ErrorFeatureRemoved:
+		err = fmt.Errorf(method, "ERROR_FEATURE_REMOVED")
+	default:
+		err = fmt.Errorf(method, "error not found")
+	}
+	return
+
+}
+
+/*
  * Types: Builtins
  */
 type Context struct {
-- 
2.1.4


[-- Attachment #4: 0003-tools-golang-xenlight-Add-host-related-functionality.patch --]
[-- Type: text/plain, Size: 5834 bytes --]

From 1012318772396a2e4219c9ffa4c57ccd443f42a1 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
Date: Thu, 29 Dec 2016 19:49:02 +0000
Subject: [PATCH 3/7] tools/golang/xenlight: Add host-related functionality

Add calls for the following host-related functionality:
- libxl_get_max_cpus
- libxl_get_online_cpus
- libxl_get_max_nodes
- libxl_get_free_memory
- libxl_get_physinfo
- libxl_get_version_info

And include golang versions of the following structs:
 - libxl_physinfo
 - libxl_version_info
 - libxl_hwcap
---
 tools/golang/xenlight/xenlight.go | 193 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 193 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index 677e5a5..05604c7 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -128,6 +128,68 @@ type Context struct {
 	ctx *C.libxl_ctx
 }
 
+type Hwcap struct {
+	Hwcap []C.uint32_t
+}
+
+func hwcapCToGo(chwcap C.libxl_hwcap) (ghwcap Hwcap) {
+	// Alloc a Go slice for the bytes
+	size := 8
+	ghwcap.Hwcap = make([]C.uint32_t, size)
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint32_t)(unsafe.Pointer(&chwcap[0]))[:size:size]
+
+	// And copy the C array into the Go array
+	copy(ghwcap.Hwcap, mapslice)
+
+	return
+}
+
+/*
+ * Types: IDL
+ *
+ * FIXME: Generate these automatically from the IDL
+ */
+type Physinfo struct {
+	Threads_per_core uint32
+	Cores_per_socket uint32
+
+	Max_cpu_id uint32
+	Nr_cpus    uint32
+	Cpu_khz    uint32
+
+	Total_pages         uint64
+	Free_pages          uint64
+	Scrub_pages         uint64
+	Outstanding_pages   uint64
+	Sharing_freed_pages uint64
+	Sharing_used_frames uint64
+
+	Nr_nodes uint32
+	Hw_cap   Hwcap
+
+	Cap_hvm          bool
+	Cap_hvm_directio bool
+}
+
+type VersionInfo struct {
+	Xen_version_major int
+	Xen_version_minor int
+	Xen_version_extra string
+	Compiler          string
+	Compile_by        string
+	Compile_domain    string
+	Compile_date      string
+	Capabilities      string
+	Changeset         string
+	Virt_start        uint64
+	Pagesize          int
+	Commandline       string
+	Build_id          string
+}
+
+
 /*
  * Context
  */
@@ -168,3 +230,134 @@ func (Ctx *Context) CheckOpen() (err error) {
 	}
 	return
 }
+
+//int libxl_get_max_cpus(libxl_ctx *ctx);
+func (Ctx *Context) GetMaxCpus() (maxCpus int, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_get_max_cpus(Ctx.ctx)
+	//FIXME: proper error
+	if ret < 0 {
+		err = createError("libxl_get_max_cpus failed: ", ret)
+		return
+	}
+	maxCpus = int(ret)
+	return
+}
+
+//int libxl_get_online_cpus(libxl_ctx *ctx);
+func (Ctx *Context) GetOnlineCpus() (onCpus int, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_get_online_cpus(Ctx.ctx)
+	//FIXME: proper error
+	if ret < 0 {
+		err = createError("libxl_get_online_cpus failed: ", ret)
+		return
+	}
+	onCpus = int(ret)
+	return
+}
+
+//int libxl_get_max_nodes(libxl_ctx *ctx);
+func (Ctx *Context) GetMaxNodes() (maxNodes int, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+	ret := C.libxl_get_max_nodes(Ctx.ctx)
+	//FIXME: proper error
+	if ret < 0 {
+		err = createError("libxl_get_max_nodes failed: ", ret)
+		return
+	}
+	maxNodes = int(ret)
+	return
+}
+
+//int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb);
+func (Ctx *Context) GetFreeMemory() (memkb uint64, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+	var cmem C.uint64_t
+	ret := C.libxl_get_free_memory(Ctx.ctx, &cmem)
+
+	if ret < 0 {
+		err = createError("libxl_get_free_memory failed: ", ret)
+		return
+	}
+
+	memkb = uint64(ret)
+	return
+
+}
+
+//int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
+func (Ctx *Context) GetPhysinfo() (physinfo *Physinfo, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+	var cphys C.libxl_physinfo
+
+	ret := C.libxl_get_physinfo(Ctx.ctx, &cphys)
+
+	//FIXME: proper error
+	if ret < 0 {
+		err = createError("libxl_get_physinfo failed: ", ret)
+		return
+	}
+	physinfo = &Physinfo{}
+	physinfo.Threads_per_core = uint32(cphys.threads_per_core)
+	physinfo.Cores_per_socket = uint32(cphys.cores_per_socket)
+	physinfo.Max_cpu_id = uint32(cphys.max_cpu_id)
+	physinfo.Nr_cpus = uint32(cphys.nr_cpus)
+	physinfo.Cpu_khz = uint32(cphys.cpu_khz)
+	physinfo.Total_pages = uint64(cphys.total_pages)
+	physinfo.Free_pages = uint64(cphys.free_pages)
+	physinfo.Scrub_pages = uint64(cphys.scrub_pages)
+	physinfo.Outstanding_pages = uint64(cphys.scrub_pages)
+	physinfo.Sharing_freed_pages = uint64(cphys.sharing_freed_pages)
+	physinfo.Sharing_used_frames = uint64(cphys.sharing_used_frames)
+	physinfo.Nr_nodes = uint32(cphys.nr_nodes)
+	physinfo.Hw_cap = hwcapCToGo(cphys.hw_cap)
+	physinfo.Cap_hvm = bool(cphys.cap_hvm)
+	physinfo.Cap_hvm_directio = bool(cphys.cap_hvm_directio)
+
+	return
+}
+
+//const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx);
+func (Ctx *Context) GetVersionInfo() (info *VersionInfo, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var cinfo *C.libxl_version_info
+
+	cinfo = C.libxl_get_version_info(Ctx.ctx)
+
+	info = &VersionInfo{}
+	info.Xen_version_major = int(cinfo.xen_version_major)
+	info.Xen_version_minor = int(cinfo.xen_version_minor)
+	info.Xen_version_extra = C.GoString(cinfo.xen_version_extra)
+	info.Compiler = C.GoString(cinfo.compiler)
+	info.Compile_by = C.GoString(cinfo.compile_by)
+	info.Compile_domain = C.GoString(cinfo.compile_domain)
+	info.Compile_date = C.GoString(cinfo.compile_date)
+	info.Capabilities = C.GoString(cinfo.capabilities)
+	info.Changeset = C.GoString(cinfo.changeset)
+	info.Virt_start = uint64(cinfo.virt_start)
+	info.Pagesize = int(cinfo.pagesize)
+
+	return
+}
-- 
2.1.4


[-- Attachment #5: 0004-golang-xenlight-Implement-libxl_get_gomainfinfo-and-.patch --]
[-- Type: text/plain, Size: 3311 bytes --]

From dcadedf83b219755994af123e2ee0ec49db85445 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
Date: Thu, 29 Dec 2016 19:54:10 +0000
Subject: [PATCH 4/7] golang/xenlight: Implement libxl_get_gomainfinfo and
 libxl_domain_unpause

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 tools/golang/xenlight/xenlight.go | 91 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index 05604c7..96a6952 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -124,6 +124,12 @@ func createError(method string, cerrNum C.int) (err error) {
 /*
  * Types: Builtins
  */
+type Domid uint32
+
+type MemKB uint64
+
+type Uuid C.libxl_uuid
+
 type Context struct {
 	ctx *C.libxl_ctx
 }
@@ -189,6 +195,29 @@ type VersionInfo struct {
 	Build_id          string
 }
 
+type Dominfo struct {
+	Uuid       Uuid
+	Domid      Domid
+	Running    bool
+	Blocked    bool
+	Paused     bool
+	Shutdown   bool
+	Dying      bool
+	Never_stop bool
+
+	Shutdown_reason   int32 // FIXME shutdown_reason enumeration
+	Outstanding_memkb MemKB
+	Current_memkb     MemKB
+	Shared_memkb      MemKB
+	Paged_memkb       MemKB
+	Max_memkb         MemKB
+	Cpu_time          time.Duration
+	Vcpu_max_id       uint32
+	Vcpu_online       uint32
+	Cpupool           uint32
+	Domain_type       int32 //FIXME libxl_domain_type enumeration
+
+}
 
 /*
  * Context
@@ -361,3 +390,65 @@ func (Ctx *Context) GetVersionInfo() (info *VersionInfo, err error) {
 
 	return
 }
+
+//int libxl_domain_info(libxl_ctx*, libxl_dominfo *info_r, uint32_t domid);
+func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var cdi C.libxl_dominfo
+
+	ret := C.libxl_domain_info(Ctx.ctx, unsafe.Pointer(&cdi), C.uint32_t(Id))
+
+	// FIXME: proper error
+	if ret != 0 {
+		err = createError("libxl_domain_info failed: ", ret)
+		return
+	}
+
+	// We could consider having this boilerplate generated by the
+	// idl, in a function like this:
+	//
+	// di = translateCdomaininfoToGoDomaininfo(cdi)
+	di = &Dominfo{}
+	di.Uuid = Uuid(cdi.uuid)
+	di.Domid = Domid(cdi.domid)
+	di.Running = bool(cdi.running)
+	di.Blocked = bool(cdi.blocked)
+	di.Paused = bool(cdi.paused)
+	di.Shutdown = bool(cdi.shutdown)
+	di.Dying = bool(cdi.dying)
+	di.Never_stop = bool(cdi.never_stop)
+	di.Shutdown_reason = int32(cdi.shutdown_reason)
+	di.Outstanding_memkb = MemKB(cdi.outstanding_memkb)
+	di.Current_memkb = MemKB(cdi.current_memkb)
+	di.Shared_memkb = MemKB(cdi.shared_memkb)
+	di.Paged_memkb = MemKB(cdi.paged_memkb)
+	di.Max_memkb = MemKB(cdi.max_memkb)
+	di.Cpu_time = time.Duration(cdi.cpu_time)
+	di.Vcpu_max_id = uint32(cdi.vcpu_max_id)
+	di.Vcpu_online = uint32(cdi.vcpu_online)
+	di.Cpupool = uint32(cdi.cpupool)
+	di.Domain_type = int32(cdi.domain_type)
+
+	return
+}
+
+//int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid);
+func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_domain_unpause(Ctx.ctx, C.uint32_t(Id))
+
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("libxl_domain_unpause failed: ", ret)
+	}
+	return
+}
+
-- 
2.1.4


[-- Attachment #6: 0005-golang-xenlight-Implement-libxl_bitmap-and-helper-op.patch --]
[-- Type: text/plain, Size: 4713 bytes --]

From 36ea15d6175781c48afee71c0fc4c2ca99f7e084 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
Date: Thu, 29 Dec 2016 20:01:27 +0000
Subject: [PATCH 5/7] golang/xenlight: Implement libxl_bitmap and helper
 operations

Implement Bitmap type, along with helper operations.

The Bitmap type is implemented internally in a way which makes it easy
to copy into and outof the C libxl_bitmap type.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 tools/golang/xenlight/xenlight.go | 167 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 167 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index 96a6952..b1384b0 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -152,6 +152,20 @@ func hwcapCToGo(chwcap C.libxl_hwcap) (ghwcap Hwcap) {
 	return
 }
 
+// typedef struct {
+//     uint32_t size;          /* number of bytes in map */
+//     uint8_t *map;
+// } libxl_bitmap;
+
+// Implement the Go bitmap type such that the underlying data can
+// easily be copied in and out.  NB that we still have to do copies
+// both directions, because cgo runtime restrictions forbid passing to
+// a C function a pointer to a Go-allocated structure which contains a
+// pointer.
+type Bitmap struct {
+	bitmap []C.uint8_t
+}
+
 /*
  * Types: IDL
  *
@@ -220,6 +234,159 @@ type Dominfo struct {
 }
 
 /*
+ * Bitmap operations
+ */
+
+// Return a Go bitmap which is a copy of the referred C bitmap.
+func bitmapCToGo(cbm C.libxl_bitmap) (gbm Bitmap) {
+	// Alloc a Go slice for the bytes
+	size := int(cbm.size)
+	gbm.bitmap = make([]C.uint8_t, size)
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+	// And copy the C array into the Go array
+	copy(gbm.bitmap, mapslice)
+
+	return
+}
+
+// Must be C.libxl_bitmap_dispose'd of afterwards
+func bitmapGotoC(gbm Bitmap) (cbm C.libxl_bitmap) {
+	C.libxl_bitmap_init(&cbm)
+
+	size := len(gbm.bitmap)
+	cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
+	cbm.size = C.uint32_t(size)
+	if cbm._map == nil {
+		panic("C.calloc failed!")
+	}
+
+	// Make a slice pointing to the C array
+	mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+	// And copy the Go array into the C array
+	copy(mapslice, gbm.bitmap)
+
+	return
+}
+
+func (bm *Bitmap) Test(bit int) bool {
+	ubit := uint(bit)
+	if bit > bm.Max() || bm.bitmap == nil {
+		return false
+	}
+
+	return (bm.bitmap[bit/8] & (1 << (ubit & 7))) != 0
+}
+
+func (bm *Bitmap) Set(bit int) {
+	ibit := bit / 8
+	if ibit+1 > len(bm.bitmap) {
+		bm.bitmap = append(bm.bitmap, make([]C.uint8_t, ibit+1-len(bm.bitmap))...)
+	}
+
+	bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
+}
+
+func (bm *Bitmap) SetRange(start int, end int) {
+	for i := start; i <= end; i++ {
+		bm.Set(i)
+	}
+}
+
+func (bm *Bitmap) Clear(bit int) {
+	ubit := uint(bit)
+	if bit > bm.Max() || bm.bitmap == nil {
+		return
+	}
+
+	bm.bitmap[bit/8] &= ^(1 << (ubit & 7))
+}
+
+func (bm *Bitmap) ClearRange(start int, end int) {
+	for i := start; i <= end; i++ {
+		bm.Clear(i)
+	}
+}
+
+func (bm *Bitmap) Max() int {
+	return len(bm.bitmap)*8 - 1
+}
+
+func (bm *Bitmap) IsEmpty() bool {
+	for i := 0; i < len(bm.bitmap); i++ {
+		if bm.bitmap[i] != 0 {
+			return false
+		}
+	}
+	return true
+}
+
+func (a Bitmap) And(b Bitmap) (c Bitmap) {
+	var max, min int
+	if len(a.bitmap) > len(b.bitmap) {
+		max = len(a.bitmap)
+		min = len(b.bitmap)
+	} else {
+		max = len(b.bitmap)
+		min = len(a.bitmap)
+	}
+	c.bitmap = make([]C.uint8_t, max)
+
+	for i := 0; i < min; i++ {
+		c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
+	}
+	return
+}
+
+func (bm Bitmap) String() (s string) {
+	lastOnline := false
+	crange := false
+	printed := false
+	var i int
+	/// --x-xxxxx-x -> 2,4-8,10
+	/// --x-xxxxxxx -> 2,4-10
+	for i = 0; i <= bm.Max(); i++ {
+		if bm.Test(i) {
+			if !lastOnline {
+				// Switching offline -> online, print this cpu
+				if printed {
+					s += ","
+				}
+				s += fmt.Sprintf("%d", i)
+				printed = true
+			} else if !crange {
+				// last was online, but we're not in a range; print -
+				crange = true
+				s += "-"
+			} else {
+				// last was online, we're in a range,  nothing else to do
+			}
+			lastOnline = true
+		} else {
+			if lastOnline {
+				// Switching online->offline; do we need to end a range?
+				if crange {
+					s += fmt.Sprintf("%d", i-1)
+				}
+			}
+			lastOnline = false
+			crange = false
+		}
+	}
+	if lastOnline {
+		// Switching online->offline; do we need to end a range?
+		if crange {
+			s += fmt.Sprintf("%d", i-1)
+		}
+	}
+
+	return
+}
+
+/*
  * Context
  */
 var Ctx Context
-- 
2.1.4


[-- Attachment #7: 0006-golang-xenlight-Implement-libxl_scheduler-enumeratio.patch --]
[-- Type: text/plain, Size: 2429 bytes --]

From 272e37b66bfc206c5da5acb6772df8eb4e16e9d2 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
Date: Thu, 29 Dec 2016 20:04:20 +0000
Subject: [PATCH 6/7] golang/xenlight: Implement libxl_scheduler enumeration

Include both constants and a Stringification.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 tools/golang/xenlight/xenlight.go | 63 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index b1384b0..31ce365 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -233,6 +233,69 @@ type Dominfo struct {
 
 }
 
+// # Consistent with values defined in domctl.h
+// # Except unknown which we have made up
+// libxl_scheduler = Enumeration("scheduler", [
+//     (0, "unknown"),
+//     (4, "sedf"),
+//     (5, "credit"),
+//     (6, "credit2"),
+//     (7, "arinc653"),
+//     (8, "rtds"),
+//     ])
+type Scheduler int
+
+var (
+	SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
+	SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
+	SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
+	SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
+	SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
+	SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
+)
+
+// const char *libxl_scheduler_to_string(libxl_scheduler p);
+func (s Scheduler) String() string {
+	cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
+	// No need to free const return value
+
+	return C.GoString(cs)
+}
+
+// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
+func (s *Scheduler) FromString(gstr string) (err error) {
+	cstr := C.CString(gstr)
+	defer C.free(unsafe.Pointer(cstr))
+
+	var cs C.libxl_scheduler
+	ret := C.libxl_scheduler_from_string(cstr, &cs)
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("libxl_scheduler_from_string: ", ret)
+		return
+	}
+
+	*s = Scheduler(cs)
+	return
+}
+
+func SchedulerFromString(name string) (s Scheduler, err error) {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+
+	var cs C.libxl_scheduler
+
+	ret := C.libxl_scheduler_from_string(cname, &cs)
+	if ret != 0 {
+		//FIXME: proper error
+		err = createError("libxl_scheduler_from_string failed: ", ret)
+		return
+	}
+
+	s = Scheduler(cs)
+
+	return
+}
 /*
  * Bitmap operations
  */
-- 
2.1.4


[-- Attachment #8: 0007-golang-xenlight-Implement-cpupool-operations.patch --]
[-- Type: text/plain, Size: 7508 bytes --]

From 5325d67694900fe38a35a755bd0048020164cb31 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
Date: Thu, 29 Dec 2016 20:08:44 +0000
Subject: [PATCH 7/7] golang/xenlight: Implement cpupool operations

Also include some useful "Utility" functions:
 - CpupoolFindByName
 - CpupoolMakeFree

Still need to implement the following functions:
 libxl_cpupool_rename
 libxl_cpupool_cpuadd_node
 libxl_cpupool_cpuremove_node
 libxl_cpupool_movedomain

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
 tools/golang/xenlight/xenlight.go | 244 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 244 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index 31ce365..e3d69ca 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -233,6 +233,32 @@ type Dominfo struct {
 
 }
 
+// libxl_cpupoolinfo = Struct("cpupoolinfo", [
+//     ("poolid",      uint32),
+//     ("pool_name",   string),
+//     ("sched",       libxl_scheduler),
+//     ("n_dom",       uint32),
+//     ("cpumap",      libxl_bitmap)
+//     ], dir=DIR_OUT)
+
+type CpupoolInfo struct {
+	Poolid      uint32
+	PoolName    string
+	Scheduler   Scheduler
+	DomainCount int
+	Cpumap      Bitmap
+}
+
+func translateCpupoolInfoCToGo(cci C.libxl_cpupoolinfo) (gci CpupoolInfo) {
+	gci.Poolid = uint32(cci.poolid)
+	gci.PoolName = C.GoString(cci.pool_name)
+	gci.Scheduler = Scheduler(cci.sched)
+	gci.DomainCount = int(cci.n_dom)
+	gci.Cpumap = bitmapCToGo(cci.cpumap)
+
+	return
+}
+
 // # Consistent with values defined in domctl.h
 // # Except unknown which we have made up
 // libxl_scheduler = Enumeration("scheduler", [
@@ -296,6 +322,7 @@ func SchedulerFromString(name string) (s Scheduler, err error) {
 
 	return
 }
+
 /*
  * Bitmap operations
  */
@@ -682,3 +709,220 @@ func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
 	return
 }
 
+// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
+// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
+func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
+	err := Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var nbPool C.int
+
+	c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
+
+	defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
+
+	if int(nbPool) == 0 {
+		return
+	}
+
+	// Magic
+	cpupoolListSlice := (*[1 << 30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
+
+	for i := range cpupoolListSlice {
+		info := translateCpupoolInfoCToGo(cpupoolListSlice[i])
+
+		list = append(list, info)
+	}
+
+	return
+}
+
+// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t poolid);
+func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo) {
+	err := Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	var c_cpupool C.libxl_cpupoolinfo
+
+	ret := C.libxl_cpupool_info(Ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
+	//FIXME: proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_info failed: ", ret)
+		return
+	}
+	defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
+
+	pool = translateCpupoolInfoCToGo(c_cpupool)
+
+	return
+}
+
+// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
+//                          libxl_scheduler sched,
+//                          libxl_bitmap cpumap, libxl_uuid *uuid,
+//                          uint32_t *poolid);
+// FIXME: uuid
+// FIXME: Setting poolid
+func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap Bitmap) (err error, Poolid uint32) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	poolid := C.uint32_t(0)
+	name := C.CString(Name)
+	defer C.free(unsafe.Pointer(name))
+
+	// For now, just do what xl does, and make a new uuid every time we create the pool
+	var uuid C.libxl_uuid
+	C.libxl_uuid_generate(&uuid)
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+
+	ret := C.libxl_cpupool_create(Ctx.ctx, name, C.libxl_scheduler(Scheduler),
+		cbm, &uuid, &poolid)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_create failed: ", ret)
+		return
+	}
+
+	Poolid = uint32(poolid)
+
+	return
+}
+
+// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
+func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_destroy failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
+func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_cpuadd failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                 const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+
+	ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_cpuadd_cpumap failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
+func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_cpuremove failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                    const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err error) {
+	err = Ctx.CheckOpen()
+	if err != nil {
+		return
+	}
+
+	cbm := bitmapGotoC(Cpumap)
+	defer C.libxl_bitmap_dispose(&cbm)
+
+	ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+	// FIXME: Proper error
+	if ret != 0 {
+		err = createError("libxl_cpupool_cpuremove_cpumap failed: ", ret)
+		return
+	}
+
+	return
+}
+
+// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
+// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus);
+// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid);
+
+//
+// Utility functions
+//
+func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found bool) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		if plist[i].PoolName == name {
+			found = true
+			info = plist[i]
+			return
+		}
+	}
+	return
+}
+
+func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
+	plist := Ctx.ListCpupool()
+
+	for i := range plist {
+		var Intersection Bitmap
+		Intersection = Cpumap.And(plist[i].Cpumap)
+		if !Intersection.IsEmpty() {
+			err = Ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, Intersection)
+			if err != nil {
+				return
+			}
+		}
+	}
+	return
+}
-- 
2.1.4


[-- Attachment #9: Type: text/plain, Size: 127 bytes --]

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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info
  2016-12-29 13:45   ` George Dunlap
  2016-12-29 20:20     ` George Dunlap
@ 2017-01-03 17:45     ` Ronald Rojas
  2017-01-04 16:44       ` George Dunlap
  1 sibling, 1 reply; 67+ messages in thread
From: Ronald Rojas @ 2017-01-03 17:45 UTC (permalink / raw)
  To: George Dunlap; +Cc: Wei Liu, George Dunlap, Ian Jackson, xen-devel

[-- Attachment #1: Type: text/plain, Size: 8159 bytes --]

On Thu, Dec 29, 2016 at 01:45:54PM +0000, George Dunlap wrote:
> Hey Ronald!  Looks like you're getting going pretty well here.
> 
> At a high level: I think I began by saying that this would probably all
> be a single patch.  But I think it would probably be easier to review
> the different decisions made at each point by filling out the file bit
> by bit, and explaining what's going on at each point.
> 
> I think also it would be helpful to have somewhere -- either in a
> comment or in a text file -- a description of the general approach to
> converting the libxl C style into xenlight golang style.  For instance,
> saying that for functions, we'll take the function name
> (libxl_cpupool_remove), remove the libxl_ prefix (since the packages are
> namespaced already) and convert it to CamelCase by capitalizing the first
> 
> I'll take a stab at breaking it down in an example order that makes some
> sense to me, and then you can see what you think.

I made some guidelines that I think would nicely adjust the naming convention
from C to Go. I'll add it as a file below.
> 
> Futher comments...
> 
> On 29/12/16 01:14, Ronald Rojas wrote:
> > diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
> > new file mode 100644
> > index 0000000..b0eb6f8
> > --- /dev/null
> > +++ b/tools/golang/xenlight/xenlight.go
> > @@ -0,0 +1,1000 @@
> > +/*
> > + * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation; version 2 of the
> > + * License only.
> > + *
> > + * This program is distributed in the hope that it will be useful, but
> > + * WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > + * 02110-1301, USA.
> > + */
> > +package xenlight
> > +
> > +/*
> > +#cgo LDFLAGS: -lxenlight -lyajl
> > +#include <stdlib.h>
> > +#include <libxl.h>
> > +*/
> > +import "C"
> 
> I see you switched back to dynamic linking -- any particular reason?
> 
> We probably need to put a "// FIXME" here saying that we need to
> generate these compile-time dependencies using pkg-config.

We discussed this on IRC but I'll just restate here that I was not able 
to compile the program through static linking and it would be fine to 
just use dynamic linking for now.
Since we are doing dynamic linking do we still need to use pkg-config?
> 
> > +
> > +/*
> > + * Other flags that may be needed at some point:
> > + *  -lnl-route-3 -lnl-3
> > +#cgo LDFLAGS: -lxenlight -lyajl_s -lxengnttab -lxenstore -lxenguest -lxentoollog -lxenevtchn -lxenctrl -lblktapctl -lxenforeignmemory -lxencall -lz -luuid -lutil
> > + *
> > + * To get back to simple dynamic linking:
> > +*/
> 
> Comment needs updating (to "To use static linking").

Fixed.
> 
> > +
> > +import (
> > +	"fmt"
> > +	"time"
> > +	"unsafe"
> > +)
> > +
> > +/*
> > + * Errors
> > + */
> > +const (
> > +	ErrorNonspecific                  = int(C.ERROR_NONSPECIFIC)
> > +	ErrorVersion                      = int(C.ERROR_VERSION)
> > +	ErrorFail                         = int(C.ERROR_FAIL)
> > +	ErrorNi                           = int(C.ERROR_NI)
> > +	ErrorNomem                        = int(C.ERROR_NOMEM)
> > +	ErrorInval                        = int(C.ERROR_INVAL)
> > +	ErrorBadfail                      = int(C.ERROR_BADFAIL)
> > +	ErrorGuestTimedout                = int(C.ERROR_GUEST_TIMEDOUT)
> > +	ErrorTimedout                     = int(C.ERROR_TIMEDOUT)
> > +	ErrorNoparavirt                   = int(C.ERROR_NOPARAVIRT)
> > +	ErrorNotReady                     = int(C.ERROR_NOT_READY)
> > +	ErrorOseventRegFail               = int(C.ERROR_OSEVENT_REG_FAIL)
> > +	ErrorBufferfull                   = int(C.ERROR_BUFFERFULL)
> > +	ErrorUnknownChild                 = int(C.ERROR_UNKNOWN_CHILD)
> > +	ErrorLockFail                     = int(C.ERROR_LOCK_FAIL)
> > +	ErrorJsonConfigEmpty              = int(C.ERROR_JSON_CONFIG_EMPTY)
> > +	ErrorDeviceExists                 = int(C.ERROR_DEVICE_EXISTS)
> > +	ErrorCheckpointDevopsDoesNotMatch = int(C.ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH)
> > +	ErrorCheckpointDeviceNotSupported = int(C.ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED)
> > +	ErrorVnumaConfigInvalid           = int(C.ERROR_VNUMA_CONFIG_INVALID)
> > +	ErrorDomainNotfound               = int(C.ERROR_DOMAIN_NOTFOUND)
> > +	ErrorAborted                      = int(C.ERROR_ABORTED)
> > +	ErrorNotfound                     = int(C.ERROR_NOTFOUND)
> > +	ErrorDomainDestroyed              = int(C.ERROR_DOMAIN_DESTROYED)
> > +	ErrorFeatureRemoved               = int(C.ERROR_FEATURE_REMOVED)
> > +)
> 
> The problem with this at the moment is that we don't actually return any
> of these errors -- instead we return a newly-generated error which
> contains text.
> 
> This pair of blog posts describes some approaches taken by different
> kinds of libraries to returning errors, and why:
> 
> https://www.goinggo.net/2014/10/error-handling-in-go-part-i.html
> https://www.goinggo.net/2014/11/error-handling-in-go-part-ii.html
> 
> Another approach is taken by the go syscall package:
> 
> https://golang.org/pkg/syscall/#Errno
> 
> (See also https://golang.org/src/syscall/syscall_unix.go, lines 93-100,
> and https://golang.org/src/syscall/zerrors_linux_amd64.go, at lines 1204
> and 1381.)
> 
> The approach taken by libraries in the second blog allows you to pass
> back a lot more information about what happened; but I think at the
> moment, given the limited number of things that libxl returns, that's
> probably overkill.
> 
> Which leaves us either taking the approach of something like bufio, and
> making things like this:
> 
> const (
>    ErrorNonspecific = errors.New("xenlight: Non-specific error")
>    ...
> )
> 
> Or taking the approach of the syscall package, and defining a type:
> 
> type xlerror int
> 
> func (e xlerror) Error() {
> 
> }
> 
> And making a (private) errors[] array, and re-impleminting Error() from
> the syscall package.
> 
> I think I would probably go with the syscall library's approach, since
> (like it) we are handed a set of pre-existing error numbers.
> 
> What do you think?

I was actually thinking that taking the approach similiar to bufio would
be better. It would not be difficult to create individual errors for each
error number and creating variables for each error would allow users to 
easily compare the error that's returned against specific errors. 

I've also been thinking about how to do the testing and I think it would
be good to seperate testing into two parts, testing functions that get
infomation about the system and functions that change the state of the 
system. 

I haven't been able to figure out how to use osstest to use the
Golang libxl but I think it would still be fine to do unit testing by
writing C and Go code that get information from a specific fuction(like
physinfo) and seeing if they produce the same output.

For functions that change the state of the system (like create/destroy
guests) I think your idea of using a chaos monkey would be good. Maybe
the general procedure would be something like this:
1. Get the complete system information through the functions tested
in the first part.
2. Pick a random operation from a set implemented functions. 
3. Make changes to the copy of the systems information that we have
4. Get the system information again through the golang functions and
see if this copy of the system information matches the copy we already
have.
5. Repeat as necessary

It will probably take some time to finalize the procedure so I will
plan to submit it as a seperate patch or with a later patch.
> 
> OK, there's more to look at but I think that's enough for now.
> 
>  -George
> 

thanks,
Ronald

[-- Attachment #2: rules --]
[-- Type: text/plain, Size: 843 bytes --]

Rules for changing the naming convention from C to Golang

Builtins:
Remove underscores from C style name and use camelCase. 
If the type is a primitive data type(such a boolean or int) 
the equivilant Golang type is used. Otherwise delare the
type as the C type. 
Example:
	type Scheduler int
	type Uuid C.lixl_uuid


IDL types:
Remove underscores from C style name, remove libxl prefix,
 and use camelCase. Data fields will follow the same format 
by removing underscores and using camelCase.
Example:
	type CpupoolInfo struct {
		Poolid      uint32
		PoolName    string
		Scheduler   Scheduler
		DomainCount int
		Cpumap      Bitmap
	}
	


Functions:
Removed the libxl prefix from the function name. Instead of 
underscores camelCase is used to seperate words. 
Example:
	func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo){}

[-- Attachment #3: Type: text/plain, Size: 127 bytes --]

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info
  2017-01-03 17:45     ` Ronald Rojas
@ 2017-01-04 16:44       ` George Dunlap
  0 siblings, 0 replies; 67+ messages in thread
From: George Dunlap @ 2017-01-04 16:44 UTC (permalink / raw)
  To: Ronald Rojas; +Cc: Wei Liu, Ian Jackson, xen-devel

On Tue, Jan 3, 2017 at 5:45 PM, Ronald Rojas <ronladred@gmail.com> wrote:
>> > +/*
>> > +#cgo LDFLAGS: -lxenlight -lyajl
>> > +#include <stdlib.h>
>> > +#include <libxl.h>
>> > +*/
>> > +import "C"
>>
>> I see you switched back to dynamic linking -- any particular reason?
>>
>> We probably need to put a "// FIXME" here saying that we need to
>> generate these compile-time dependencies using pkg-config.
>
> We discussed this on IRC but I'll just restate here that I was not able
> to compile the program through static linking and it would be fine to
> just use dynamic linking for now.
> Since we are doing dynamic linking do we still need to use pkg-config?

Probably at some point, to make it less likely things will ever break
in the future (and as a "consumer" of the file to make sure things
don't break for other users).

>> Or taking the approach of the syscall package, and defining a type:
>>
>> type xlerror int
>>
>> func (e xlerror) Error() {
>>
>> }
>>
>> And making a (private) errors[] array, and re-impleminting Error() from
>> the syscall package.
>>
>> I think I would probably go with the syscall library's approach, since
>> (like it) we are handed a set of pre-existing error numbers.
>>
>> What do you think?
>
> I was actually thinking that taking the approach similiar to bufio would
> be better. It would not be difficult to create individual errors for each
> error number and creating variables for each error would allow users to
> easily compare the error that's returned against specific errors.

You can do this with what the syscall library does as well -- see the
references I linked to.  Filling out my example a bit:

type Error int

const (
    ErrorNonspecific = Error(C.ERROR_NONSPECIFIC)
    ErrorVersion = Error(C.ERROR_VERSION)
    ...
)

var errors = [...]string{
  C.ERROR_NONSPECIFIC:   "Non-specific error",
  C.ERROR_VERSION:   "Wrong version",
 ...
}

func (e Error) Error() {
  if 0 <= int(e) && int(e) < len(errors) {
    s := errors[e]
    if s != "" {
      return s
    }
  }
  return "errno " + itoa(int(e))
}

Now Xenlight.ErrorNonspecific is a const that you can compare an error
to; but if you "string" an error you'll get the error message in the
errors[] table -- the same as what you get from the bufio package.

Another advantage of this method is that there's an easy way to
convert return values from libxl functions into an error (just cast it
directly to Error), and if the caller knows that the error returned is
of type Xenlight.Error, they can cast it back to an int and use it
themselves if they want.

But I think either method will work just fine. :-)

> I've also been thinking about how to do the testing and I think it would
> be good to seperate testing into two parts, testing functions that get
> infomation about the system and functions that change the state of the
> system.
>
> I haven't been able to figure out how to use osstest to use the
> Golang libxl but I think it would still be fine to do unit testing by
> writing C and Go code that get information from a specific fuction(like
> physinfo) and seeing if they produce the same output.
>
> For functions that change the state of the system (like create/destroy
> guests) I think your idea of using a chaos monkey would be good. Maybe
> the general procedure would be something like this:
> 1. Get the complete system information through the functions tested
> in the first part.
> 2. Pick a random operation from a set implemented functions.
> 3. Make changes to the copy of the systems information that we have
> 4. Get the system information again through the golang functions and
> see if this copy of the system information matches the copy we already
> have.
> 5. Repeat as necessary
>
> It will probably take some time to finalize the procedure so I will
> plan to submit it as a seperate patch or with a later patch.

Sounds like a plan.

 -George

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

end of thread, other threads:[~2017-01-04 16:44 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-29  1:13 [PATCH RFC 01/59] Initial controller framework Ronald Rojas
2016-12-29  1:13 ` [PATCH RFC 02/59] controller: Revamp communication structure Ronald Rojas
2016-12-29  1:13 ` [PATCH RFC 03/59] controller: Initial attempt to generalize process / vm creation Ronald Rojas
2016-12-29  1:13 ` [PATCH RFC 04/59] Controller: Move process worker into its own file Ronald Rojas
2016-12-29  1:13 ` [PATCH RFC 05/59] controller: Add WorkerParams argument to Init in Worker interface Ronald Rojas
2016-12-29  1:13 ` [PATCH RFC 06/59] Reorganize to enable "Dist" directory Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 07/59] controller: Introduce basic Xen functionality Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 08/59] controller: Exit after second SIGINT Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 09/59] controller: Refactor creation and stopping of workers into WorkerList methods Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 10/59] controller: First cut at BenchmarkParams Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 11/59] Refactor to move towards benchmark "plans" and data analysis Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 12/59] Basic 'report' functionality Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 13/59] Add GPL headers / COPYING file (v2 only) Ronald Rojas
2016-12-29 10:51   ` Wei Liu
2016-12-29  1:14 ` [PATCH RFC 14/59] benchmark: Store data in terms of worker sets and worker ids Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 15/59] controller: Move "running" code to a separate file Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 16/59] controller: Rename an element in BenchmarkRun to be more accurate Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 17/59] controller: Collect and display statistics on WorkerSets Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 18/59] controller: Add cpupool global config Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 19/59] Add basic libxl framework, get domain cpu_time Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 20/59] xenworker: Use libxl_domain_unpause rather than forking xl Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 21/59] Report utilization statistics Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 22/59] Use tsc for time rather than rumpkernel clock_gettime() Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 23/59] run: Don't collect results reported after command to stop guests is issued Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 24/59] report: Lots of changes Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 25/59] main: Change default workload to something a bit more extreme Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 26/59] Use kops rather than mops Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 27/59] report: Allow report verbosity to be specified Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 28/59] controller: Handle worker early death Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 29/59] report: Add basic html report Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 30/59] htmlreport: Include utilization scatterplots Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 31/59] Make a binary that can run reports on a system without libxl Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 32/59] controller: Allow specification of an input file Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 33/59] controller: Add verbosity argument and update README with new instructions Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 34/59] controller: Make a useful config file Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 35/59] libxl: Add ListCpupool Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 36/59] controller: Make 'dummy' at the level of 'run' rather than xenworker Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 37/59] libxl.go: Provide a single global context by default Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 38/59] controller: Allow multiple schedulers in the same benchmark file Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 39/59] libxl.go: Put common link flags in libxl.go Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 40/59] controller: Add / update GPL text Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 41/59] libxl.go: Link statically rather than dynamically Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 42/59] plan: Allow "templating" from other runs Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 43/59] libxl: Add bitmap support Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 44/59] libxl: Implement CpupoolCreate Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 45/59] libxl: Implement Destroy, Add/Remove operations Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 46/59] libxl: Reorganize bitmapGotoC Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 47/59] libxl: Reorganize code Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 48/59] libxl: Add Ctx.CheckOpen Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 49/59] libxl: Implement libxl_cpupool_info and Scheduler.FromString() Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 50/59] libxl: Fix Bitmap.Max(), make Test() / Clear() more robust Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 51/59] controller: Make and/or modify cpupools when possible Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 52/59] libxl: Implement Bitmap.String() Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 53/59] controller: Add WorkerConfig.SoftAffinity Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 54/59] controller/run: Add RunConfig.NumaDisable Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 55/59] plan: Make the matrix generation more programmatic Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 56/59] controller/plan: Add NumaDisable to SimpleMatrix Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 57/59] tools/blktap2: remove unused inclusion of sys/sysctl.l Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 58/59] remove irrelevant files from old repository Ronald Rojas
2016-12-29  1:14 ` [PATCH RFC 59/59] tools/xenlight: Create interface for xenlight info Ronald Rojas
2016-12-29 10:34   ` George Dunlap
2016-12-29 10:52     ` Wei Liu
2016-12-29 13:49       ` Ronald Rojas
2016-12-29 13:45   ` George Dunlap
2016-12-29 20:20     ` George Dunlap
2017-01-03 17:45     ` Ronald Rojas
2017-01-04 16:44       ` George Dunlap

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.