11"""Run JSON benchmarks on given modules."""
2+
23import sys
34from collections import namedtuple
45from timeit import timeit
5- from types import ModuleType
6- from typing import Any
76
87# XXX: here you set which modules you want to benchmark
9- MODULES_TO_TEST = ["fast_json" , "pyjson5" , "rapidjson" , "simplejson" , "ujson" ]
8+ MODULES_TO_TEST = [
9+ "fast_json" ,
10+ "orjson" ,
11+ "pyjson5" ,
12+ "rapidjson" ,
13+ "simdjson" ,
14+ "simplejson" ,
15+ "ujson" ,
16+ ]
1017MODULE_REF = "json"
1118
1219RAW = (
3239Ref = namedtuple ("Ref" , "loads, dumps" )
3340
3441
35- def run_dumps (implementation : ModuleType ) -> str :
36- return implementation .dumps (FORMATED )
37-
38-
39- def run_loads (implementation : ModuleType ) -> dict [str , Any ]:
40- return implementation .loads (RAW )
41-
42-
4342def run (stmt : str , setup : str ) -> float :
4443 try :
4544 timeit (setup = setup , number = 1 )
@@ -77,22 +76,22 @@ def benchmark(*implementations: str) -> None:
7776
7877 for impl in implementations :
7978 loads = run (
80- f"run_loads( { impl } )" ,
79+ "loads(RAW )" ,
8180 "; " .join (
8281 [
83- f"import { impl } " ,
84- "from __main__ import FORMATED, run_loads " ,
85- f "assert run_loads( { impl } ) == FORMATED" ,
82+ f"from { impl } import loads " ,
83+ "from __main__ import FORMATED, RAW " ,
84+ "assert loads(RAW ) == FORMATED" ,
8685 ]
8786 ),
8887 )
8988 dumps = run (
90- f"run_dumps( { impl } )" ,
89+ "dumps(FORMATED )" ,
9190 "; " .join (
9291 [
93- f"import { impl } " ,
94- "from __main__ import run_dumps " ,
95- f "assert isinstance(run_dumps( { impl } ), str)" ,
92+ f"from { impl } import dumps " ,
93+ "from __main__ import FORMATED " ,
94+ "assert isinstance(dumps(FORMATED ), str)" ,
9695 ]
9796 ),
9897 )
@@ -101,20 +100,38 @@ def benchmark(*implementations: str) -> None:
101100 reference = Ref (loads , dumps )
102101 candidates .append ((False , impl , loads , 1.0 , dumps , 1.0 ))
103102 else :
104- loads_coef = loads / reference .loads
105- dumps_coef = dumps / reference .dumps
103+ loads_coef = loads / reference .loads or 10
104+ dumps_coef = dumps / reference .dumps or 10
106105 is_candidate = is_potential_candidate (loads_coef , dumps_coef )
107- candidates .append ((not is_candidate , impl , loads , loads_coef , dumps , dumps_coef ))
106+ candidates .append (
107+ (not is_candidate , impl , loads , loads_coef , dumps , dumps_coef )
108+ )
108109
109110 signs = {None : "!" , True : "+" , False : "-" }
110111 fmt = "{} {} loads: {} {} | dumps: {} {}"
111112 for is_candidate , impl , loads , loads_coef , dumps , dumps_coef in sorted (
112113 candidates , key = lambda c : (c [0 ], c [3 ] + c [5 ], c [1 ])
113114 ):
115+ if loads_coef >= 10 :
116+ loads_coef = 0.0
117+ if dumps_coef >= 10 :
118+ dumps_coef = 0.0
119+ if loads_coef + dumps_coef == 0.0 :
120+ continue
121+
114122 # Ugly, I know. But to simplify the previous `sorted()` call, `is_candidate` is True for non candidate implementations
115123 is_candidate = not is_candidate
116124 sign = signs [is_candidate if impl != MODULE_REF else None ]
117- print (fmt .format (sign , impl .ljust (justify , "…" ), res (loads ), coef (loads_coef ), res (dumps ), coef (dumps_coef )))
125+ print (
126+ fmt .format (
127+ sign ,
128+ impl .ljust (justify , "…" ),
129+ res (loads ),
130+ coef (loads_coef ),
131+ res (dumps ),
132+ coef (dumps_coef ),
133+ )
134+ )
118135
119136
120137def main () -> int :
0 commit comments