github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/stats/automatic_stats_manual_test.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package stats_test 12 13 import ( 14 "context" 15 "flag" 16 "fmt" 17 "runtime" 18 "sync" 19 "testing" 20 "time" 21 22 "github.com/cockroachdb/cockroach/pkg/base" 23 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 24 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 25 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 26 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 27 ) 28 29 var runManual = flag.Bool( 30 "run-manual", false, 31 "run manual tests", 32 ) 33 34 // TestAdaptiveThrottling is a "manual" test: it runs automatic statistics with 35 // varying load on the system and prints out the times. It should be run on a 36 // lightly loaded system using: 37 // 38 // make test PKG=./pkg/sql/stats TESTS=AdaptiveThrottling TESTFLAGS='-v --run-manual -logtostderr NONE' 39 // 40 // Sample output: 41 // 42 // --- PASS: TestAdaptiveThrottling (114.51s) 43 // automatic_stats_manual_test.go:72: Populate table took 7.639067726s 44 // automatic_stats_manual_test.go:72: --- Load 0% --- 45 // automatic_stats_manual_test.go:72: Create stats took 1.198634729s 46 // automatic_stats_manual_test.go:72: --- Load 30% --- 47 // automatic_stats_manual_test.go:72: Create stats took 2.270165784s 48 // automatic_stats_manual_test.go:72: --- Load 50% --- 49 // automatic_stats_manual_test.go:72: Create stats took 7.324599981s 50 // automatic_stats_manual_test.go:72: --- Load 70% --- 51 // automatic_stats_manual_test.go:72: Create stats took 15.886412857s 52 // 53 func TestAdaptiveThrottling(t *testing.T) { 54 defer leaktest.AfterTest(t)() 55 ctx := context.Background() 56 if !*runManual { 57 t.Skip("manual test with no --run-manual") 58 } 59 s, sqlDB, _ := serverutils.StartServer(t, base.TestServerArgs{}) 60 defer s.Stopper().Stop(ctx) 61 62 r := sqlutils.MakeSQLRunner(sqlDB) 63 r.Exec(t, "SET CLUSTER SETTING sql.stats.automatic_collection.enabled = false") 64 r.Exec(t, "CREATE TABLE xyz (x INT, y INT, z INT)") 65 66 // log prints the message to stdout and to the test log. 67 log := func(msg string) { 68 fmt.Println(msg) 69 t.Log(msg) 70 } 71 72 step := func(msg string, fn func()) { 73 fmt.Println(msg) 74 before := timeutil.Now() 75 fn() 76 log(fmt.Sprintf("%s took %s", msg, timeutil.Now().Sub(before))) 77 } 78 79 step("Populate table", func() { 80 for i := 0; i < 200; i++ { 81 r.Exec(t, "INSERT INTO xyz SELECT x, 2*x, 3*x FROM generate_series(1, 1000) AS g(x)") 82 } 83 }) 84 85 for _, load := range []int{0, 3, 5, 7} { 86 log(fmt.Sprintf("--- Load %d%% ---", load*10)) 87 // Set up a load on each CPU. 88 cancel := make(chan struct{}) 89 var wg sync.WaitGroup 90 for i := 0; i < runtime.NumCPU(); i++ { 91 wg.Add(1) 92 go func() { 93 runLoad(load, cancel) 94 wg.Done() 95 }() 96 } 97 98 // Sleep for 2 * DefaultMetricsSampleInterval, to make sure the runtime 99 // stats reflect the load we want. 100 sleep := 2 * base.DefaultMetricsSampleInterval 101 fmt.Printf("Sleeping for %s\n", sleep) 102 time.Sleep(sleep) 103 step("Create stats", func() { 104 r.Exec(t, "CREATE STATISTICS __auto__ FROM xyz") 105 }) 106 close(cancel) 107 wg.Wait() 108 } 109 } 110 111 // runLoad runs a goroutine that runs a load for (<load> / 10) of the time. 112 // It stops when the cancel channel is closed. 113 func runLoad(load int, cancel chan struct{}) { 114 if load == 0 { 115 <-cancel 116 return 117 } 118 ticker := time.NewTicker(time.Millisecond) 119 defer ticker.Stop() 120 for idx := 0; ; idx = (idx + 1) % 10 { 121 if idx >= load { 122 // No work this time slice; just wait until the ticker fires. 123 select { 124 case <-cancel: 125 return 126 case <-ticker.C: 127 } 128 continue 129 } 130 for done := false; !done; { 131 select { 132 case <-cancel: 133 return 134 case <-ticker.C: 135 done = true 136 default: 137 // Do some work: find the first 100 prime numbers. 138 for x, count := 2, 0; count < 100; x++ { 139 prime := true 140 for i := 2; i*i < x; i++ { 141 if x%i == 0 { 142 prime = false 143 break 144 } 145 } 146 if prime { 147 count++ 148 } 149 } 150 } 151 } 152 } 153 }