|  | // +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 | 
|  | } | 
|  | } | 
|  | } | 
|  | }) | 
|  | } |