8 from pathlib 
import Path
 
   11 from bokeh.layouts 
import column
 
   12 from bokeh.models 
import ColumnDataSource, Whisker
 
   13 from bokeh.plotting 
import figure, show
 
   14 from bokeh.transform 
import factor_cmap, jitter
 
   16 TimeNS = typing.NewType(
"TimeNS", int)
 
   20     """Variance informations""" 
   37         return f
"<Variance {self.mean=}, {self.median=}, {self.stddev=}>" 
   43     def __init__(self, name: str, times: list[TimeNS], variance: 
None | Variance):
 
   50         return Data(name, [], 
None)
 
   53         return f
"<Data {self.name=}, {self.times=}, {self.variance=}>" 
   57     """Convert JSON output time into TimeNS""" 
   58     t = float(bench[
"real_time"])
 
   59     if bench[
"time_unit"] == 
"ns":
 
   61     elif bench[
"time_unit"] == 
"us":
 
   62         return TimeNS(int(t * 1e3))
 
   63     elif bench[
"time_unit"] == 
"ms":
 
   64         return TimeNS(int(t * 1e6))
 
   65     elif bench[
"time_unit"] == 
"s":
 
   66         return TimeNS(int(t * 1e9))
 
   70     """Parse google benchmark JSON output""" 
   73     for bench 
in json_content[
"benchmarks"]:
 
   74         run_name = bench[
"run_name"]
 
   75         run_type = bench[
"run_type"]
 
   76         if run_type == 
"aggregate":
 
   77             aggregate_name = bench[
"aggregate_name"]
 
   78             variance = variance_dict.setdefault(run_name, Variance.default())
 
   79             if aggregate_name == 
"mean":
 
   81             elif aggregate_name == 
"median":
 
   83             elif aggregate_name == 
"stddev":
 
   85         elif run_type == 
"iteration":
 
   86             data = data_dict.setdefault(run_name, Data.from_name(run_name))
 
   89     for k, v 
in variance_dict.items():
 
   90         data_dict[k].variance = v
 
   92     return list(data_dict.values())
 
   96     """Convert data name into a nice label""" 
   97     return s.split(
"/")[1]
 
  101     """Compute data lower and upper bounds to display Whisker box""" 
  104         return (float(v.median - v.stddev), float(v.median + v.stddev))
 
  106         return (float(
"nan"), float(
"nan"))
 
  110     """Return a list with data name and time""" 
  111     return [(
class_name(data.name), t) 
for t 
in data.times]
 
  120     lower = lower_upper[:, 0]
 
  121     upper = lower_upper[:, 1]
 
  125         sizing_mode=
"stretch_width",
 
  127         background_fill_color=
"#efefef",
 
  128         title=
"Benchmark results",
 
  130     p.xgrid.grid_line_color = 
None 
  133     whisker_source = ColumnDataSource(data=dict(base=classes, upper=upper, lower=lower))
 
  138         source=whisker_source,
 
  142     error.upper_head.size = 20
 
  143     error.lower_head.size = 20
 
  147     flat_data = np.array(
 
  148         list(itertools.chain.from_iterable([
flatten_data(d) 
for d 
in datas]))
 
  151     scatter_source = ColumnDataSource(
 
  152         data=dict(cl=flat_data[:, 0], time=flat_data[:, 1].astype(int))
 
  156         jitter(
"cl", 0.3, range=p.x_range),
 
  158         source=scatter_source,
 
  162         color=factor_cmap(
"cl", 
"Light7", classes),
 
  170     for data_batch 
in itertools.batched(datas, 7):
 
  175             sizing_mode=
"stretch_width",
 
  183         raise argparse.ArgumentTypeError(f
"{file} is not a file")
 
  188     parser = argparse.ArgumentParser(description=
"Plot benchmark results")
 
  189     parser.add_argument(
"json_output", help=
"Include directory", type=is_file)
 
  195     args = parser.parse_args(args)
 
  201 if __name__ == 
"__main__":