Skip to content

Commit 1ae8c58

Browse files
committed
WIP: add perf tests
1 parent 6111b79 commit 1ae8c58

File tree

1 file changed

+293
-0
lines changed

1 file changed

+293
-0
lines changed

tarantool_test.go

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"runtime"
1616
"strings"
1717
"sync"
18+
"sync/atomic"
1819
"testing"
1920
"time"
2021

@@ -95,6 +96,298 @@ var opts = Opts{
9596

9697
const N = 500
9798

99+
func BenchmarkPerformance_naive(b *testing.B) {
100+
var err error
101+
102+
conn := test_helpers.ConnectWithValidation(b, dialer, opts)
103+
defer conn.Close()
104+
105+
_, err = conn.Replace(spaceNo, []interface{}{uint(1111), "hello", "world"})
106+
if err != nil {
107+
b.Fatalf("failed to inialize database: %s", err)
108+
}
109+
110+
b.ResetTimer()
111+
112+
for b.Loop() {
113+
req := NewSelectRequest(spaceNo).
114+
Index(indexNo).
115+
Iterator(IterEq).
116+
Key([]interface{}{uint(1111)})
117+
data, err := conn.Do(req).Get()
118+
if err != nil {
119+
b.Errorf("request error: %s", err)
120+
}
121+
122+
tuple := data[0].([]any)
123+
if tuple[0].(uint16) != uint16(1111) {
124+
b.Errorf("invalid result")
125+
}
126+
}
127+
}
128+
129+
func BenchmarkPerformance_naive_with_single_request(b *testing.B) {
130+
var err error
131+
132+
conn := test_helpers.ConnectWithValidation(b, dialer, opts)
133+
defer conn.Close()
134+
135+
_, err = conn.Replace(spaceNo, []interface{}{uint(1111), "hello", "world"})
136+
if err != nil {
137+
b.Fatalf("failed to inialize database: %s", err)
138+
}
139+
140+
req := NewSelectRequest(spaceNo).
141+
Index(indexNo).
142+
Iterator(IterEq).
143+
Key(UintKey{I: 1111})
144+
145+
b.ResetTimer()
146+
147+
for b.Loop() {
148+
data, err := conn.Do(req).Get()
149+
if err != nil {
150+
b.Errorf("request error: %s", err)
151+
}
152+
153+
tuple := data[0].([]any)
154+
if tuple[0].(uint16) != uint16(1111) {
155+
b.Errorf("invalid result")
156+
}
157+
}
158+
}
159+
160+
type benchTuple struct {
161+
id uint
162+
}
163+
164+
func (t *benchTuple) DecodeMsgpack(dec *msgpack.Decoder) error {
165+
l, err := dec.DecodeArrayLen()
166+
if err != nil {
167+
return fmt.Errorf("failed to decode tuples array: %w", err)
168+
}
169+
170+
if l != 1 {
171+
return fmt.Errorf("unexpected tuples array with len %d", l)
172+
}
173+
174+
l, err = dec.DecodeArrayLen()
175+
if err != nil {
176+
return fmt.Errorf("failed to decode tuple array: %w", err)
177+
}
178+
179+
if l < 1 {
180+
return fmt.Errorf("too smal tuple have 0 fields")
181+
}
182+
183+
t.id, err = dec.DecodeUint()
184+
if err != nil {
185+
return fmt.Errorf("failed to decode id: %w", err)
186+
}
187+
188+
return nil
189+
}
190+
191+
func BenchmarkPerformance_naive_with_custom_type(b *testing.B) {
192+
var err error
193+
194+
conn := test_helpers.ConnectWithValidation(b, dialer, opts)
195+
defer conn.Close()
196+
197+
_, err = conn.Replace(spaceNo, []interface{}{uint(1111), "hello", "world"})
198+
if err != nil {
199+
b.Fatalf("failed to inialize database: %s", err)
200+
}
201+
202+
req := NewSelectRequest(spaceNo).
203+
Index(indexNo).
204+
Iterator(IterEq).
205+
Key(UintKey{I: 1111})
206+
207+
var tuple benchTuple
208+
209+
b.ResetTimer()
210+
211+
for b.Loop() {
212+
err := conn.Do(req).GetTyped(&tuple)
213+
if err != nil {
214+
b.Errorf("request error: %s", err)
215+
}
216+
217+
if tuple.id != 1111 {
218+
b.Errorf("invalid result")
219+
}
220+
}
221+
}
222+
223+
func BenchmarkPerformance_multithread(b *testing.B) {
224+
var err error
225+
226+
conn := test_helpers.ConnectWithValidation(b, dialer, opts)
227+
defer conn.Close()
228+
229+
_, err = conn.Replace(spaceNo, []interface{}{uint(1111), "hello", "world"})
230+
if err != nil {
231+
b.Fatalf("failed to inialize database: %s", err)
232+
}
233+
234+
req := NewSelectRequest(spaceNo).
235+
Index(indexNo).
236+
Iterator(IterEq).
237+
Key(UintKey{I: 1111})
238+
239+
b.ResetTimer()
240+
241+
b.RunParallel(func(pb *testing.PB) {
242+
var tuple benchTuple
243+
244+
for pb.Next() {
245+
err := conn.Do(req).GetTyped(&tuple)
246+
if err != nil {
247+
b.Errorf("request error: %s", err)
248+
}
249+
250+
if tuple.id != 1111 {
251+
b.Errorf("invalid result")
252+
}
253+
}
254+
})
255+
}
256+
257+
func BenchmarkPerformance_multithread_parallelism(b *testing.B) {
258+
var err error
259+
260+
conn := test_helpers.ConnectWithValidation(b, dialer, opts)
261+
defer conn.Close()
262+
263+
_, err = conn.Replace(spaceNo, []interface{}{uint(1111), "hello", "world"})
264+
if err != nil {
265+
b.Fatalf("failed to inialize database: %s", err)
266+
}
267+
268+
req := NewSelectRequest(spaceNo).
269+
Index(indexNo).
270+
Iterator(IterEq).
271+
Key(UintKey{I: 1111})
272+
273+
b.ResetTimer()
274+
275+
for p := 1; p <= 1024; p *= 2 {
276+
b.Run(fmt.Sprintf("%d", p), func(b *testing.B) {
277+
b.SetParallelism(p)
278+
b.ResetTimer()
279+
280+
b.RunParallel(func(pb *testing.PB) {
281+
var tuple benchTuple
282+
283+
for pb.Next() {
284+
err := conn.Do(req).GetTyped(&tuple)
285+
if err != nil {
286+
b.Errorf("request error: %s", err)
287+
}
288+
289+
if tuple.id != 1111 {
290+
b.Errorf("invalid result")
291+
}
292+
}
293+
})
294+
})
295+
}
296+
}
297+
298+
func TestPerformance(t *testing.T) {
299+
requests := int64(10_000_000)
300+
connections := 16
301+
302+
ops := opts
303+
ops.Concurrency = 8
304+
305+
conns := make([]*Connection, 0, connections)
306+
for range connections {
307+
conn := test_helpers.ConnectWithValidation(t, dialer, ops)
308+
defer conn.Close()
309+
310+
conns = append(conns, conn)
311+
}
312+
313+
_, err := conns[0].Replace(spaceNo, []interface{}{uint(1111)})
314+
if err != nil {
315+
t.Fatalf("failed to inialize database: %s", err)
316+
}
317+
318+
req := NewSelectRequest(spaceNo).
319+
Index(indexNo).
320+
Iterator(IterEq).
321+
Key(UintKey{I: 1111})
322+
323+
maxRps := float64(0)
324+
maxConnections := 0
325+
maxConcurrency := 0
326+
327+
for cn := 1; cn <= connections; cn *= 2 {
328+
for cc := 1; cc <= 512; cc *= 2 {
329+
var wg sync.WaitGroup
330+
331+
curRequests := requests
332+
333+
start := time.Now()
334+
335+
for i := range cc {
336+
wg.Add(1)
337+
338+
ch := make(chan *Future, 1024)
339+
340+
go func(i int) {
341+
defer close(ch)
342+
343+
for atomic.AddInt64(&curRequests, -1) >= 0 {
344+
ch <- conns[i%cn].Do(req)
345+
}
346+
}(i)
347+
348+
go func() {
349+
defer wg.Done()
350+
351+
var tuple benchTuple
352+
353+
for fut := range ch {
354+
err := fut.GetTyped(&tuple)
355+
if err != nil {
356+
t.Errorf("request error: %s", err)
357+
}
358+
359+
if tuple.id != 1111 {
360+
t.Errorf("invalid result")
361+
}
362+
}
363+
}()
364+
}
365+
366+
wg.Wait()
367+
368+
duration := time.Since(start)
369+
370+
rps := float64(requests)/duration.Seconds()
371+
fmt.Println("requests :", requests)
372+
fmt.Println("concurrency:", cc)
373+
fmt.Println("connections:", cn)
374+
fmt.Printf("duration : %.2f\n", duration.Seconds())
375+
fmt.Printf("requests/s : %.2f\n", rps)
376+
fmt.Println("============")
377+
378+
if maxRps < rps {
379+
maxRps = rps
380+
maxConnections = cn
381+
maxConcurrency = cc
382+
}
383+
}
384+
}
385+
386+
fmt.Println("max connections:", maxConnections)
387+
fmt.Println("max concurrency:", maxConcurrency)
388+
fmt.Printf("max requests/s : %.2f", maxRps)
389+
}
390+
98391
func BenchmarkClientSerial(b *testing.B) {
99392
var err error
100393

0 commit comments

Comments
 (0)