147 lines
4.3 KiB
Python
147 lines
4.3 KiB
Python
import click
|
|
import csv
|
|
import re
|
|
import sqlite3
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Tuple
|
|
|
|
@dataclass
|
|
class TimingData:
|
|
tasks: int
|
|
nodes: int
|
|
gpus_per_node: int
|
|
blockcount: Tuple[int, int, int]
|
|
array_index: int
|
|
|
|
# Given in seconds
|
|
timings_by_task: [float]
|
|
|
|
RUN_PATTERN = re.compile(r".*t([0-9]+)n([0-9]+)g([0-9]+)x([0-9]+)y([0-9]+)z([0-9]+)-([0-9]+)")
|
|
TIMING_PATTERN = re.compile(r"timing-([0-9]+)\.dat")
|
|
TIMING_ROW_PATTERN = re.compile(r"([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+).*")
|
|
|
|
def get_timing(timing_path: Path, action: str) -> float:
|
|
with timing_path.open(encoding="utf8") as timing_file:
|
|
for line in timing_file:
|
|
m = TIMING_ROW_PATTERN.match(line)
|
|
if not m:
|
|
continue
|
|
|
|
if m.group(1) == action:
|
|
return float(m.group(5))
|
|
|
|
raise f"Could not find action '{action}' in {timing_path}"
|
|
|
|
def get_timings(d: Path, action: str) -> [float]:
|
|
timings = []
|
|
for timing_path in d.iterdir():
|
|
i = int(TIMING_PATTERN.match(timing_path.name).group(1))
|
|
timings.append((i, get_timing(timing_path, action) / 1_000_000))
|
|
|
|
return [timing for i, timing in sorted(timings, key=lambda t: t[0])]
|
|
|
|
def get_outdir_timing_data(d: Path, action: str) -> TimingData:
|
|
match_results = RUN_PATTERN.match(d.name)
|
|
tasks = int(match_results.group(1))
|
|
nodes = int(match_results.group(2))
|
|
gpus_per_node = int(match_results.group(3))
|
|
blockcount = (
|
|
int(match_results.group(4)),
|
|
int(match_results.group(5)),
|
|
int(match_results.group(6))
|
|
)
|
|
array_index = int(match_results.group(7))
|
|
timings_by_task = get_timings(d / "timing", action)
|
|
|
|
return TimingData(
|
|
tasks,
|
|
nodes,
|
|
gpus_per_node,
|
|
blockcount,
|
|
array_index,
|
|
timings_by_task
|
|
)
|
|
|
|
@click.group()
|
|
def timing():
|
|
pass
|
|
|
|
@timing.command()
|
|
@click.argument(
|
|
"directories",
|
|
type=click.Path(exists=True, file_okay=False, path_type=Path),
|
|
nargs=-1
|
|
)
|
|
@click.option("--db", default="timings.db", help="Path of sqlite database file")
|
|
def make_timing_db(directories, db):
|
|
"""
|
|
Collect NAStJA timing data from all passed directories and save them into a SQLite database.
|
|
|
|
Drops the timings table from the given database and creates a new timings table.
|
|
|
|
@param db asjdas
|
|
"""
|
|
db = sqlite3.connect(db)
|
|
c = db.cursor()
|
|
c.execute("drop table if exists timings")
|
|
c.execute("create table timings (tasks, blockcount_x, blockcount_y, blockcount_z, array_index, averagetime)")
|
|
|
|
print("Collecting timing info...")
|
|
for d in directories:
|
|
print(d)
|
|
t = get_outdir_timing_data(d, "Sweep:DynamicECM")
|
|
c.executemany(
|
|
"insert into timings values (?, ?, ?, ?, ?, ?)",
|
|
[
|
|
(t.tasks, t.blockcount[0], t.blockcount[1], t.blockcount[2], t.array_index, sum(t.timings_by_task) / len(t.timings_by_task))
|
|
]
|
|
)
|
|
print("Done, committing into DB...")
|
|
|
|
db.commit()
|
|
|
|
print("Done!")
|
|
|
|
@timing.command()
|
|
@click.option("--db", default="timings.db", help="Path of sqlite database file")
|
|
@click.option("--time/--no-time", default=False, help="Print average time of best run instead of speedup")
|
|
def strong_dat(db, time):
|
|
db = sqlite3.connect(db)
|
|
c = db.cursor()
|
|
res = c.execute("""
|
|
select tasks, min(avg)
|
|
from (
|
|
select tasks, blockcount_x, blockcount_y, blockcount_z, sum(averagetime) / count(*) as avg
|
|
from timings group by tasks, blockcount_x, blockcount_y, blockcount_z
|
|
) group by tasks order by tasks asc;
|
|
""")
|
|
values = res.fetchall()
|
|
|
|
if not time:
|
|
print("gpus\tspeedup")
|
|
for tasks, time in values:
|
|
print(f"{tasks}\t{values[0][1] / time}")
|
|
else:
|
|
print("gpus\ttime")
|
|
for tasks, time in values:
|
|
print(f"{tasks}\t{time}")
|
|
|
|
@timing.command()
|
|
@click.option("--db", default="timings.db", help="Path of sqlite database file")
|
|
def weak_dat(db):
|
|
db = sqlite3.connect(db)
|
|
c = db.cursor()
|
|
res = c.execute("""
|
|
select tasks, avg(averagetime) as mean from timings group by tasks order by tasks asc
|
|
""")
|
|
values = res.fetchall()
|
|
|
|
print("gpus\tefficiency")
|
|
for tasks, mean in values:
|
|
print(f"{tasks}\t{values[0][1] / mean}")
|
|
|
|
if __name__ == "__main__":
|
|
timing()
|