fork of https://github.com/sourcegraph/zoekt
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 4.3 kB View raw
1package search 2 3import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/google/go-cmp/cmp" 9) 10 11func BenchmarkYield(b *testing.B) { 12 // Use quantum longer than the benchmark runs 13 quantum := time.Minute 14 15 // Benchmark of the raw primitive we are using to tell if we should yield. 16 b.Run("timer", func(b *testing.B) { 17 t := time.NewTimer(quantum) 18 defer t.Stop() 19 20 for n := 0; n < b.N; n++ { 21 select { 22 case <-t.C: 23 b.Fatal("done") 24 default: 25 } 26 } 27 }) 28 29 // Benchmark of an alternative approach to timer. It is _much_ slower. 30 b.Run("now", func(b *testing.B) { 31 deadline := time.Now().Add(quantum) 32 33 for n := 0; n < b.N; n++ { 34 if time.Now().After(deadline) { 35 b.Fatal("done") 36 } 37 } 38 }) 39 40 // Benchmark of our wrapper around time.Timer 41 b.Run("deadlineTimer", func(b *testing.B) { 42 t := newDeadlineTimer(time.Now().Add(quantum)) 43 defer t.Stop() 44 45 for n := 0; n < b.N; n++ { 46 if t.Exceeded() { 47 b.Fatal("done") 48 } 49 } 50 }) 51 52 // Bencmark of actual yield function 53 b.Run("yield", func(b *testing.B) { 54 ctx := context.Background() 55 sched := newMultiScheduler(1) 56 sched.interactiveDuration = quantum 57 proc, err := sched.Acquire(ctx) 58 if err != nil { 59 b.Fatal(err) 60 } 61 defer proc.Release() 62 63 for n := 0; n < b.N; n++ { 64 if err := proc.Yield(ctx); err != nil { 65 b.Fatal(err) 66 } 67 } 68 }) 69} 70 71func TestYield(t *testing.T) { 72 ctx := context.Background() 73 quantum := 10 * time.Millisecond 74 deadline := time.Now().Add(quantum) 75 76 sched := newMultiScheduler(1) 77 sched.interactiveDuration = quantum 78 proc, err := sched.Acquire(ctx) 79 if err != nil { 80 t.Fatal(err) 81 } 82 defer proc.Release() 83 84 called := false 85 oldYieldFunc := proc.yieldFunc 86 proc.yieldFunc = func(ctx context.Context) error { 87 if called { 88 t.Fatal("yieldFunc called more than once") 89 } 90 called = true 91 if time.Now().Before(deadline) { 92 t.Fatal("yieldFunc called before deadline") 93 } 94 return oldYieldFunc(ctx) 95 } 96 97 var pre, post int 98 for post < 10 { 99 if err := proc.Yield(ctx); err != nil { 100 t.Fatal(err) 101 } 102 103 if called { 104 post++ 105 } else { 106 pre++ 107 } 108 } 109 110 // We can't assert anything based on time since it will run into race 111 // conditions with the runtime. So we just log the pre and post values so we 112 // can eyeball them sometimes :) 113 t.Logf("pre=%d post=%d", pre, post) 114} 115 116func TestMultiScheduler(t *testing.T) { 117 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 118 defer cancel() 119 120 capacity := 8 121 batchCap := capacity / 4 122 sched := newMultiScheduler(int64(capacity)) 123 sched.interactiveDuration = 0 // instantly downgrade to batch on call to yield. 124 125 var procs []*process 126 addProc := func() { 127 t.Helper() 128 proc, err := sched.Acquire(ctx) 129 if err != nil { 130 t.Fatal(err) 131 } 132 procs = append(procs, proc) 133 } 134 defer func() { 135 for _, p := range procs { 136 p.Release() 137 } 138 }() 139 140 // Fill up interactive queue 141 for range capacity { 142 addProc() 143 } 144 145 // We expect this to fail since the queue is at capacity 146 if _, err := sched.Acquire(quickCtx(t)); err == nil { 147 t.Fatal("expected first acquire after cap to fail") 148 } 149 150 // move procs[0] to batch queue freeing up interactive 151 if err := procs[0].Yield(ctx); err != nil { 152 t.Fatal(err) 153 } 154 addProc() 155 156 // We expect this to fail since the queue is at capacity again. 157 if _, err := sched.Acquire(quickCtx(t)); err == nil { 158 t.Fatal("expected second acquire after cap to fail") 159 } 160 161 // Fill up batch queue. Already has one item 162 for i := 1; i < batchCap; i++ { 163 if err := procs[i].Yield(ctx); err != nil { 164 t.Fatal(err) 165 } 166 } 167 168 // We expect this to fail since the batch queue is at capacity. 169 if err := procs[batchCap].Yield(quickCtx(t)); err == nil { 170 t.Fatal("expected second acquire after cap to fail") 171 } 172 173 for _, p := range procs { 174 p.Release() 175 } 176 procs = nil 177} 178 179func quickCtx(t *testing.T) context.Context { 180 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) 181 t.Cleanup(cancel) 182 return ctx 183} 184 185func TestParseTuneables(t *testing.T) { 186 cases := map[string]map[string]int{ 187 "": {}, 188 "disable": {"disable": 1}, 189 "disable,batchdiv=2": {"disable": 1, "batchdiv": 2}, 190 } 191 192 for v, want := range cases { 193 got := parseTuneables(v) 194 if d := cmp.Diff(want, got); d != "" { 195 t.Errorf("parseTuneables(%q) mismatch (-want, +got):\n%s", v, d) 196 } 197 } 198}