@@ -46,10 +46,10 @@ func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt{
4646return 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 {
5050tb := (* TB )(b )
5151comprStr := ""
52- if useCompression {
52+ if compress {
5353comprStr = "&compress=1"
5454 }
5555db := 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 ){
7575tb := (* TB )(b )
76- b .StopTimer ()
7776b .ReportAllocs ()
7877db := initDB (b , compr ,
7978"DROP TABLE IF EXISTS foo" ,
@@ -115,8 +114,6 @@ func benchmarkQueryHelper(b *testing.B, compr bool){
115114
116115func BenchmarkExec (b * testing.B ){
117116tb := (* TB )(b )
118- b .StopTimer ()
119- b .ReportAllocs ()
120117db := tb .checkDB (sql .Open (driverNameTest , dsn ))
121118db .SetMaxIdleConns (concurrencyLevel )
122119defer db .Close ()
@@ -128,9 +125,11 @@ func BenchmarkExec(b *testing.B){
128125var wg sync.WaitGroup
129126wg .Add (concurrencyLevel )
130127defer wg .Wait ()
131- b .StartTimer ()
132128
133- for i := 0 ; i < concurrencyLevel ; i ++ {
129+ b .ReportAllocs ()
130+ b .ResetTimer ()
131+
132+ for i := 0 ; i < concurrencyLevel ; i ++ {
134133go func (){
135134for {
136135if atomic .AddInt64 (& remain , - 1 ) < 0 {
@@ -158,14 +157,15 @@ func initRoundtripBenchmarks() ([]byte, int, int){
158157}
159158
160159func BenchmarkRoundtripTxt (b * testing.B ){
161- b .StopTimer ()
162160sample , min , max := initRoundtripBenchmarks ()
163161sampleString := string (sample )
164- b .ReportAllocs ()
165162tb := (* TB )(b )
166163db := tb .checkDB (sql .Open (driverNameTest , dsn ))
167164defer db .Close ()
168- b .StartTimer ()
165+
166+ b .ReportAllocs ()
167+ b .ResetTimer ()
168+
169169var result string
170170for i := 0 ; i < b .N ; i ++ {
171171length := min + i
@@ -192,15 +192,15 @@ func BenchmarkRoundtripTxt(b *testing.B){
192192}
193193
194194func BenchmarkRoundtripBin (b * testing.B ){
195- b .StopTimer ()
196195sample , min , max := initRoundtripBenchmarks ()
197- b .ReportAllocs ()
198196tb := (* TB )(b )
199197db := tb .checkDB (sql .Open (driverNameTest , dsn ))
200198defer db .Close ()
201199stmt := tb .checkStmt (db .Prepare ("SELECT ?" ))
202200defer stmt .Close ()
203- b .StartTimer ()
201+
202+ b .ReportAllocs ()
203+ b .ResetTimer ()
204204var result sql.RawBytes
205205for i := 0 ; i < b .N ; i ++ {
206206length := min + i
@@ -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)" )
394393defer db .Close ()
@@ -399,11 +398,14 @@ func BenchmarkReceiveMassiveRows(b *testing.B){
399398b .Errorf ("failed to prepare query: %v" , err )
400399return
401400 }
401+
402+ args := make ([]any , 200 )
403+ for i := 1 ; i < 200 ; i += 2 {
404+ args [i ] = sval
405+ }
402406for i := 0 ; i < 10000 ; i += 100 {
403- args := make ([]any , 200 )
404407for j := 0 ; j < 100 ; j ++ {
405408args [j * 2 ] = i + j
406- args [j * 2 + 1 ] = sval
407409 }
408410_ , err := stmt .Exec (args ... )
409411if err != nil {
@@ -413,30 +415,43 @@ func BenchmarkReceiveMassiveRows(b *testing.B){
413415 }
414416stmt .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.
417423b .Run ("query" , func (b * testing.B ){
418424b .ReportAllocs ()
419-
420425for i := 0 ; i < b .N ; i ++ {
421426rows , err := db .Query (`SELECT id, val FROM foo` )
422427if err != nil {
423428b .Errorf ("failed to select: %v" , err )
424429return
425430 }
431+ // rows.Scan() escapes arguments. So these variables must be defined
432+ // before loop.
433+ var i int
434+ var s sql.RawBytes
426435for 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 {
431437b .Errorf ("failed to scan: %v" , err )
432- _ = rows .Close ()
438+ rows .Close ()
433439return
434440 }
435441 }
436442if err = rows .Err (); err != nil {
437443b .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