Last active
May 11, 2016 19:17
-
-
Save petrhosek/6848a2a56bc5cbbb1ac637e2f6411b4c to your computer and use it in GitHub Desktop.
LLVM MC bundle emission memory usage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/gnuplot | |
set xlabel "Input size" | |
set ylabel "Output size" | |
set terminal dumb size 200,80 | |
plot 'test.dat' using 1:2 with lines |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"container/list" | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"math/rand" | |
"log" | |
"os" | |
"os/exec" | |
"os/signal" | |
"path" | |
"regexp" | |
"runtime" | |
"strconv" | |
"sync" | |
) | |
type point [2]int | |
type polygon [4]point | |
var ( | |
funcs int | |
ops int | |
llvmPath string | |
jobs int | |
) | |
func generate_memory_test(filename string, funcs int, ops int) { | |
file, err := os.Create(filename) | |
if err != nil { | |
panic(err) | |
} | |
defer func() { | |
if err := file.Close(); err != nil { | |
panic(err) | |
} | |
}() | |
writer := bufio.NewWriter(file) | |
for i := 1; i < funcs; i++ { | |
fmt.Fprintf(writer, "void func_%v(int *p);\n", i) | |
} | |
fmt.Fprintln(writer) | |
for i := 1; i < funcs; i++ { | |
fmt.Fprintf(writer, "void func_%v(int *p) {\n", i) | |
for j := 0; j < ops; j++ { | |
fmt.Fprintf(writer, " p[%v] = p[%v];\n", rand.Intn(ops), rand.Intn(ops)) | |
} | |
fmt.Fprintf(writer, "}\n\n") | |
} | |
fmt.Fprintln(writer, "int main(int argc, const char *argv[]) {") | |
for i := 1; i < funcs; i++ { | |
fmt.Fprintf(writer, " func_%v((void *)0x%v);\n", i, rand.Intn(ops)) | |
} | |
fmt.Fprintln(writer, "}") | |
writer.Flush() | |
} | |
func generate_test(filename string, funcs int, ops int) { | |
file, err := os.Create(filename) | |
if err != nil { | |
panic(err) | |
} | |
defer func() { | |
if err := file.Close(); err != nil { | |
panic(err) | |
} | |
}() | |
writer := bufio.NewWriter(file) | |
for i := 0; i < funcs; i++ { | |
fmt.Fprintf(writer, "void func_%v(void);\n", i) | |
} | |
fmt.Fprintln(writer) | |
for i := 0; i < funcs; i++ { | |
fmt.Fprintf(writer, "void func_%v(void) {\n", i) | |
k := 0 | |
for j := 0; k < ops; j++ { | |
if i != j % funcs { | |
fmt.Fprintf(writer, " func_%v();\n", j % funcs) | |
k++ | |
} | |
} | |
fmt.Fprintf(writer, "}\n\n") | |
} | |
fmt.Fprintln(writer, "int main(int argc, const char *argv[]) {") | |
for i := 0; i < funcs; i++ { | |
fmt.Fprintf(writer, " func_%v();\n", i) | |
} | |
fmt.Fprintln(writer, "}") | |
writer.Flush() | |
} | |
func run_test(dir string, n int, m int) { | |
src := fmt.Sprintf("%v/test-%v-%v.c", dir, n, m) | |
asm := fmt.Sprintf("%v/test-%v-%v.s", dir, n, m) | |
obj := fmt.Sprintf("%v/test-%v-%v.o", dir, n, m) | |
generate_memory_test(src, n, m) | |
defer os.Remove(src) | |
cmd := exec.Command(path.Join(llvmPath, "clang"), src, "-S", "-o", asm) | |
if err := cmd.Run(); err != nil { | |
log.Printf("# %v %v clang error: %v\n", n, m, err) | |
return | |
} | |
defer os.Remove(asm) | |
data, err := ioutil.ReadFile(asm) | |
if err != nil { | |
panic(err) | |
} | |
str := "\t.bundle_align_mode 4\n" + string(data) | |
ioutil.WriteFile(asm, []byte(str), 0640) | |
if err != nil { | |
panic(err) | |
} | |
cmd = exec.Command("/usr/bin/time", "-f", "\"rsize %M\"", path.Join(llvmPath, "llvm-mc"), asm, "-filetype=obj", "-o", obj) | |
output, err := cmd.CombinedOutput() | |
if err != nil { | |
log.Printf("# %v %v llvm-mc error: %v\n", n, m, err) | |
return | |
} | |
defer os.Remove(obj) | |
rsize := 0 | |
re := regexp.MustCompile("rsize ([0-9]+)") | |
for _, match := range re.FindAllStringSubmatch(string(output), -1) { | |
size, err := strconv.Atoi(match[1]) | |
if err != nil { | |
continue | |
} | |
if size > rsize { | |
rsize = size | |
} | |
} | |
file, err := os.Open(obj) | |
if err != nil { | |
panic(err) | |
} | |
defer func() { | |
if err := file.Close(); err != nil { | |
panic(err) | |
} | |
}() | |
info, err := file.Stat() | |
if err != nil { | |
panic(err) | |
} | |
fmt.Printf("%v %v # %v %v\n", info.Size(), rsize, n, m) | |
} | |
func work(poly polygon, ch chan point) { | |
var queue list.List | |
queue.PushBack(poly) | |
for e := queue.Front(); e != nil; e = queue.Front() { | |
p := e.Value.(polygon) | |
if p[0][0] != p[2][0] && p[0][1] != p[2][1] { | |
p1 := point{(p[0][0] + p[1][0]) / 2, p[0][1]} | |
p2 := point{p[1][0], (p[1][1] + p[2][1]) / 2} | |
p3 := point{(p[2][0] + p[3][0]) / 2, p[2][1]} | |
p4 := point{p[3][0], (p[3][1] + p[0][1]) / 2} | |
p5 := point{(p[0][0] + p[2][0]) / 2, (p[0][1] + p[2][1]) / 2} | |
if (p5[0] != p[0][0] && p5[1] != p[0][1]) && | |
(p5[0] != p[2][0] && p5[1] != p[2][1]) { | |
ch <- p5 | |
queue.PushBack(polygon{p[0], p1, p5, p4}) | |
queue.PushBack(polygon{p1, p[1], p2, p5}) | |
queue.PushBack(polygon{p5, p2, p[2], p3}) | |
queue.PushBack(polygon{p4, p5, p3, p[3]}) | |
} | |
} | |
queue.Remove(e) | |
} | |
} | |
func worker(p polygon) <-chan point { | |
ch := make(chan point) | |
go func() { | |
work(p, ch) | |
close(ch) | |
}() | |
return ch | |
} | |
func main() { | |
flag.StringVar(&llvmPath, "path", "", "LLVM toolchain path") | |
flag.IntVar(&funcs, "funcs", 1, "number of functions") | |
flag.IntVar(&ops, "ops", 1, "number of operations") | |
flag.IntVar(&jobs, "jobs", runtime.NumCPU(), "number of parallel jobs") | |
flag.Parse() | |
pwd, err := os.Getwd() | |
if err != nil { | |
panic(err) | |
} | |
dir, err := ioutil.TempDir(pwd, "tests") | |
if err != nil { | |
panic(err) | |
} | |
defer os.Remove(dir) | |
go func() { | |
sig := make(chan os.Signal, 1) | |
signal.Notify(sig, os.Interrupt) | |
<-sig | |
os.Exit(0) | |
}() | |
tasks := make(chan struct {i int; j int}, jobs) | |
var group sync.WaitGroup | |
for i := 0; i < jobs; i++ { | |
group.Add(1) | |
go func() { | |
for req := range tasks { | |
run_test(dir, req.i, req.j) | |
} | |
group.Done() | |
}() | |
} | |
queue := worker(polygon{ | |
point{1, 1}, | |
point{1, ops}, | |
point{funcs, ops}, | |
point{funcs, 1}, | |
}) | |
for p := range queue { | |
tasks <- struct {i int; j int}{p[0], p[1]} | |
} | |
close(tasks) | |
group.Wait() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To use the script: