def print_summary_graphs(self, kind, key: Callable[[TestCase], Any], key_fmt: Callable[[TestCase], Any], long_msg): groups = {key(v): key_fmt(v) for v in self.test_cases} if len(groups) <= 1: return # do not print one-liner graphs durations = defaultdict(timedelta) tile_sizes = defaultdict(int) tile_counts = defaultdict(int) for res in self.test_cases: durations[key(res)] += res.result.duration tile_sizes[key(res)] += res.result.bytes tile_counts[key(res)] += res.size() stats = { g: PerfSummary(duration=durations[g], tiles=tile_counts[g], bytes=tile_sizes[g]) for g in groups } setattr(self.results, kind, stats) old_stats = getattr(self.old_run, kind, None) if self.old_run else None speed_data = [] size_data = [] for grp, grp_desc in groups.items(): old = old_stats[grp] if old_stats and grp in old_stats else None speed_data.append(stats[grp].graph_msg(True, grp_desc, old)) size_data.append(stats[grp].graph_msg(False, grp_desc, old)) print_graph(f"{long_msg} generation speed (longer is better)", speed_data) print_graph(f"{long_msg} average tile sizes (shorter is better)", size_data, is_bytes=True)
async def run_test(self, conn: Connection, test: TestCase): results = [] print(f"\nRunning {test.format()}...") if self.verbose: print( f'Using SQL query:\n\n-------\n\n{test.query}\n\n-------\n\n') args = [ test.query, test.zoom, test.start[0], test.before[0] - 1, test.start[1], test.before[1] - 1, ] start = dt.utcnow() if self.summary: test.result.bytes = await conn.fetchval(*args) else: for row in await conn.fetch(*args): results.append(((row['z'], row['x'], row['y']), row['len'])) test.result.bytes += row['len'] test.result.duration = dt.utcnow() - start test.result.__post_init__() old = test.old_result if self.summary: print(test.result.perf_format(old)) return if test.size() != len(results): print( f"WARNING: Requested {test.size():,} tiles != got {len(results):,}" ) if not results: print(f"Query returned no data after {test.result.duration}") return test.tiles = len(results) results.sort(key=lambda v: v[1]) buckets = min(test.tiles, self.buckets) sums = [0] * buckets first = [buckets + 1] * buckets last = [buckets + 1] * buckets last_ind = -1 for ind, val in enumerate(results): i = int(float(ind) / test.tiles * buckets) sums[i] += val[1] last[i] = ind if last_ind != i: first[i] = ind last_ind = i test.result.buckets = [] for i in range(buckets): smallest = results[first[i]] largest = results[last[i]] test.result.buckets.append( PerfBucket( smallest_id='/'.join(map(str, smallest[0])), smallest_size=smallest[1], largest_id='/'.join(map(str, largest[0])), largest_size=largest[1], bytes=sums[i], tiles=(last[i] - first[i] + 1), )) old_buckets = old and old.buckets or [] print_graph( f"Tile sizes for {test.tiles:,} tiles " f"(~{test.tiles / buckets:.0f}/line) done in " f"{round_td(test.result.duration)} " f"({test.result.gen_speed:,.1f} tiles/s" f"{change(old.gen_speed, test.result.gen_speed, True) if old else ''})", [ v.graph_msg( old_buckets[ind] if ind < len(old_buckets) else None) for ind, v in enumerate(test.result.buckets) ], is_bytes=True)