save_build_stats.py 3.02 KB
Newer Older
Martin Cejp's avatar
Martin Cejp committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python3

"""
CREATE TABLE public.builds (
    id serial NOT NULL,
    pipeline_timestamp timestamp(0) NOT NULL,
    pipeline_url varchar NOT NULL,
    branch varchar NOT NULL,
    commit_sha1 varchar(40) NOT NULL,
    commit_timestamp timestamp(0) NOT NULL,
    "attributes" json NULL,
    CONSTRAINT builds_pk PRIMARY KEY (id)
);
"""

import json
Martin Cejp's avatar
CI fun    
Martin Cejp committed
17
import logging
Martin Cejp's avatar
Martin Cejp committed
18
19
import os

20
from junitparser import JUnitXml
Martin Cejp's avatar
Martin Cejp committed
21
22
23
import psycopg


Martin Cejp's avatar
CI fun    
Martin Cejp committed
24
25
26
27
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


Martin Cejp's avatar
Martin Cejp committed
28
29
30
31
32
33
results = {}
results["commit_title"] = os.environ["CI_COMMIT_TITLE"]


# Results of simulation

34
35
36
37
38
if os.path.exists("results.xml"):       # ugh. fromfile() raises generic OSError
                                        # instead of FileNotFoundError
    xml = JUnitXml.fromfile("results.xml")

    failures = []
Martin Cejp's avatar
Martin Cejp committed
39

40
41
42
43
44
45
46
47
48
49
50
51
    for suite in xml:
        for case in suite:
            if any(r._tag == "failure" for r in case.result):
                logger.info("%s:%s FAIL", case.classname, case.name)
                failures.append(case.classname + ":" + case.name)
            else:
                logger.info("%s:%s PASS", case.classname, case.name)

    if len(failures) > 0:
        logger.info("cocotb FAIL")
        results["sim"] = dict(result="fail", failed_testcases=failures)
    else:
Martin Cejp's avatar
CI fun    
Martin Cejp committed
52
        logger.info("cocotb PASS")
Martin Cejp's avatar
Martin Cejp committed
53
        results["sim"] = dict(result="pass")
54
else:
Martin Cejp's avatar
CI fun    
Martin Cejp committed
55
    logger.error("results.xml not found")
Martin Cejp's avatar
Martin Cejp committed
56
57
    results["sim"] = dict(result=None)

58
59
# TODO: refactor completely to (probably) save results for individual tests
if os.path.exists("verilator.fail"):
Martin Cejp's avatar
CI fun    
Martin Cejp committed
60
    logger.info("verilator FAIL")
61
    results["sim"]["result"] = "fail"
Martin Cejp's avatar
CI fun    
Martin Cejp committed
62
63
64
65
66
elif os.path.exists("verilator.pass"):
    logger.info("verilator PASS")
    # do not change sim result
else:
    logger.error("verilator result unknown")
67
    results["sim"]["result"] = None
Martin Cejp's avatar
Martin Cejp committed
68

Martin Cejp's avatar
CI fun    
Martin Cejp committed
69

Martin Cejp's avatar
Martin Cejp committed
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# Results of P&R

try:
    with open("build/nextpnr-report.json", "rt") as f:
        report = json.load(f)

    results["build"] = dict(result="pass",
                            fmax=report["fmax"],
                            utilization=report["utilization"]
                            )
except FileNotFoundError:
    results["build"] = dict(result="fail")


Martin Cejp's avatar
Martin Cejp committed
84
85
# Benchmark

Martin Cejp's avatar
Martin Cejp committed
86
CPU_MHZ = 50
Martin Cejp's avatar
Martin Cejp committed
87
88
89
90
91
92
93
94
95
96
97

try:
    with open("dhrystones_per_second", "rt") as f:
        dmips = int(f.read()) / 1757
        results["benchmark"] = dict(dmips=dmips, dmips_per_mhz=dmips / CPU_MHZ)
except FileNotFoundError:
    logger.error("dhrystones_per_second not found")
except ValueError:
    logger.error("dhrystones_per_second malformed or test failed")


Martin Cejp's avatar
Martin Cejp committed
98
99
100
101
102
103
104
105
106
107
108
109
# Connect to DB

with psycopg.connect(os.environ["POSTGRES_CONN_STRING"]) as conn:
    cursor = conn.cursor()
    cursor.execute('INSERT INTO builds(pipeline_timestamp, pipeline_url, branch, commit_sha1, commit_timestamp, "attributes") VALUES (%s, %s, %s, %s, %s, %s)', (
        os.environ["CI_PIPELINE_CREATED_AT"],
        os.environ["CI_PIPELINE_URL"],
        os.environ["CI_COMMIT_BRANCH"],
        os.environ["CI_COMMIT_SHA"],
        os.environ["CI_COMMIT_TIMESTAMP"],
        json.dumps(results))
    )