/usr/share/go-1.8/test/maplinear.go is in golang-1.8-src 1.8.3-2ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | // +build darwin linux
// run
// Copyright 2013 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.
// Test that maps don't go quadratic for NaNs and other values.
package main
import (
"fmt"
"math"
"time"
)
// checkLinear asserts that the running time of f(n) is in O(n).
// tries is the initial number of iterations.
func checkLinear(typ string, tries int, f func(n int)) {
// Depending on the machine and OS, this test might be too fast
// to measure with accurate enough granularity. On failure,
// make it run longer, hoping that the timing granularity
// is eventually sufficient.
timeF := func(n int) time.Duration {
t1 := time.Now()
f(n)
return time.Since(t1)
}
t0 := time.Now()
n := tries
fails := 0
for {
t1 := timeF(n)
t2 := timeF(2 * n)
// should be 2x (linear); allow up to 3x
if t2 < 3*t1 {
if false {
fmt.Println(typ, "\t", time.Since(t0))
}
return
}
// If n ops run in under a second and the ratio
// doesn't work out, make n bigger, trying to reduce
// the effect that a constant amount of overhead has
// on the computed ratio.
if t1 < 1*time.Second {
n *= 2
continue
}
// Once the test runs long enough for n ops,
// try to get the right ratio at least once.
// If five in a row all fail, give up.
if fails++; fails >= 5 {
panic(fmt.Sprintf("%s: too slow: %d inserts: %v; %d inserts: %v\n",
typ, n, t1, 2*n, t2))
}
}
}
type I interface {
f()
}
type C int
func (C) f() {}
func main() {
// NaNs. ~31ms on a 1.6GHz Zeon.
checkLinear("NaN", 30000, func(n int) {
m := map[float64]int{}
nan := math.NaN()
for i := 0; i < n; i++ {
m[nan] = 1
}
if len(m) != n {
panic("wrong size map after nan insertion")
}
})
// ~6ms on a 1.6GHz Zeon.
checkLinear("eface", 10000, func(n int) {
m := map[interface{}]int{}
for i := 0; i < n; i++ {
m[i] = 1
}
})
// ~7ms on a 1.6GHz Zeon.
// Regression test for CL 119360043.
checkLinear("iface", 10000, func(n int) {
m := map[I]int{}
for i := 0; i < n; i++ {
m[C(i)] = 1
}
})
// ~6ms on a 1.6GHz Zeon.
checkLinear("int", 10000, func(n int) {
m := map[int]int{}
for i := 0; i < n; i++ {
m[i] = 1
}
})
// ~18ms on a 1.6GHz Zeon.
checkLinear("string", 10000, func(n int) {
m := map[string]int{}
for i := 0; i < n; i++ {
m[fmt.Sprint(i)] = 1
}
})
// ~6ms on a 1.6GHz Zeon.
checkLinear("float32", 10000, func(n int) {
m := map[float32]int{}
for i := 0; i < n; i++ {
m[float32(i)] = 1
}
})
// ~6ms on a 1.6GHz Zeon.
checkLinear("float64", 10000, func(n int) {
m := map[float64]int{}
for i := 0; i < n; i++ {
m[float64(i)] = 1
}
})
// ~22ms on a 1.6GHz Zeon.
checkLinear("complex64", 10000, func(n int) {
m := map[complex64]int{}
for i := 0; i < n; i++ {
m[complex(float32(i), float32(i))] = 1
}
})
// ~32ms on a 1.6GHz Zeon.
checkLinear("complex128", 10000, func(n int) {
m := map[complex128]int{}
for i := 0; i < n; i++ {
m[complex(float64(i), float64(i))] = 1
}
})
// ~70ms on a 1.6GHz Zeon.
// The iterate/delete idiom currently takes expected
// O(n lg n) time. Fortunately, the checkLinear test
// leaves enough wiggle room to include n lg n time
// (it actually tests for O(n^log_2(3)).
// To prevent false positives, average away variation
// by doing multiple rounds within a single run.
checkLinear("iterdelete", 2500, func(n int) {
for round := 0; round < 4; round++ {
m := map[int]int{}
for i := 0; i < n; i++ {
m[i] = i
}
for i := 0; i < n; i++ {
for k := range m {
delete(m, k)
break
}
}
}
})
}
|