mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-25 04:19:53 +00:00
a7e4a49fae
A bunch of spot optmizations after cpu/memory profiling: 1. Optimize hot-path coverage comparison in fuzzer. 2. Don't allocate and copy serialized program, serialize directly into shmem. 3. Reduce allocations during parsing of output shmem (encoding/binary sucks). 4. Don't allocate and copy coverage arrays, refer directly to the shmem region (we are not going to mutate them). 5. Don't validate programs outside of tests, validation allocates tons of memory. 6. Replace the choose primitive with simpler switches. Choose allocates fullload of memory (for int, func, and everything the func refers). 7. Other minor optimizations.
236 lines
5.4 KiB
Go
236 lines
5.4 KiB
Go
// Copyright 2015 syzkaller project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
package cover
|
|
|
|
import (
|
|
"math/rand"
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func initTest(t *testing.T) (*rand.Rand, int) {
|
|
iters := 100000
|
|
if testing.Short() {
|
|
iters = 1000
|
|
}
|
|
seed := int64(time.Now().UnixNano())
|
|
rs := rand.NewSource(seed)
|
|
t.Logf("seed=%v", seed)
|
|
return rand.New(rs), iters
|
|
}
|
|
|
|
type Test struct {
|
|
V0 Cover
|
|
V1 Cover
|
|
R Cover
|
|
}
|
|
|
|
func runTest(t *testing.T, f func(Cover, Cover) Cover, sorted, symmetric bool, tests []Test) {
|
|
if symmetric {
|
|
for _, test := range tests {
|
|
tests = append(tests, Test{test.V1, test.V0, test.R})
|
|
}
|
|
}
|
|
tests = append(tests, Test{Cover{}, Cover{}, Cover{}})
|
|
for _, test := range tests {
|
|
if sorted {
|
|
if !sort.IsSorted(test.V0) {
|
|
t.Fatalf("input is not sorted: %+v", test.V0)
|
|
}
|
|
if !sort.IsSorted(test.V1) {
|
|
t.Fatalf("input is not sorted: %+v", test.V1)
|
|
}
|
|
}
|
|
if !sort.IsSorted(test.R) {
|
|
t.Fatalf("golden is not sorted: %+v", test.R)
|
|
}
|
|
res := f(test.V0, test.V1)
|
|
if !sort.IsSorted(res) {
|
|
t.Fatalf("output is not sorted: %+v", res)
|
|
}
|
|
if (len(res) != 0 || len(test.R) != 0) && !reflect.DeepEqual(res, test.R) {
|
|
t.Fatalf("f(%+v, %+v) = %+v (expect: %+v)", test.V0, test.V1, res, test.R)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCanonicalize(t *testing.T) {
|
|
runTest(t, func(c0, c1 Cover) Cover { return Canonicalize([]uint32(c0)) }, false, false, []Test{
|
|
{Cover{1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 6}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
|
|
{Cover{6, 2, 3, 4, 5, 1}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
|
|
{Cover{6, 1, 2, 6, 3, 3, 4, 5, 1}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
|
|
})
|
|
}
|
|
|
|
func TestDifference(t *testing.T) {
|
|
runTest(t, Difference, true, false, []Test{
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{3}, Cover{1, 2, 4, 5, 6}},
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{1, 6}, Cover{2, 3, 4, 5}},
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{0, 10}, Cover{1, 2, 3, 4, 5, 6}},
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{0, 3, 6}, Cover{1, 2, 4, 5}},
|
|
})
|
|
}
|
|
|
|
func TestSymmetricDifference(t *testing.T) {
|
|
runTest(t, SymmetricDifference, true, true, []Test{
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{1, 2, 3, 4, 5, 6}, Cover{}},
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{2, 4, 6}, Cover{1, 3, 5}},
|
|
{Cover{2, 4, 6}, Cover{1, 3, 5}, Cover{1, 2, 3, 4, 5, 6}},
|
|
})
|
|
}
|
|
|
|
func TestUnion(t *testing.T) {
|
|
runTest(t, Union, true, true, []Test{
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{1, 2, 3, 4, 5, 6}, Cover{1, 2, 3, 4, 5, 6}},
|
|
{Cover{1, 3, 5}, Cover{2, 4, 6}, Cover{1, 2, 3, 4, 5, 6}},
|
|
{Cover{1, 2, 3, 5}, Cover{2, 4, 5, 6}, Cover{1, 2, 3, 4, 5, 6}},
|
|
})
|
|
}
|
|
|
|
func TestIntersection(t *testing.T) {
|
|
runTest(t, Intersection, true, true, []Test{
|
|
{Cover{1, 2, 3, 4, 5, 6}, Cover{}, Cover{}},
|
|
{Cover{1, 2, 3}, Cover{4, 5, 6}, Cover{}},
|
|
{Cover{1, 2, 3}, Cover{2, 3, 5}, Cover{2, 3}},
|
|
})
|
|
}
|
|
|
|
func TestMinimize(t *testing.T) {
|
|
tests := []struct {
|
|
inp []Cover
|
|
out []int
|
|
}{
|
|
// Take all.
|
|
{
|
|
[]Cover{
|
|
{1, 2, 3},
|
|
{4, 5, 6},
|
|
{7, 8, 9},
|
|
},
|
|
[]int{0, 1, 2},
|
|
},
|
|
// Take one.
|
|
{
|
|
[]Cover{
|
|
{1, 2, 3, 4, 5, 6, 7, 8, 9},
|
|
{1},
|
|
{2, 3, 4, 5},
|
|
{6, 7, 8},
|
|
},
|
|
[]int{0},
|
|
},
|
|
// Take two.
|
|
{
|
|
[]Cover{
|
|
{1, 2, 3, 4, 5, 6, 7, 8, 9},
|
|
{1},
|
|
{2, 3, 4, 5},
|
|
{10},
|
|
},
|
|
[]int{0, 3},
|
|
},
|
|
// Take another two.
|
|
{
|
|
[]Cover{
|
|
{1, 2, 3, 4},
|
|
{1, 2},
|
|
{3, 4, 5, 6, 7},
|
|
{3, 7},
|
|
},
|
|
[]int{2, 0},
|
|
},
|
|
// Take the largest one.
|
|
{
|
|
[]Cover{
|
|
{1, 2},
|
|
{1, 2, 3, 4, 5},
|
|
{3, 4, 5},
|
|
},
|
|
[]int{1},
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
res := Minimize(test.inp)
|
|
if !reflect.DeepEqual(res, test.out) {
|
|
t.Logf("corpus:")
|
|
for _, in := range test.inp {
|
|
t.Logf(" %+v", in)
|
|
}
|
|
t.Fatalf("expect: %+v, got: %+v", test.out, res)
|
|
}
|
|
}
|
|
}
|
|
|
|
func randCover(rnd *rand.Rand, maxLen int) Cover {
|
|
tmp := make(Cover, rnd.Intn(maxLen))
|
|
for j := range tmp {
|
|
tmp[j] = uint32(rnd.Intn(100))
|
|
}
|
|
return Canonicalize(tmp)
|
|
}
|
|
|
|
func TestMinimizeRandom(t *testing.T) {
|
|
rnd, iters := initTest(t)
|
|
for i := 0; i < iters; i++ {
|
|
n := rnd.Intn(20)
|
|
cov := make([]Cover, n)
|
|
for i := range cov {
|
|
cov[i] = randCover(rnd, 10)
|
|
}
|
|
var total Cover
|
|
for _, c := range cov {
|
|
total = Union(total, c)
|
|
}
|
|
mini := Minimize(cov)
|
|
var minimized Cover
|
|
for _, idx := range mini {
|
|
minimized = Union(minimized, cov[idx])
|
|
}
|
|
if !reflect.DeepEqual(total, minimized) {
|
|
t.Logf("minimized %v -> %v", len(cov), len(mini))
|
|
t.Logf("corpus:")
|
|
for _, in := range cov {
|
|
t.Logf(" %+v", in)
|
|
}
|
|
t.Logf("minimized:")
|
|
for _, in := range cov {
|
|
t.Logf(" %+v", in)
|
|
}
|
|
t.Fatalf("better luck next time")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestHasDifference(t *testing.T) {
|
|
rnd, iters := initTest(t)
|
|
for i := 0; i < iters; i++ {
|
|
cov1 := randCover(rnd, 20)
|
|
cov2 := randCover(rnd, 20)
|
|
diff := Difference(cov1, cov2)
|
|
hasDiff := HasDifference(cov1, cov2)
|
|
if len(diff) != 0 != hasDiff {
|
|
t.Fatalf("cov1=%+v cov2=%+v diff=%+v hasDiff=%v", cov1, cov2, diff, hasDiff)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkHasDifference(b *testing.B) {
|
|
rnd := rand.New(rand.NewSource(0))
|
|
cov0 := make(Cover, 70000)
|
|
for i := range cov0 {
|
|
cov0[i] = uint32(rnd.Intn(1 << 30))
|
|
}
|
|
cov1 := Canonicalize(append(Cover{}, cov0[:500]...))
|
|
cov0 = Canonicalize(cov0)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = HasDifference(cov1, cov0)
|
|
}
|
|
}
|