@@ -20,6 +20,7 @@ package gocql
2020
2121import (
2222 "fmt"
23+ "strconv"
2324 "testing"
2425)
2526
@@ -33,13 +34,18 @@ func BenchmarkBatchQueryAppend(b *testing.B) {
3334 for _ , size := range []int {10 , 100 } {
3435 b .Run (fmt .Sprintf ("entries=%d" , size ), func (b * testing.B ) {
3536 b .ReportAllocs ()
37+ // Pre-compute value strings so fmt.Sprintf doesn't dominate allocations.
38+ vals := make ([]string , size )
39+ for j := 0 ; j < size ; j ++ {
40+ vals [j ] = "val_" + strconv .Itoa (j )
41+ }
3642 var batch * Batch
3743 for i := 0 ; i < b .N ; i ++ {
3844 batch = & Batch {
3945 Type : LoggedBatch ,
4046 }
4147 for j := 0 ; j < size ; j ++ {
42- batch .Query ("INSERT INTO ks.tbl (pk, v) VALUES (?, ?)" , j , fmt . Sprintf ( "val_%d" , j ) )
48+ batch .Query ("INSERT INTO ks.tbl (pk, v) VALUES (?, ?)" , j , vals [ j ] )
4349 }
4450 }
4551 benchSink = batch
@@ -54,13 +60,18 @@ func BenchmarkBatchQueryAppendPreallocated(b *testing.B) {
5460 for _ , size := range []int {10 , 100 } {
5561 b .Run (fmt .Sprintf ("entries=%d" , size ), func (b * testing.B ) {
5662 b .ReportAllocs ()
63+ // Pre-compute value strings so fmt.Sprintf doesn't dominate allocations.
64+ vals := make ([]string , size )
65+ for j := 0 ; j < size ; j ++ {
66+ vals [j ] = "val_" + strconv .Itoa (j )
67+ }
5768 var batch * Batch
5869 for i := 0 ; i < b .N ; i ++ {
5970 batch = (& Batch {
6071 Type : LoggedBatch ,
6172 }).Reserve (size )
6273 for j := 0 ; j < size ; j ++ {
63- batch .Query ("INSERT INTO ks.tbl (pk, v) VALUES (?, ?)" , j , fmt . Sprintf ( "val_%d" , j ) )
74+ batch .Query ("INSERT INTO ks.tbl (pk, v) VALUES (?, ?)" , j , vals [ j ] )
6475 }
6576 }
6677 benchSink = batch
@@ -76,10 +87,26 @@ func BenchmarkBatchBuildWriteFrame(b *testing.B) {
7687 b .Run (fmt .Sprintf ("entries=%d" , size ), func (b * testing.B ) {
7788 b .ReportAllocs ()
7889
79- // Pre-build mock column types and values
8090 colCount := 2
8191 typ := NativeType {proto : protoVersion4 , typ : TypeInt }
8292
93+ // Pre-compute prepared IDs and marshaled values outside the benchmark loop
94+ // so fmt.Sprintf and Marshal don't pollute allocation measurements.
95+ prepIDs := make ([][]byte , size )
96+ marshaledVals := make ([][]byte , size * colCount )
97+ for j := 0 ; j < size ; j ++ {
98+ prepIDs [j ] = []byte ("prepared_" + strconv .Itoa (j % 5 ))
99+ for k := 0 ; k < colCount ; k ++ {
100+ val , err := Marshal (typ , j + k )
101+ if err != nil {
102+ b .Fatalf ("Marshal(%d): %v" , j + k , err )
103+ }
104+ marshaledVals [j * colCount + k ] = val
105+ }
106+ }
107+
108+ b .ResetTimer ()
109+
83110 var req * writeBatchFrame
84111 for i := 0 ; i < b .N ; i ++ {
85112 req = & writeBatchFrame {
@@ -91,16 +118,15 @@ func BenchmarkBatchBuildWriteFrame(b *testing.B) {
91118
92119 stmts := make (map [string ]string , size )
93120
94- // Simulate the allocation pattern from executeBatch
121+ // Simulate the per-statement allocation pattern from executeBatch
95122 for j := 0 ; j < size ; j ++ {
96123 bs := & req .statements [j ]
97- bs .preparedID = [] byte ( fmt . Sprintf ( "prepared_%d" , j % 5 ))
98- stmts [string (bs .preparedID )] = fmt . Sprintf ( "INSERT INTO ks.tbl (pk, v) VALUES (?, ?)" )
124+ bs .preparedID = prepIDs [ j ]
125+ stmts [string (bs .preparedID )] = "INSERT INTO ks.tbl (pk, v) VALUES (?, ?)"
99126
100127 bs .values = make ([]queryValues , colCount )
101128 for k := 0 ; k < colCount ; k ++ {
102- val , _ := Marshal (typ , j + k )
103- bs .values [k ] = queryValues {value : val }
129+ bs .values [k ] = queryValues {value : marshaledVals [j * colCount + k ]}
104130 }
105131 }
106132 // Prevent the compiler from eliminating the stmts allocation.
@@ -123,6 +149,22 @@ func BenchmarkBatchBuildWriteFrameBulkAlloc(b *testing.B) {
123149 colCount := 2
124150 typ := NativeType {proto : protoVersion4 , typ : TypeInt }
125151
152+ // Pre-compute prepared IDs and marshaled values outside the benchmark loop.
153+ prepIDs := make ([][]byte , size )
154+ marshaledVals := make ([][]byte , size * colCount )
155+ for j := 0 ; j < size ; j ++ {
156+ prepIDs [j ] = []byte ("prepared_" + strconv .Itoa (j % 5 ))
157+ for k := 0 ; k < colCount ; k ++ {
158+ val , err := Marshal (typ , j + k )
159+ if err != nil {
160+ b .Fatalf ("Marshal(%d): %v" , j + k , err )
161+ }
162+ marshaledVals [j * colCount + k ] = val
163+ }
164+ }
165+
166+ b .ResetTimer ()
167+
126168 var req * writeBatchFrame
127169 for i := 0 ; i < b .N ; i ++ {
128170 req = & writeBatchFrame {
@@ -137,12 +179,11 @@ func BenchmarkBatchBuildWriteFrameBulkAlloc(b *testing.B) {
137179
138180 for j := 0 ; j < size ; j ++ {
139181 bs := & req .statements [j ]
140- bs .preparedID = [] byte ( fmt . Sprintf ( "prepared_%d" , j % 5 ))
182+ bs .preparedID = prepIDs [ j ]
141183
142184 bs .values = allValues [j * colCount : (j + 1 )* colCount ]
143185 for k := 0 ; k < colCount ; k ++ {
144- val , _ := Marshal (typ , j + k )
145- bs .values [k ] = queryValues {value : val }
186+ bs .values [k ] = queryValues {value : marshaledVals [j * colCount + k ]}
146187 }
147188 }
148189 }
@@ -171,10 +212,13 @@ func BenchmarkBatchWriteFrameSerialization(b *testing.B) {
171212
172213 for j := 0 ; j < size ; j ++ {
173214 bs := & frame .statements [j ]
174- bs .preparedID = []byte (fmt . Sprintf ( "prepared_%d" , j % 5 ))
215+ bs .preparedID = []byte ("prepared_" + strconv . Itoa ( j % 5 ))
175216 bs .values = make ([]queryValues , colCount )
176217 for k := 0 ; k < colCount ; k ++ {
177- val , _ := Marshal (typ , j + k )
218+ val , err := Marshal (typ , j + k )
219+ if err != nil {
220+ b .Fatalf ("Marshal(%d): %v" , j + k , err )
221+ }
178222 bs .values [k ] = queryValues {value : val }
179223 }
180224 }
0 commit comments