@@ -46,10 +46,10 @@ func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt {
4646 return stmt
4747}
4848
49- func initDB (b * testing.B , useCompression bool , queries ... string ) * sql.DB {
49+ func initDB (b * testing.B , compress bool , queries ... string ) * sql.DB {
5050 tb := (* TB )(b )
5151 comprStr := ""
52- if useCompression {
52+ if compress {
5353 comprStr = "&compress=1"
5454 }
5555 db := tb .checkDB (sql .Open (driverNameTest , dsn + comprStr ))
@@ -64,16 +64,15 @@ func initDB(b *testing.B, useCompression bool, queries ...string) *sql.DB {
6464const concurrencyLevel = 10
6565
6666func BenchmarkQuery (b * testing.B ) {
67- benchmarkQueryHelper (b , false )
67+ benchmarkQuery (b , false )
6868}
6969
70- func BenchmarkQueryCompression (b * testing.B ) {
71- benchmarkQueryHelper (b , true )
70+ func BenchmarkQueryCompressed (b * testing.B ) {
71+ benchmarkQuery (b , true )
7272}
7373
74- func benchmarkQueryHelper (b * testing.B , compr bool ) {
74+ func benchmarkQuery (b * testing.B , compr bool ) {
7575 tb := (* TB )(b )
76- b .StopTimer ()
7776 b .ReportAllocs ()
7877 db := initDB (b , compr ,
7978 "DROP TABLE IF EXISTS foo" ,
@@ -93,7 +92,7 @@ func benchmarkQueryHelper(b *testing.B, compr bool) {
9392 defer wg .Wait ()
9493 b .StartTimer ()
9594
96- for range concurrencyLevel {
95+ for i := 0 ; i < concurrencyLevel ; i ++ {
9796 go func () {
9897 for {
9998 if atomic .AddInt64 (& remain , - 1 ) < 0 {
@@ -115,8 +114,6 @@ func benchmarkQueryHelper(b *testing.B, compr bool) {
115114
116115func BenchmarkExec (b * testing.B ) {
117116 tb := (* TB )(b )
118- b .StopTimer ()
119- b .ReportAllocs ()
120117 db := tb .checkDB (sql .Open (driverNameTest , dsn ))
121118 db .SetMaxIdleConns (concurrencyLevel )
122119 defer db .Close ()
@@ -128,9 +125,11 @@ func BenchmarkExec(b *testing.B) {
128125 var wg sync.WaitGroup
129126 wg .Add (concurrencyLevel )
130127 defer wg .Wait ()
131- b .StartTimer ()
132128
133- for range concurrencyLevel {
129+ b .ReportAllocs ()
130+ b .ResetTimer ()
131+ 132+ for i := 0 ; i < concurrencyLevel ; i ++ {
134133 go func () {
135134 for {
136135 if atomic .AddInt64 (& remain , - 1 ) < 0 {
@@ -158,14 +157,15 @@ func initRoundtripBenchmarks() ([]byte, int, int) {
158157}
159158
160159func BenchmarkRoundtripTxt (b * testing.B ) {
161- b .StopTimer ()
162160 sample , min , max := initRoundtripBenchmarks ()
163161 sampleString := string (sample )
164- b .ReportAllocs ()
165162 tb := (* TB )(b )
166163 db := tb .checkDB (sql .Open (driverNameTest , dsn ))
167164 defer db .Close ()
168- b .StartTimer ()
165+ 166+ b .ReportAllocs ()
167+ b .ResetTimer ()
168+ 169169 var result string
170170 for i := 0 ; i < b .N ; i ++ {
171171 length := min + i
@@ -192,15 +192,15 @@ func BenchmarkRoundtripTxt(b *testing.B) {
192192}
193193
194194func BenchmarkRoundtripBin (b * testing.B ) {
195- b .StopTimer ()
196195 sample , min , max := initRoundtripBenchmarks ()
197- b .ReportAllocs ()
198196 tb := (* TB )(b )
199197 db := tb .checkDB (sql .Open (driverNameTest , dsn ))
200198 defer db .Close ()
201199 stmt := tb .checkStmt (db .Prepare ("SELECT ?" ))
202200 defer stmt .Close ()
203- b .StartTimer ()
201+ 202+ b .ReportAllocs ()
203+ b .ResetTimer ()
204204 var result sql.RawBytes
205205 for i := 0 ; i < b .N ; i ++ {
206206 length := min + i
@@ -345,7 +345,7 @@ func BenchmarkQueryRawBytes(b *testing.B) {
345345 for i := range blob {
346346 blob [i ] = 42
347347 }
348- for i := range 100 {
348+ for i := 0 ; i < 100 ; i ++ {
349349 _ , err := db .Exec ("INSERT INTO bench_rawbytes VALUES (?, ?)" , i , blob )
350350 if err != nil {
351351 b .Fatal (err )
@@ -385,10 +385,9 @@ func BenchmarkQueryRawBytes(b *testing.B) {
385385 }
386386}
387387
388- // BenchmarkReceiveMassiveRows measures performance of receiving large number of rows.
389- func BenchmarkReceiveMassiveRows (b * testing.B ) {
388+ func benchmark10kRows (b * testing.B , compress bool ) {
390389 // Setup -- prepare 10000 rows.
391- db := initDB (b , false ,
390+ db := initDB (b , compress ,
392391 "DROP TABLE IF EXISTS foo" ,
393392 "CREATE TABLE foo (id INT PRIMARY KEY, val TEXT)" )
394393 defer db .Close ()
@@ -399,11 +398,14 @@ func BenchmarkReceiveMassiveRows(b *testing.B) {
399398 b .Errorf ("failed to prepare query: %v" , err )
400399 return
401400 }
401+ 402+ args := make ([]any , 200 )
403+ for i := 1 ; i < 200 ; i += 2 {
404+ args [i ] = sval
405+ }
402406 for i := 0 ; i < 10000 ; i += 100 {
403- args := make ([]any , 200 )
404- for j := range 100 {
407+ for j := 0 ; j < 100 ; j ++ {
405408 args [j * 2 ] = i + j
406- args [j * 2 + 1 ] = sval
407409 }
408410 _ , err := stmt .Exec (args ... )
409411 if err != nil {
@@ -413,30 +415,43 @@ func BenchmarkReceiveMassiveRows(b *testing.B) {
413415 }
414416 stmt .Close ()
415417
416- // Use b.Run() to skip expensive setup.
418+ // benchmark function called several times with different b.N.
419+ // it means heavy setup is called multiple times.
420+ // Use b.Run() to run expensive setup only once.
421+ // Go 1.24 introduced b.Loop() for this purpose. But we keep this
422+ // benchmark compatible with Go 1.20.
417423 b .Run ("query" , func (b * testing.B ) {
418424 b .ReportAllocs ()
419- 420425 for i := 0 ; i < b .N ; i ++ {
421426 rows , err := db .Query (`SELECT id, val FROM foo` )
422427 if err != nil {
423428 b .Errorf ("failed to select: %v" , err )
424429 return
425430 }
431+ // rows.Scan() escapes arguments. So these variables must be defined
432+ // before loop.
433+ var i int
434+ var s sql.RawBytes
426435 for rows .Next () {
427- var i int
428- var s sql.RawBytes
429- err = rows .Scan (& i , & s )
430- if err != nil {
436+ if err := rows .Scan (& i , & s ); err != nil {
431437 b .Errorf ("failed to scan: %v" , err )
432- _ = rows .Close ()
438+ rows .Close ()
433439 return
434440 }
435441 }
436442 if err = rows .Err (); err != nil {
437443 b .Errorf ("failed to read rows: %v" , err )
438444 }
439- _ = rows .Close ()
445+ rows .Close ()
440446 }
441447 })
442448}
449+ 450+ // BenchmarkReceive10kRows measures performance of receiving large number of rows.
451+ func BenchmarkReceive10kRows (b * testing.B ) {
452+ benchmark10kRows (b , false )
453+ }
454+ 455+ func BenchmarkReceive10kRowsCompressed (b * testing.B ) {
456+ benchmark10kRows (b , true )
457+ }
0 commit comments