|  | // Copyright 2015 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  | package ssa | 
|  |  | 
|  | import ( | 
|  | "cmd/compile/internal/types" | 
|  | "fmt" | 
|  | "testing" | 
|  | ) | 
|  |  | 
|  | const ( | 
|  | blockCount = 1000 | 
|  | passCount  = 15000 | 
|  | ) | 
|  |  | 
|  | type passFunc func(*Func) | 
|  |  | 
|  | func BenchmarkDSEPass(b *testing.B)           { benchFnPass(b, dse, blockCount, genFunction) } | 
|  | func BenchmarkDSEPassBlock(b *testing.B)      { benchFnBlock(b, dse, genFunction) } | 
|  | func BenchmarkCSEPass(b *testing.B)           { benchFnPass(b, cse, blockCount, genFunction) } | 
|  | func BenchmarkCSEPassBlock(b *testing.B)      { benchFnBlock(b, cse, genFunction) } | 
|  | func BenchmarkDeadcodePass(b *testing.B)      { benchFnPass(b, deadcode, blockCount, genFunction) } | 
|  | func BenchmarkDeadcodePassBlock(b *testing.B) { benchFnBlock(b, deadcode, genFunction) } | 
|  |  | 
|  | func multi(f *Func) { | 
|  | cse(f) | 
|  | dse(f) | 
|  | deadcode(f) | 
|  | } | 
|  | func BenchmarkMultiPass(b *testing.B)      { benchFnPass(b, multi, blockCount, genFunction) } | 
|  | func BenchmarkMultiPassBlock(b *testing.B) { benchFnBlock(b, multi, genFunction) } | 
|  |  | 
|  | // benchFnPass runs passFunc b.N times across a single function. | 
|  | func benchFnPass(b *testing.B, fn passFunc, size int, bg blockGen) { | 
|  | b.ReportAllocs() | 
|  | c := testConfig(b) | 
|  | fun := c.Fun("entry", bg(size)...) | 
|  | CheckFunc(fun.f) | 
|  | b.ResetTimer() | 
|  | for i := 0; i < b.N; i++ { | 
|  | fn(fun.f) | 
|  | b.StopTimer() | 
|  | CheckFunc(fun.f) | 
|  | b.StartTimer() | 
|  | } | 
|  | } | 
|  |  | 
|  | // benchFnPass runs passFunc across a function with b.N blocks. | 
|  | func benchFnBlock(b *testing.B, fn passFunc, bg blockGen) { | 
|  | b.ReportAllocs() | 
|  | c := testConfig(b) | 
|  | fun := c.Fun("entry", bg(b.N)...) | 
|  | CheckFunc(fun.f) | 
|  | b.ResetTimer() | 
|  | for i := 0; i < passCount; i++ { | 
|  | fn(fun.f) | 
|  | } | 
|  | b.StopTimer() | 
|  | } | 
|  |  | 
|  | func genFunction(size int) []bloc { | 
|  | var blocs []bloc | 
|  | elemType := types.Types[types.TINT64] | 
|  | ptrType := elemType.PtrTo() | 
|  |  | 
|  | valn := func(s string, m, n int) string { return fmt.Sprintf("%s%d-%d", s, m, n) } | 
|  | blocs = append(blocs, | 
|  | Bloc("entry", | 
|  | Valu(valn("store", 0, 4), OpInitMem, types.TypeMem, 0, nil), | 
|  | Valu("sb", OpSB, types.Types[types.TUINTPTR], 0, nil), | 
|  | Goto(blockn(1)), | 
|  | ), | 
|  | ) | 
|  | for i := 1; i < size+1; i++ { | 
|  | blocs = append(blocs, Bloc(blockn(i), | 
|  | Valu(valn("v", i, 0), OpConstBool, types.Types[types.TBOOL], 1, nil), | 
|  | Valu(valn("addr", i, 1), OpAddr, ptrType, 0, nil, "sb"), | 
|  | Valu(valn("addr", i, 2), OpAddr, ptrType, 0, nil, "sb"), | 
|  | Valu(valn("addr", i, 3), OpAddr, ptrType, 0, nil, "sb"), | 
|  | Valu(valn("zero", i, 1), OpZero, types.TypeMem, 8, elemType, valn("addr", i, 3), | 
|  | valn("store", i-1, 4)), | 
|  | Valu(valn("store", i, 1), OpStore, types.TypeMem, 0, elemType, valn("addr", i, 1), | 
|  | valn("v", i, 0), valn("zero", i, 1)), | 
|  | Valu(valn("store", i, 2), OpStore, types.TypeMem, 0, elemType, valn("addr", i, 2), | 
|  | valn("v", i, 0), valn("store", i, 1)), | 
|  | Valu(valn("store", i, 3), OpStore, types.TypeMem, 0, elemType, valn("addr", i, 1), | 
|  | valn("v", i, 0), valn("store", i, 2)), | 
|  | Valu(valn("store", i, 4), OpStore, types.TypeMem, 0, elemType, valn("addr", i, 3), | 
|  | valn("v", i, 0), valn("store", i, 3)), | 
|  | Goto(blockn(i+1)))) | 
|  | } | 
|  |  | 
|  | blocs = append(blocs, | 
|  | Bloc(blockn(size+1), Goto("exit")), | 
|  | Bloc("exit", Exit("store0-4")), | 
|  | ) | 
|  |  | 
|  | return blocs | 
|  | } |