blob: cb88d80e00d68d6b4fab8ac56b073a6ac90690f5 [file] [log] [blame]
package parser
import (
"math"
"testing"
"skia.googlesource.com/buildbot.git/perf/go/config"
"skia.googlesource.com/buildbot.git/perf/go/types"
)
func newTestContext() *Context {
tile := types.NewTile()
t1 := types.NewPerfTraceN(3)
t1.Params_["os"] = "Ubuntu12"
t1.Params_["config"] = "8888"
t1.Values[1] = 1.234
tile.Traces["t1"] = t1
t2 := types.NewPerfTraceN(3)
t2.Params_["os"] = "Ubuntu12"
t2.Params_["config"] = "gpu"
t2.Values[1] = 1.236
tile.Traces["t2"] = t2
return NewContext(tile)
}
func TestFilter(t *testing.T) {
ctx := newTestContext()
testCases := []struct {
input string
length int
}{
{`filter("os=Ubuntu12")`, 2},
{`filter("")`, 2},
{`filter("config=8888")`, 1},
{`filter("config=gpu")`, 1},
{`filter("config=565")`, 0},
}
for _, tc := range testCases {
traces, err := ctx.Eval(tc.input)
if err != nil {
t.Fatalf("Failed to run filter %q: %s", tc.input, err)
}
if got, want := len(traces), tc.length; got != want {
t.Errorf("Wrong traces length %q: Got %v Want %v", tc.input, got, want)
}
}
}
func TestEvalNoModifyTile(t *testing.T) {
ctx := newTestContext()
traces, err := ctx.Eval(`fill(filter("config=8888"))`)
if err != nil {
t.Fatalf("Failed to run filter: %s", err)
}
// Make sure we made a deep copy of the traces in the Tile.
if got, want := ctx.Tile.Traces["t1"].(*types.PerfTrace).Values[0], config.MISSING_DATA_SENTINEL; got != want {
t.Errorf("Tile incorrectly modified: Got %v Want %v", got, want)
}
if got, want := traces[0].Values[0], 1.234; got != want {
t.Errorf("fill() failed: Got %v Want %v", got, want)
}
}
func TestEvalErrors(t *testing.T) {
ctx := newTestContext()
testCases := []string{
// Invalid forms.
`filter("os=Ubuntu12"`,
`filter(")`,
`"config=8888"`,
`("config=gpu")`,
`{}`,
// Forms that fail internal Func validation.
`filter(2)`,
`norm("foo")`,
`norm(filter(""), "foo")`,
`ave(2)`,
`avg(2)`,
`norm(2)`,
`fill(2)`,
`norm()`,
`ave()`,
`avg()`,
`fill()`,
}
for _, tc := range testCases {
_, err := ctx.Eval(tc)
if err == nil {
t.Fatalf("Expected %q to fail parsing:", tc)
}
}
}
func near(a, b float64) bool {
return math.Abs(a-b) < 0.001
}
func TestNorm(t *testing.T) {
ctx := newTestContext()
ctx.Tile.Traces["t1"].(*types.PerfTrace).Values = []float64{2.0, -2.0, 1e100}
delete(ctx.Tile.Traces, "t2")
traces, err := ctx.Eval(`norm(filter(""))`)
if err != nil {
t.Fatalf("Failed to eval norm() test: %s", err)
}
if got, want := traces[0].Values[0], 1.0; !near(got, want) {
t.Errorf("Distance mismatch: Got %v Want %v Full %#v", got, want, traces[0].Values)
}
}
func TestAve(t *testing.T) {
ctx := newTestContext()
ctx.Tile.Traces["t1"].(*types.PerfTrace).Values = []float64{1.0, -1.0, 1e100, 1e100}
ctx.Tile.Traces["t2"].(*types.PerfTrace).Values = []float64{1e100, 2.0, -2.0, 1e100}
traces, err := ctx.Eval(`ave(filter(""))`)
if err != nil {
t.Fatalf("Failed to eval ave() test: %s", err)
}
if got, want := len(traces), 1; got != want {
t.Errorf("ave() returned wrong length: Got %v Want %v", got, want)
}
for i, want := range []float64{1.0, 0.5, -2.0, 1e100} {
if got := traces[0].Values[i]; !near(got, want) {
t.Errorf("Distance mismatch: Got %v Want %v", got, want)
}
}
}
func TestAvg(t *testing.T) {
ctx := newTestContext()
ctx.Tile.Traces["t1"].(*types.PerfTrace).Values = []float64{1.0, -1.0, 1e100, 1e100}
ctx.Tile.Traces["t2"].(*types.PerfTrace).Values = []float64{1e100, 2.0, -2.0, 1e100}
traces, err := ctx.Eval(`avg(filter(""))`)
if err != nil {
t.Fatalf("Failed to eval avg() test: %s", err)
}
if got, want := len(traces), 1; got != want {
t.Errorf("avg() returned wrong length: Got %v Want %v", got, want)
}
for i, want := range []float64{1.0, 0.5, -2.0, 1e100} {
if got := traces[0].Values[i]; !near(got, want) {
t.Errorf("Distance mismatch: Got %v Want %v", got, want)
}
}
}
func TestCount(t *testing.T) {
ctx := newTestContext()
ctx.Tile.Traces["t1"].(*types.PerfTrace).Values = []float64{1.0, -1.0, 1e100, 1e100}
ctx.Tile.Traces["t2"].(*types.PerfTrace).Values = []float64{1e100, 2.0, -2.0, 1e100}
traces, err := ctx.Eval(`count(filter(""))`)
if err != nil {
t.Fatalf("Failed to eval count() test: %s", err)
}
if got, want := len(traces), 1; got != want {
t.Errorf("count() returned wrong length: Got %v Want %v", got, want)
}
for i, want := range []float64{1.0, 2.0, 1.0, 0.0} {
if got := traces[0].Values[i]; !near(got, want) {
t.Errorf("Distance mismatch: Got %v Want %v", got, want)
}
}
}
func TestRatio(t *testing.T) {
ctx := newTestContext()
ctx.Tile.Traces["t1"].(*types.PerfTrace).Values = []float64{10, 4, 100, 50, 9999, 0}
ctx.Tile.Traces["t2"].(*types.PerfTrace).Values = []float64{5, 2, 4, 5, 0, 1000}
traces, err := ctx.Eval(`ratio(
ave(fill(filter("config=gpu"))),
ave(fill(filter("config=8888"))))`)
if err != nil {
t.Fatalf("Failed to eval ratio() test: %s", err)
}
if got, want := len(traces), 1; got != want {
t.Errorf("ratio() returned wrong length: Got %v Want %v", got, want)
}
for i, want := range []float64{0.5, 0.5, 0.04, 0.1, 0, 1e+100} {
if got := traces[0].Values[i]; got != want {
t.Errorf("Ratio mismatch: Got %v Want %v", got, want)
}
}
}
func TestFill(t *testing.T) {
ctx := newTestContext()
ctx.Tile.Traces["t1"].(*types.PerfTrace).Values = []float64{1e100, 1e100, 2, 3, 1e100, 5}
delete(ctx.Tile.Traces, "t2")
traces, err := ctx.Eval(`fill(filter("config=8888"))`)
if err != nil {
t.Fatalf("Failed to eval fill() test: %s", err)
}
if got, want := len(traces), 1; got != want {
t.Errorf("fill() returned wrong length: Got %v Want %v", got, want)
}
for i, want := range []float64{2, 2, 2, 3, 5, 5} {
if got := traces[0].Values[i]; !near(got, want) {
t.Errorf("Distance mismatch: Got %v Want %v", got, want)
}
}
}