77import pyarrow as pa
88import pyarrow .parquet as pq
99
10+ from format_bench .fair import FairOperation , result_evidence
1011from format_bench .runner import stats_ms
1112
1213
1314TABLE_NAME = "sensors"
1415
1516
16- def _measure (function : Callable [[], int ], warmups : int , iterations : int ) -> dict :
17+ def _normalize_result (name : str , value : Any ) -> Any :
18+ if value is None :
19+ return None
20+ if isinstance (value , bytes ):
21+ value = value .decode ("utf-8" )
22+ if name in {"temperature" , "pressure" }:
23+ return float (value )
24+ if name == "sequence" :
25+ return int (value )
26+ if name == "active" :
27+ return bool (value )
28+ return str (value )
29+
30+
31+ def _measure (function : Callable [[], pa .Table ], warmups : int , iterations : int ) -> dict :
32+ result = pa .table ({})
1733 for _ in range (warmups ):
18- function ()
19- samples , result = [], 0
34+ result = function ()
35+ samples = []
2036 for _ in range (iterations ):
2137 started = time .perf_counter_ns ()
2238 result = function ()
2339 samples .append ((time .perf_counter_ns () - started ) / 1_000_000 )
24- return {"timing" : stats_ms (samples ), "result" : result }
40+ return {
41+ "timing" : stats_ms (samples ),
42+ "result" : result .num_rows ,
43+ "evidence" : result_evidence (result , FairOperation .READ_ALL ),
44+ }
2545
2646
2747def _schema () -> tuple [Any , list [str ], list [Any ]]:
@@ -181,26 +201,50 @@ def run_tsfile_claim(
181201 end = min (points_per_device , start + max (1 , points_per_device // 10 ))
182202 device = f"device-{ device_index :03d} "
183203
184- def ts_query () -> int :
185- rows = 0
204+ def ts_query () -> pa . Table :
205+ rows = []
186206 with TsFileReader (str (tsfile_path )) as reader :
187207 with reader .query_table (
188208 TABLE_NAME , columns , start , end - 1 , tag_eq ("device" , device )
189209 ) as result :
190210 while result .next ():
191- rows += 1
192- return rows
211+ rows .append (
212+ {
213+ name : _normalize_result (
214+ name , result .get_value_by_name (name )
215+ )
216+ for name in columns
217+ }
218+ )
219+ return pa .Table .from_pylist (
220+ rows ,
221+ schema = pa .schema (
222+ [
223+ pa .field ("device" , pa .string ()),
224+ pa .field ("site" , pa .string ()),
225+ pa .field ("temperature" , pa .float64 ()),
226+ pa .field ("pressure" , pa .float64 ()),
227+ pa .field ("active" , pa .bool_ ()),
228+ pa .field ("sequence" , pa .int64 ()),
229+ ]
230+ ),
231+ )
193232
194- def parquet_query () -> int :
233+ def parquet_query () -> pa . Table :
195234 return pq .read_table (
196235 parquet_path ,
197236 columns = columns ,
198237 filters = [("device" , "=" , device ), ("timestamp" , ">=" , start ), ("timestamp" , "<" , end )],
199- ). num_rows
238+ )
200239
201240 ts_result = _measure (ts_query , warmups , iterations )
202241 parquet_result = _measure (parquet_query , warmups , iterations )
203- status = "MEASURED" if ts_result ["result" ] == parquet_result ["result" ] else "FAILED"
242+ status = (
243+ "MEASURED"
244+ if ts_result ["result" ] == parquet_result ["result" ]
245+ and ts_result ["evidence" ] == parquet_result ["evidence" ]
246+ else "FAILED"
247+ )
204248 return {
205249 "status" : status ,
206250 "rows" : devices * points_per_device ,
@@ -213,4 +257,8 @@ def parquet_query() -> int:
213257 },
214258 "bytes" : {"tsfile" : tsfile_path .stat ().st_size , "parquet" : parquet_path .stat ().st_size },
215259 "timing" : {"tsfile" : ts_result , "parquet" : parquet_result },
260+ "evidence" : {
261+ "tsfile" : ts_result ["evidence" ],
262+ "parquet" : parquet_result ["evidence" ],
263+ },
216264 }
0 commit comments