Skip to content

Instantly share code, notes, and snippets.

@adamgreig
Last active December 1, 2023 19:43
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save adamgreig/b040b6e3d7a7a64f613780eae6c07930 to your computer and use it in GitHub Desktop.
Save adamgreig/b040b6e3d7a7a64f613780eae6c07930 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import re
import sys
import time
import subprocess
import multiprocessing
import termplotlib as tpl
import numpy as np
def run_npnr(seed):
args = [f"nextpnr-{sys.argv[2]}"] + sys.argv[3:] + ["--seed", str(seed)]
lims = {}
tars = {}
p = subprocess.run(args, capture_output=True, check=False, text=True)
for line in p.stderr.split("\n"):
matches = re.search("Max frequency for clock\s*'([^']*)': ([\d\.]*) MHz "
"\([A-Z]* at ([\d\.]*) MHz\)", line)
if matches is not None:
clk = matches.group(1)
lims[clk] = float(matches.group(2))
tars[clk] = float(matches.group(3))
return seed, lims, tars
def run_many(n=20):
print(f"Running {n} seeds...", end='', flush=True)
t0 = time.time()
pool = multiprocessing.Pool()
results = pool.map(run_npnr, range(n))
t = time.time() - t0
print(f" done in {t:.1f}s.")
seeds = [r[0] for r in results]
achieveds = [r[1] for r in results]
targets = results[0][2]
return targets, seeds, achieveds
def plot(target, achieved):
fig = tpl.figure()
lower = int(np.min(achieved))
upper = int(np.ceil(np.max(achieved)))
bins = int(upper - lower)
counts, bin_edges = np.histogram(achieved, bins, range=(lower, upper))
labels = [f"{x:.0f}MHz" for x in range(int(lower), int(upper))]
fig.barh(counts, labels, max_width=40, bar_width=1, show_vals=True, force_ascii=False)
fig.show()
def summarise(target, seeds, achieved):
best_seed = seeds[np.argmax(achieved)]
worst_seed = seeds[np.argmin(achieved)]
print(f"Target {target:.2f}MHz, worst case {min(achieved):.2f}MHz "
f"(seed {worst_seed}), "
f"best case {max(achieved):.2f}MHz (seed {best_seed}).")
n_good = sum(1 for a in achieved if a >= target)
spread = np.max(achieved) - np.min(achieved)
print(f"{n_good} above target ({n_good*100/len(seeds):.1f}%). "
f"Mean {np.mean(achieved):.2f}MHz, "
f"std. dev. {np.std(achieved):.2f}MHz, spread {spread:.2f}MHz.")
if __name__ == "__main__":
targets, seeds, achieveds = run_many(int(sys.argv[1]))
for clk in targets:
target = targets[clk]
achieved = [a[clk] for a in achieveds]
print("Clock", clk)
plot(target, achieved)
summarise(target, seeds, achieved)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment