Skip to content

Commit f054ecc

Browse files
committed
Record the machine that produced each library's results
The report's "System info" line was CPU model, RAM and distro, which is identical on ryzen-5950x-1 and ryzen-5950x-2, and nothing anywhere said which node a run came from. job_claim.host is the only place the hostname was written, and that is a live claim table - the next run overwrites it, so the question "which machine produced this result" was unanswerable a day later. Put the hostname in front of the report's system info, and store the hostname and the whole system info string in [libversion], which is already keyed (date, branch, libname) - one row per library per run, which is the right granularity now that libraries of the same branch can be claimed by different machines. Both schema changes are ADD COLUMN only: the rows already in the databases keep their results and read back NULL for a run whose machine was never recorded. sqlite migrates on user_version 3 -> 4 (and from 1 and 2, which also had to gain the columns); PostgreSQL uses ADD COLUMN IF NOT EXISTS, since the shared database is created once and never migrated. Verified on a copy of both: the existing rows survive, the new insert shape works, re-running createTables is a no-op, and the NATURAL JOIN in test.py is unaffected - the added names collide with nothing in omcversion or in a branch table. sqlite2postgres.py learns the two columns as well, and now fills a text column the source lacks with NULL instead of the string "0". What made this worth doing: ExternalMedia and Buildings' Utilities.IO.Python_3_8 models have been flipping in exact anti-phase on master since 2026-08-11, ten run pairs out of ten. It turned out that ExternalMedia does not load on the Ubuntu 22.04 node and the Buildings Python library does not load on the Ubuntu 24.04 nodes, so master alternating between two machines is the whole of it - but establishing that took cross-referencing a transient claim table against report timestamps, which is exactly the work this commit makes unnecessary. See OpenModelica/OpenModelica#16376.
1 parent 54cae49 commit f054ecc

3 files changed

Lines changed: 56 additions & 28 deletions

File tree

‎resultsdb.py‎

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,19 @@ def createTables(self, branch):
229229
if user_version == 0:
230230
# Table to lookup from a run (date, branch) to omcversion used
231231
cursor.execute("CREATE TABLE if not exists [omcversion] (date integer NOT NULL, branch text NOT NULL, omcversion text NOT NULL)")
232-
# Table to lookup from a run (date, branch) which library versions were used
233-
cursor.execute("CREATE TABLE if not exists [libversion] (date integer NOT NULL, branch text NOT NULL, libname text NOT NULL, libversion text NOT NULL, confighash integer NOT NULL)")
232+
# Table to lookup from a run (date, branch) which library versions were used,
233+
# and the machine that produced them
234+
cursor.execute("CREATE TABLE if not exists [libversion] (date integer NOT NULL, branch text NOT NULL, libname text NOT NULL, libversion text NOT NULL, confighash integer NOT NULL, host text, sysinfo text)")
234235
elif user_version == 1:
235236
cursor.execute("ALTER TABLE [libversion] ADD COLUMN confighash integer NOT NULL DEFAULT(0)")
237+
self.addLibversionHost(cursor)
236238
elif user_version == 2:
237239
for tbl in [t for t in self.tables() if t not in ["libversion", "omcversion"]]:
238240
cursor.execute("ALTER TABLE [%s] ADD COLUMN parsing real NOT NULL DEFAULT(0.0)" % tbl)
239-
elif user_version != 3:
241+
self.addLibversionHost(cursor)
242+
elif user_version == 3:
243+
self.addLibversionHost(cursor)
244+
elif user_version != 4:
240245
raise SystemExit("Unknown schema user_version=%d" % user_version)
241246

242247
cols = ", ".join("%s %s NOT NULL" % (c, SQLITE_TYPES[t]) for c, t in BRANCH_COLUMNS)
@@ -245,7 +250,18 @@ def createTables(self, branch):
245250
cursor.execute("DROP INDEX IF EXISTS [idx_%s_date]" % branch)
246251
cursor.execute("DROP INDEX IF EXISTS idx_omcversion_date")
247252
cursor.execute("DROP INDEX IF EXISTS idx_libversion_date")
248-
self.setUserVersion(3)
253+
self.setUserVersion(4)
254+
255+
def addLibversionHost(self, cursor):
256+
"""Add the host columns to an existing [libversion].
257+
258+
ADD COLUMN only, so the rows already there keep their results and simply
259+
read back NULL for a run whose machine was never recorded.
260+
"""
261+
have = set(r[1] for r in cursor.execute("PRAGMA table_info([libversion])"))
262+
for col in ["host", "sysinfo"]:
263+
if col not in have:
264+
cursor.execute("ALTER TABLE [libversion] ADD COLUMN %s text" % col)
249265

250266
def tables(self):
251267
return [t for (t,) in self.conn.execute("SELECT name FROM sqlite_master WHERE type='table'")]
@@ -399,7 +415,12 @@ def createTables(self, branch):
399415
date bigint NOT NULL, branch text NOT NULL, omcversion text)""")
400416
cursor.execute("""CREATE TABLE IF NOT EXISTS libversion (
401417
date bigint NOT NULL, branch text NOT NULL, libname text NOT NULL,
402-
libversion text, confighash bigint NOT NULL)""")
418+
libversion text, confighash bigint NOT NULL,
419+
host text, sysinfo text)""")
420+
# The shared database predates the host columns; add them without touching
421+
# the rows already in there, which keep their results and read back NULL.
422+
for col in ["host", "sysinfo"]:
423+
cursor.execute("ALTER TABLE libversion ADD COLUMN IF NOT EXISTS %s text" % col)
403424
cols = ", ".join("%s %s%s" % (c, POSTGRES_TYPES[t], " NOT NULL" if c in BRANCH_KEY else "")
404425
for c, t in BRANCH_COLUMNS)
405426
cursor.execute("CREATE TABLE IF NOT EXISTS %s (%s)" % (self.quote(branch), cols))

‎sqlite2postgres.py‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@
6969
LOOKUP_COLUMNS = {
7070
"omcversion": [("date", "bigint"), ("branch", "text"), ("omcversion", "text")],
7171
"libversion": [("date", "bigint"), ("branch", "text"), ("libname", "text"),
72-
("libversion", "text"), ("confighash", "bigint")],
72+
("libversion", "text"), ("confighash", "bigint"),
73+
("host", "text"), ("sysinfo", "text")],
7374
}
7475

7576
# Derived data, no longer generated by all-plots.py; not worth migrating.
@@ -233,8 +234,12 @@ def migrate_table(pg, sconn, source, tbl, columns, batch, quiet, skip_existing=F
233234
names = [c for c, _ in columns]
234235
have = sqlite_columns(sconn, tbl)
235236
missing = [c for c in names if c not in have]
236-
# Older databases lack "parsing"; test.py defaults it to 0.0 as well.
237-
select = ",".join(ident(c) if c in have else "0" for c in names)
237+
# Older databases lack "parsing", and ones older still lack the libversion
238+
# host columns. test.py defaults the numbers to 0; a text column a run never
239+
# recorded is NULL, not the string "0".
240+
types = dict(columns)
241+
select = ",".join(ident(c) if c in have else ("NULL" if types[c] == "text" else "0")
242+
for c in names)
238243

239244
create_table(pg, tbl, columns)
240245
last_rowid, rows_read, done = read_progress(pg, source, tbl)

‎test.py‎

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from joblib import Parallel, delayed
1313
import simplejson as json
1414
import psutil, subprocess, threading, hashlib
15+
import socket
1516
from subprocess import call
1617
from monotonic import monotonic
1718
from omcommon import friendlyStr, multiple_replace
@@ -993,6 +994,26 @@ def resultValues(model, libname, data, simulator=None):
993994
data.get("parsing") or 0.0
994995
)
995996

997+
def cpu_name():
998+
if isWin:
999+
return processor()
1000+
else:
1001+
for line in open("/proc/cpuinfo").readlines():
1002+
if "model name" in line.strip():
1003+
return (re.sub( ".*model name.*:", "", line, count=1)).strip()
1004+
1005+
if isWin:
1006+
lsb_release = ""
1007+
else:
1008+
try:
1009+
lsb_release = check_output_log(commands + ["cat","/etc/lsb-release"]).decode().strip()
1010+
lsb_release = dict(a.split("=") for a in lsb_release.split("\n"))["DISTRIB_DESCRIPTION"].strip('"')
1011+
except:
1012+
lsb_release = ""
1013+
1014+
hostname = socket.gethostname()
1015+
sysInfo = "%s: %s, %d GB RAM, %s%s" % (hostname, cpu_name(), int(math.ceil(psutil.virtual_memory().total / (1024.0**3))), ("Docker " + docker + " ") if docker else "", lsb_release)
1016+
9961017
for (resultBranch, simulator) in resultBranches:
9971018
db.createTables(resultBranch)
9981019
for key in stats.keys():
@@ -1003,7 +1024,7 @@ def resultValues(model, libname, data, simulator=None):
10031024
resultValues(model, libname, data, simulator))
10041025
for libname in stats_by_libname.keys():
10051026
confighash = stats_by_libname[libname]["conf"]["confighash"]
1006-
cursor.execute("INSERT INTO libversion VALUES (?,?,?,?,?)%s" % db.insertIgnore(), (testRunStartTimeAsEpoch, resultBranch, libname, stats_by_libname[libname]["conf"]["libraryLastChange"], confighash))
1027+
cursor.execute("INSERT INTO libversion VALUES (?,?,?,?,?,?,?)%s" % db.insertIgnore(), (testRunStartTimeAsEpoch, resultBranch, libname, stats_by_libname[libname]["conf"]["libraryLastChange"], confighash, hostname, sysInfo))
10071028
cursor.execute("INSERT INTO omcversion VALUES (?,?,?)%s" % db.insertIgnore(), (testRunStartTimeAsEpoch, resultBranch, omc_version))
10081029
"""
10091030
# Not really a good thing to do; was just done to make generation of the report simpler
@@ -1028,25 +1049,6 @@ def checkPhase(phase, n):
10281049
def is_non_zero_file(fpath):
10291050
return os.path.isfile(os.path.normpath(fpath)) and os.path.getsize(os.path.normpath(fpath)) > 0
10301051

1031-
def cpu_name():
1032-
if isWin:
1033-
return processor()
1034-
else:
1035-
for line in open("/proc/cpuinfo").readlines():
1036-
if "model name" in line.strip():
1037-
return (re.sub( ".*model name.*:", "", line, count=1)).strip()
1038-
1039-
if isWin:
1040-
lsb_release = ""
1041-
else:
1042-
try:
1043-
lsb_release = check_output_log(commands + ["cat","/etc/lsb-release"]).decode().strip()
1044-
lsb_release = dict(a.split("=") for a in lsb_release.split("\n"))["DISTRIB_DESCRIPTION"].strip('"')
1045-
except:
1046-
lsb_release = ""
1047-
1048-
sysInfo = "%s, %d GB RAM, %s%s" % (cpu_name(), int(math.ceil(psutil.virtual_memory().total / (1024.0**3))), ("Docker " + docker + " ") if docker else "", lsb_release)
1049-
10501052
# create target dir to move results without sync operations (win or when --noSync is used)
10511053
def stageRootFor(simulator, suffix):
10521054
"""The directory a branch is published from.

0 commit comments

Comments
 (0)