@@ -17,6 +17,7 @@ package grumpy
1717import (
1818 "reflect"
1919 "regexp"
20+ "runtime"
2021 "sync"
2122 "testing"
2223 "time"
@@ -244,6 +245,146 @@ func TestDictGetItem(t *testing.T) {
244245 }
245246}
246247
248+ // BenchmarkDictGetItem is to keep an eye on the speed of contended dict access
249+ // in a fast read loop.
250+ func BenchmarkDictGetItem (b * testing.B ) {
251+ d := newTestDict (
252+ "foo" , 1 ,
253+ "bar" , 2 ,
254+ None , 3 ,
255+ 4 , 5 )
256+ k := NewInt (4 ).ToObject ()
257+
258+ b .ResetTimer ()
259+ b .RunParallel (func (pb * testing.PB ) {
260+ f := NewRootFrame ()
261+ var ret * Object
262+ var raised * BaseException
263+ for pb .Next () {
264+ ret , raised = d .GetItem (f , k )
265+ }
266+ runtime .KeepAlive (ret )
267+ runtime .KeepAlive (raised )
268+ })
269+ }
270+
271+ func BenchmarkDictIterItems (b * testing.B ) {
272+ bench := func (d * Dict ) func (* testing.B ) {
273+ return func (b * testing.B ) {
274+ f := NewRootFrame ()
275+ args := f .MakeArgs (1 )
276+ args [0 ] = d .ToObject ()
277+ b .ResetTimer ()
278+
279+ var ret * Object
280+ var raised * BaseException
281+ for i := 0 ; i < b .N ; i ++ {
282+ iter , _ := dictIterItems (f , args , nil )
283+ for {
284+ ret , raised = Next (f , iter )
285+ if raised != nil {
286+ if ! raised .isInstance (StopIterationType ) {
287+ b .Fatalf ("iteration failed with: %v" , raised )
288+ }
289+ f .RestoreExc (nil , nil )
290+ break
291+ }
292+ }
293+ }
294+ runtime .KeepAlive (ret )
295+ runtime .KeepAlive (raised )
296+ }
297+ }
298+
299+ b .Run ("0-elements" , bench (newTestDict ()))
300+ b .Run ("1-elements" , bench (newTestDict (1 , 2 )))
301+ b .Run ("2-elements" , bench (newTestDict (1 , 2 , 3 , 4 )))
302+ b .Run ("3-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 )))
303+ b .Run ("4-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 )))
304+ b .Run ("5-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 )))
305+ b .Run ("6-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 )))
306+ b .Run ("7-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 )))
307+ b .Run ("8-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 )))
308+ }
309+
310+ func BenchmarkDictIterKeys (b * testing.B ) {
311+ bench := func (d * Dict ) func (* testing.B ) {
312+ return func (b * testing.B ) {
313+ f := NewRootFrame ()
314+ args := f .MakeArgs (1 )
315+ args [0 ] = d .ToObject ()
316+ b .ResetTimer ()
317+
318+ var ret * Object
319+ var raised * BaseException
320+ for i := 0 ; i < b .N ; i ++ {
321+ iter , _ := dictIterKeys (f , args , nil )
322+ for {
323+ ret , raised = Next (f , iter )
324+ if raised != nil {
325+ if ! raised .isInstance (StopIterationType ) {
326+ b .Fatalf ("iteration failed with: %v" , raised )
327+ }
328+ f .RestoreExc (nil , nil )
329+ break
330+ }
331+ }
332+ }
333+ runtime .KeepAlive (ret )
334+ runtime .KeepAlive (raised )
335+ }
336+ }
337+
338+ b .Run ("0-elements" , bench (newTestDict ()))
339+ b .Run ("1-elements" , bench (newTestDict (1 , 2 )))
340+ b .Run ("2-elements" , bench (newTestDict (1 , 2 , 3 , 4 )))
341+ b .Run ("3-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 )))
342+ b .Run ("4-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 )))
343+ b .Run ("5-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 )))
344+ b .Run ("6-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 )))
345+ b .Run ("7-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 )))
346+ b .Run ("8-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 )))
347+ }
348+
349+ func BenchmarkDictIterValues (b * testing.B ) {
350+ bench := func (d * Dict ) func (* testing.B ) {
351+ return func (b * testing.B ) {
352+ f := NewRootFrame ()
353+ args := f .MakeArgs (1 )
354+ args [0 ] = d .ToObject ()
355+ b .ResetTimer ()
356+
357+ var ret * Object
358+ var raised * BaseException
359+ for i := 0 ; i < b .N ; i ++ {
360+ iter , _ := dictIterValues (f , args , nil )
361+ for {
362+ ret , raised = Next (f , iter )
363+ if raised != nil {
364+ if ! raised .isInstance (StopIterationType ) {
365+ b .Fatalf ("iteration failed with: %v" , raised )
366+ }
367+ f .RestoreExc (nil , nil )
368+ break
369+ }
370+ }
371+ }
372+ runtime .KeepAlive (ret )
373+ runtime .KeepAlive (raised )
374+ }
375+ }
376+
377+ b .Run ("0-elements" , bench (newTestDict ()))
378+ b .Run ("1-elements" , bench (newTestDict (1 , 2 )))
379+ b .Run ("2-elements" , bench (newTestDict (1 , 2 , 3 , 4 )))
380+ b .Run ("3-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 )))
381+ b .Run ("4-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 )))
382+ b .Run ("5-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 )))
383+ b .Run ("6-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 )))
384+ b .Run ("7-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 )))
385+ b .Run ("8-elements" , bench (newTestDict (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 )))
386+ }
387+
247388func TestDictGetItemString (t * testing.T ) {
248389 getItemString := newBuiltinFunction ("TestDictGetItemString" , func (f * Frame , args Args , _ KWArgs ) (* Object , * BaseException ) {
249390 if raised := checkFunctionArgs (f , "TestDictGetItem" , args , DictType , StrType ); raised != nil {
0 commit comments