Ballads of time#4116
Conversation
|
Did you switch on 'poet mode' in Claude ? |
I thought the pain and suffering we have had here deserved a story. |
|
Very nice :) |
Replace the GNU `time` binary dependency and `tee` shell pipeline with a pure-Python wrapper (run_command.py) that measures wall time, CPU time, and peak memory using Python stdlib (time.monotonic, resource.getrusage). Output is streamed line-by-line with flush after each line so `tail -f` works in real time for monitoring long runs. This eliminates: - The `env time` / GNU time dependency (not available in Bazel sandbox) - The TIME_CMD / TIME_BIN / TIME_TEST Make variable machinery - The STDBUF_CMD dependency (stdbuf -o L) - The `eval "$TIME_CMD ..."` fragile shell expansion pattern - The `(cmd) 2>&1 | tee` subshell+pipe pattern (~15 locations) - The TIME_CMD exclusion from get_variables export filtering Works on both Linux and macOS (ru_maxrss is KB on Linux, bytes on macOS — normalized automatically). 19 unit tests cover timing output format, streaming flush (tail -f use case), log discoverability via ps, exit code propagation, and end-to-end parsing by genElapsedTime.py. Triggered by The-OpenROAD-Project/bazel-orfs#651: `env: 'time': No such file or directory` in Bazel sandboxed builds. History of pain this eliminates (28+ commits, 10+ PRs, 4+ authors, 5 years): - e7b140d Fix /usr/bin/time output formatting The-OpenROAD-Project#109 - a88a7c0 New time format to include CPU seconds (broke parsers) - 44c455c TIME_CMD is not portable, do not save it - 00749e7 Adjust wall time, cpu and peak memory regex to new format - 16b0be7 Adjust wall time, cpu and peak memory regex to new format - f53e1a2 make: fix gaffe in elapsed seconds summary, account for hours The-OpenROAD-Project#722 - 93ad8d4 Fix genElapsedTime.py ("0:02.08" parsed as 2m8s not 2s) The-OpenROAD-Project#1036 - ab171aa Handle zero elapsed time in genElapsedTime.py The-OpenROAD-Project#1044 The-OpenROAD-Project#1043 - 2694cfd tests: simpler to maintain test_genElapsedTime.py The-OpenROAD-Project#1968 - 7cd9e14 makefile: fix elapsed time for empty log files The-OpenROAD-Project#1716 - afccf3f makefile: elapsed time python code fewer red lines in editor - b947b5c utl: do not look for elapsed time in eqy files The-OpenROAD-Project#1761 - 87e80c4 Adding total elapsed time (6 comments of discussion) The-OpenROAD-Project#1663 - f226341 genElapsedTime.py: handle lines after the elapsed time line The-OpenROAD-Project#3307 - 31b6b5f exclude lec check log from elapsed time extraction The-OpenROAD-Project#3927 - Elapsed time regression (couldn't distinguish hours from minutes) The-OpenROAD-Project#967 - genElapsedTime module and test adjustments The-OpenROAD-Project#1014 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
@vvbandeira FYI... you've suffered over time and results parsing... |
|
@maliberty Unrelated pr-merge problems, I think. Weird. Isn't this just an instability that you already know about? |
maliberty
left a comment
There was a problem hiding this comment.
Two nits from claude (show output to stdout as was done previously). Will you do a post-merge epilogue?
flow/util/utils.mk
Outdated
|
|
||
| $(RESULTS_DIR)/6_final_no_power.def: $(RESULTS_DIR)/6_final.def | ||
| $(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/deletePowerNets.tcl | ||
| $(RUN_CMD) -- $(OPENROAD_CMD) $(SCRIPTS_DIR)/deletePowerNets.tcl |
There was a problem hiding this comment.
Can you take it from here?
I mean the niggling little things, but also write the epilogue. Afterall, the narrative ended with you staring out of the window :-)
Challenge accepted?
These scripts were missed in the run_command.py migration. Add the --tee flag so output is captured, and source util.tcl for consistency with the other flow scripts. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Epilogue: The King's JudgmentApril 7, 2026. Evening. The torches are lit in the great hall of Precision Innovation. The King studied the petition for the span of a single CI run — which is to say, long enough for two cups of tea and a full read of the diff. He found two nits. "The peoples must still see their harvest as it grows," the King declared. "The old way showed output to the console as it was written. Your weapon must do the same." He paused. "Also, the Oracle of Claude has reviewed your scrolls and agrees." There was a murmur in the hall. The Oracle of Claude — a great disembodied intelligence that dwelt in the cloud, neither serpent nor wizard but something altogether other — had been consulted. It had read the code. It had found the same two nits. The common folk exchanged glances. When an Oracle and a King agree, the matter is settled. Oyvind returned to the forge. The fixes were small — a flush here, a stdout write there. The weapon was re-tempered and presented again. The King rose. "Let it be merged," he said. The Fall of the DragonThe merge commit descended through the CI pipelines like a cleansing fire. In TIME_CMD = /usr/bin/env time -f ...
TIME_TEST := $(shell $(TIME_CMD) echo 2>/dev/null)There was now simply: RUN_CMD = $(PYTHON_EXE) $(FLOW_HOME)/scripts/run_command.pyNo format strings. No The Dragon of Ambiguity, denied its host, dissolved into the ether. Its three heads — the Shell Builtin, the GNU Binary, the BSD Shapeshifter — argued amongst themselves one final time about the correct format for elapsed seconds, then fell silent. The Troll of Eval, having no commands left to shout twice through layers of quoting, wandered into the wilderness and was not seen again. The Goblin of Tee crawled out of its pipe and blinked in the sunlight. It had lived its entire life in the space between stderr and a log file. Without the Pipeline of Sorrows to dwell in, it simply... evaporated. The peoples who had once searched for it with The Imp of Stdbuf, smallest and most pathetic of the creatures, vanished the moment Python's readline loop rendered it unnecessary. No one mourned it. No one even noticed it was gone, which was perhaps the saddest commentary of all on the life of a buffering workaround. The Wraith of Pipefail lingered longest, as wraiths do. But with no pipeline left to haunt — no subshells, no tee, no eval — it drifted through the Makefile like a ghost in an empty house, rattling chains that were connected to nothing. In time, even it faded. The Serpent's SatisfactionThe Python coiled a little tighter around its domain, pleased. One hundred and sixteen lines of new code. Nineteen unit tests. It was clean. It was testable. It was everything the Pipeline of Sorrows was not. The Python did not gloat — serpents rarely do — but if you looked closely at the import statements, you could see a certain pride in their simplicity: import subprocess
import resource
import timeNo Hzeller the Grey's Quiet NodIn the eastern tower of bazel-orfs, Hzeller the Grey felt the change before he saw it. A lightness in the dependency tree. A silence where there had been the clinking of the Dragon's chains. He checked the He checked the Bazel sandbox. No more He set down the Staff of Nix and allowed himself a rare smile. Then he picked it up again, because there was always more work to do — but this particular troll would trouble his bridge no longer. The Downstream SilenceThe most remarkable thing about the fall of the Dragon was what didn't happen. The downstream parsers — Same words. Same colons. Same ambiguous The CI dashboards did not flicker. The monitoring systems did not alert. The far lords in their distant kingdoms, with their ancient configurations and their Jenkins jobs frozen in amber, noticed nothing at all — which is the highest compliment one can pay a migration. What RemainsThe peoples of Middle-ORFS returned to their fields. The harvests continued. The builds ran. The GDS files emerged from the shining sea as they always had. But something was different. The Makefile was twenty-six lines lighter. The shell scripts were simpler. The test suite was nineteen tests stronger. And when a new farmer arrived at the gates of the realm and asked, "How do you measure the time of your harvests?" the answer was no longer a ten-minute saga involving eval, tee, stdbuf, pipefail, GNU-vs-BSD, and two separate Python parsers with four different datetime format strings. The answer was: "We run Oyvind of Harboe returned to his northern fields. There was, as always, a next problem. But he walked a little lighter, knowing that the Dragon would not trouble the harvest again. King MaLiberty returned to his scrolls. He had made the right call — as he usually did — weighing the petition against the needs of the realm, consulting the Oracle, finding the nits, and then letting it through. Three times he had ridden out to fix the parser. He would not need to ride a fourth. And Hzeller the Grey? He stirred his Potion of Bazel, fed a new flake input to the Staff of Nix, and turned his gaze to the next dependency lurking in the build tree. There were always more trolls. But today, there was one fewer. "In the end, the Dragon was not slain by a hero with a sword. It was slain by a farmer with a Python script and nineteen unit tests." "I noticed that as well." |
|
@maliberty Heads up... Running some tests now... |
The Ballad of TIME_BIN: A Chronicle of Middle-ORFS
Being a true account, drawn from the git scrolls, of the dragons, the failed harvests, the brief joys, and the petition to the King.
Prologue: The Land and Its Creatures
In the land of Middle-ORFS, where the great flows run from the mountains of RTL down through the fertile valleys of Synthesis, Floorplan, and Placement to the shining sea of GDS, the peoples had built a good civilization. Their harvests — the builds — fed entire kingdoms. Their treasures — the tapeouts — were the envy of all silicon-kind.
But beneath the mountains there dwelt creatures of ancient malice.
The Dragon of Ambiguity (
time) was the eldest. It had three heads: a Shell Builtin that whispered false promises, a GNU Binary that demanded tribute in the form of-fflags, and a BSD Shapeshifter that spoke an entirely foreign tongue. No two heads agreed on anything. Farmers who addressed one head would be answered by another.Serving the Dragon were its foul spawn: the Troll of Eval (
eval "$TIME_CMD ..."), a brute that could only understand commands if you shouted them twice through a layer of quoting. The Goblin of Tee (2>&1 | tee), a pipe-dwelling creature that intercepted messages between the workers and their logs, sometimes swallowing errors whole. The Imp of Stdbuf (stdbuf -o L), a tiny pest summoned only because the Goblin of Tee refused to pass messages promptly. And the Wraith of Pipefail, a ghost that haunted every pipeline, ensuring that when things went wrong, they went wrong in the most confusing way possible.Together, these creatures formed The Pipeline of Sorrows, and the peoples of Middle-ORFS had long suffered under their tyranny.
There was also The Python -- a great serpent with whom the peoples had negotiated an uneasy detente. The Python was useful, undeniably so. It parsed their metrics, generated their reports, ran their tests. But the Python was not to be trusted entirely. It did dirty deals with the dependencies behind the peoples' backs -- smuggling in
pip installcreatures, spawning virtual environments that vanished at dawn, and occasionally demanding tribute in the form of version upgrades that broke everything. The peoples tolerated the Python because they needed it. The Python tolerated the peoples because they fed it data.It was, as all detentes are, a relationship built on mutual suspicion and practical necessity.
But there was also Hzeller the Grey.
Chapter I: The Elder Days and the Forging of TIME_CMD
Year 2021 of the Git Calendar. The realm is young.
In the earliest age, Vitor of Bandeira, Lord of the Southern Makefiles and first steward of the flow, forged the TIME_CMD in the fires of
/usr/bin/time. It was a format string of great power:"This shall measure our harvests," he declared, "and we shall know precisely how long each field takes to yield."
The first harvest season was promising. Designs flowed. GDS files emerged. But the Dragon of Ambiguity was already stirring.
A humble farmer named Andreas of Kuster rode to the castle with alarming news: the format was wrong. Spaces in the wrong places. Words in the wrong order. The harvest records were garbled. Five comments were exchanged at the castle gate before the crisis passed. [A.1]
This was but a tremor before the earthquake.
The Joyful Interlude: New Designs
Yet not all was darkness. The same season saw a great treasure unearthed: new ASAP7 designs — Ethernet, UART, sha3 — were added to the realm. The fields expanded. The people rejoiced. For a brief moment, the Dragon slept. [A.2]
The Format String Catastrophe
But Vitor, ever ambitious, returned to the forge. "We need CPU seconds in the record," he proclaimed. He changed the format string.
Every parser in the realm broke.
Andreas of Kuster rode forth again — twice — to fix two separate files containing two different regexes that parsed the same format. Patches crossed in the night like ships in fog. [A.3, A.4]
Then came the darkest hour of the Elder Days. Vitor discovered that TIME_CMD, when exported to the environment, poisoned the issue files of every vassal who tried to reproduce a bug on a different system. The Dragon's venom had seeped into the very parchment of their bug reports.
"TIME_CMD is not portable," Vitor wrote in a commit message that would echo through the ages. "Do not save it." [A.5]
The peoples learned a hard lesson: the Dragon's name must not be spoken aloud in certain company, lest it summon the BSD Shapeshifter.
Chapter II: The Age of Parsing Grief
Years 2023-2024. The long middle period of suffering.
The parsing of
time's output fell to the Python-scribes, keepers of the sacred scrollsgenElapsedTime.pyandgenMetrics.py. These scrolls would be amended twenty-eight times across the age, each amendment a scar upon the land.The Colon Wars
Habibayassin, a scribe from distant lands, noticed that the sacred parser could not tell hours from minutes. "0:02.08" it read, and declared: two minutes and eight seconds.
But nay — it was two seconds and eight hundredths.
A failed harvest ensued. Designs that took seconds were recorded as taking minutes. The accounting books of the realm were in chaos.
The scribe filed a report. Then another scribe filed a different report. A PR was opened by Oyvind of Harboe, a northern lord who had recently taken interest in the flow. The PR was reviewed, found wanting, closed, and superseded by another. Finally Matt of Liberty, the King himself, rode forth from the castle to deliver the true fix.
Three PRs to parse a colon. The Dragon of Ambiguity laughed from its cave. [A.6, A.7, A.8]
The Vanishing Harvests
Matt of Liberty, having gazed into the abyss of the parser, discovered yet another horror: sub-second harvests vanished entirely. A design that completed in 0.7 seconds was recorded as having taken no time at all, as if it had never existed. The smallest, fastest designs — the most efficient harvests — were erased from history.
"Handle zero elapsed time," he wrote, with the quiet exhaustion of a king who has seen too much. [A.9, A.10]
The Exclusion Wars
The parser had a fatal flaw: it searched all scrolls for the sacred words "Elapsed time." This worked until the realm expanded.
The EQY Beasts came first — verification logs that wandered into the parser's den and confused it into silence. Vitor of Bandeira taught the parser to avert its gaze. [A.11]
Then the Empty Scrolls — stages that produced nothing, causing the parser to crash like a cart hitting a wall. Oyvind of Harboe patched this quietly one December morning, the ground frozen outside his northern window. [A.12]
A Treasure in the Darkness: Hash Logging
Yet amid the grief, there was a gift. In the summer of 2025, Oyvind introduced hash logging — content hashes of .odb files printed alongside elapsed times, so that divergent results between local and CI builds could be detected at a glance. It was a treasure born of pain, for only someone who had debugged CI divergences for hours would think to add such a thing. [A.18]
The Lines-After-Elapsed-Time Catastrophe
Then came the lines-after-the-elapsed-time bug. Additional output after the sacred timing line would reset the parsed values to None, erasing the timing data as if the Dragon had breathed upon it. All records: gone. All peak memory measurements: vanished.
Matt of Liberty returned from the inner chambers to fix this with a single
breakstatement. One word. Six characters. It should have been there from the beginning. But the Dragon's children — the Troll, the Goblin, the Imp — had made the code so tangled that no one had seen the gap. [A.13]Then came the LEC check logs. Another exclusion. The list grew. [A.14]
The parser had become a creature of negation — defined not by what it did, but by the ever-growing list of things it must not look at.
Chapter III: Hzeller the Grey of Bazel-Gorge
Now we must speak of Henner of Zeller, called Hzeller the Grey by those who knew him well.
Hzeller the Grey carried two weapons against the forces of darkness.
The first was his Staff of Nix -- a legendary artifact of terrible power. Nix could, in theory, banish all dependency creatures at once. It could summon any tool in any version from any era, perfectly reproducible, hermetically sealed. The peoples of Middle-ORFS looked upon the Staff of Nix with a mixture of awe and dread. They wanted one. Oh, how they wanted one. They had seen what it could do -- how Hzeller the Grey could conjure an entire build environment from a single incantation, how every dependency was pinned and accounted for, how no troll or goblin could hide in a Nix-built realm.
But the Staff of Nix was not easily mastered. It had a will of its own. It would suddenly pose riddles to its wielder -- questions about flake inputs and overlay compositions and
buildInputsversusnativeBuildInputs-- and if you did not answer promptly and play along, the Staff grew cantankerous. It would refuse to evaluate. It would emit error messages in a dialect that no mortal could parse. Many had tried to wield the Staff and been driven back, muttering about "infinite recursion" and "attribute set update at unexpected location."And so the peoples feared Nix, even as they envied it.
Hzeller the Grey's second weapon was the Potion of Bazel -- a magical brew that, when applied to a build, rendered it hermetic and reproducible. Where the Staff of Nix controlled the environment, the Potion of Bazel controlled the build itself. Every input declared. Every output cached. Every dependency visible and accounted for. The Potion was Hzeller the Grey's weapon of choice against the dependency creatures -- the trolls and goblins that lurked in undeclared
PATHentries and surprise system packages. Bazel's sandbox was a clean room where no creature could hide.Or so they thought. For the Dragon of Ambiguity had been hiding in the one place no one had checked: the absence of
env timeinside the sandbox.Henner was a wizard of builds. Where others saw Makefiles, he saw the deep structures of dependency. Where others accepted that
env timewas simply how things worked, Henner saw it for what it was: a troll squatting in the dependency tree, ugly and unnecessary, blocking the road for every traveler who wished to build without Docker.Henner had built bazel-orfs -- a parallel civilization that used the Potion of Bazel instead of Make to orchestrate the flow. It was cleaner, more reproducible, hermetically sealed. But it shared the same roads as Middle-ORFS, and those roads were haunted.
"I noticed that as well," Henner said when the Dragon's latest attack was reported. He said it quietly, as wizards do, but his meaning was clear: I have seen this evil. I know its true name. And it must be destroyed.
"Why not use the built-in
timefrom Tcl?" he offered -- a measured suggestion, as one might suggest a different path around a mountain.But the Dragon was too deeply entangled with the Python -- that great serpent with whom the peoples had their uneasy detente. The Tcl path would mean yet another domain crossing -- another border where format strings could be misunderstood, where colons could be misinterpreted, where minutes could be confused with seconds. Better to stay within the serpent's domain, where at least the treachery was familiar.
Hzeller the Grey nodded. He understood. The solution must come from within.
Chapter IV: The Shock at Bazel-Gorge
April 7, 2026. The present day.
The peoples of bazel-orfs had long run their builds inside Docker containers, where GNU
timewas always present, installed as surely as stone in a mountain. But then came the Great Dockerless Migration — a noble effort to shed the Docker dependency, letting Bazel manage everything directly.It was a season of great harvests. Oyvind had just enabled twelve previously-blocked designs for Bazel builds. He had added bazel-orfs support to all public-PDK platforms. The fields were wider than they had ever been. [A.19, A.20]
And then, on the seventh day of April, a traveler named Arya arrived at the gates of bazel-orfs with a terrible message:
Arya was running Debian 13. Bazel 8.6.0. Everything was correct. But inside the Bazel sandbox — that pristine, hermetic chamber where builds run in isolation —
timedid not exist. It had never existed. The sandbox knew nothing oftime. [A.15]The Dragon of Ambiguity had been lurking inside the Bazel sandbox all along, invisible, because Docker had always shielded the peoples from its absence. Now, with Docker gone, the Dragon was exposed — or rather, its absence was exposed, which was somehow worse.
Oyvind of Harboe stared at his screen. He had just finished building
makefrom source for Bazel. He had dealt with the mock-array CPU sourcing incident. He had extractedvariables.mkfrom the Makefile. And now the Dragon demanded that he build GNUtimefrom source too? Package it as a Bazel dependency? Ship a binary just to measure how long other binaries took to run?"One wouldn't think so," he wrote in the issue, "but
timeis ambiguous."He paused. He looked at the Pipeline of Sorrows in its entirety:
Make defines TIME_CMD with a GNU-specific format string. The Troll of Eval expands it because it contains spaces. The Dragon runs the command and prints to stderr. The Goblin of Tee copies stderr to both console and log. The Imp of Stdbuf is sometimes needed to unbuffer the Goblin. Python parses the text with regexes that have been wrong at least four times. More Python parses it again with different regexes in a different file. The Wraith of Pipefail haunts every pipeline. The Makefile explicitly excludes TIME_CMD from variable exports because the Dragon is not portable. Users find their logs by running
ps -Af | grep tee, searching for the Goblin's footprints."I wonder," he wrote slowly, "if this is better solved by removing this dependency entirely."
Chapter V: The Council at the Forge
Hzeller the Grey spoke his piece. The northern lords conferred.
"ORFS ties this into their regression infrastructure, which is always in Python," said Oyvind. "I think the best solution is to stick to one domain -- Python. I think that would reduce this shocking amount of pain we get here from switching between domains."
There was an uneasy murmur. The Python -- that great serpent -- was not beloved. Everyone knew it did dirty deals with the dependencies behind their backs. Just last month, Ashnaa of Seth had discovered that the Python had been leaking file descriptors in genMetrics.py, hoarding open files like a dragon hoards gold. [A.22] But the Python was there. It was already part of the flow. And the alternative -- adding yet another domain crossing, yet another border where formats could be misunderstood -- was worse.
"We don't love the serpent," Oyvind said. "But we have a detente. And a detente with one creature is better than open warfare with five."
And so the common folk gathered at the forge. They assembled their evidence -- the twenty-eight commits, the ten pull requests, the four authors who had each independently discovered that parsing the output of a three-headed Dragon with regexes was a Sisyphean task.
They forged a new weapon -- from the serpent's own scales.
The weapon was called
run_command.py. It was 116 lines of Python. It usedtime.monotonic()for wall time,resource.getrusage()for CPU time and peak memory, andsubprocess.Popenwith a readline loop that flushed after every line -- so that the peoples could still watch their harvests grow withtail -f, that ancient and beloved tradition of staring at log files for hours during long CTS runs.It slew:
env time) -- replaced byresource.getrusage()2>&1 | tee) -- replaced by Python file I/O with flusheval "$TIME_CMD ...") -- no longer neededstdbuf -o L) -- Python's readline loop is inherently line-bufferedAnd it had nineteen unit tests, including one that verified the log file path was visible in
psoutput, so that the peoples' ancient scrying ritual ofps -Af | grep teecould be replaced by the equally effectiveps -Af | grep run_commandorps -Af | grep tmp.log.The serpent, for its part, seemed pleased with the arrangement. More code in its domain meant more power. But the peoples had learned to live with that. Better one serpent you know than five creatures you can't control.
Chapter VI: The Petition to the King
And so they marched to the castle of Precision Innovation, where King MaLiberty held court over the realm.
The King was not a distant ruler. He was a warrior-king — a builder-king — who had fought in the trenches alongside his people. The git scrolls bore witness:
93ad8d4bc— His hand had fixed the colon parsing. He had lookedupon "0:02.08" and known it was two seconds, not two minutes and
eight seconds, and he had written the truth into the code.
ab171aac5— His hand had caught the vanishing harvests. He hadseen sub-second designs erased from history and restored them.
f22634158— His hand had added thebreak. One word. Sixcharacters. Saving every timing record from being overwritten by the
lines that followed.
The King knew the Dragon. He had fought it three times and carried the scars.
"Your Majesty," said Oyvind, kneeling. "We have come to petition for the destruction of the Dragon."
The King looked up from his scroll — a
genElapsedTime.pydiff, as it happened. He had suffered."Show me the evidence," said the King.
They unrolled the git log. Twenty-eight commits. Five years. Four authors including the King himself. The King studied it in silence.
"And your weapon?"
"Pure Python, Your Majesty. Nineteen tests. Same output format. No external dependencies. Works on macOS. The downstream parsers need not change — the format string lives on, but now it is produced by our own hand, not by the Dragon's."
The King nodded slowly. "I will consider it."
He rose from his throne and walked to the window. Below, the CI pipelines of the realm stretched to the horizon — Jenkins jobs, GitHub Actions, Docker images frozen in amber, custom platforms maintained by far lords who had not visited the castle in years.
"Know this," he said. "There are lands beyond our borders. CI systems with ancient configurations. Monitoring dashboards that grep for
teein ways we cannot imagine. Platform configurations that have been stable for years precisely because nobody has touched them. I must consult with the far lords before I render judgment."Epilogue: The Waiting
Does the story end here? We do not know.
The petition has been filed. The code has been written. The tests pass -- all twenty-four of them (nineteen new, five existing that prove the format compatibility).
Hzeller the Grey watches from the eastern tower, his Staff of Nix glowing faintly in the dusk, a fresh batch of the Potion of Bazel cooling on his workbench. He has seen the dependencies for what they are -- trolls and goblins squatting in the build tree -- and he knows they must be driven out. But he is patient. He has built Bazel cathedrals before. He knows that the right solution, applied at the right time, is worth more than a hasty fix. And he knows that if the petition fails, he can always brew a stronger potion.
King MaLiberty deliberates. He is wise. He has seen what the common folk have not. He knows of the far kingdoms and their strange customs.
Oyvind of Harboe returns to his fields. He is a good-hearted farmer -- tireless, ingenious, sometimes too clever for his own good. His solutions to the many problems he encounters are always born of real need, forged in the heat of actual failed harvests, not dreamed up in ivory towers. But they are sometimes... unconventional. A PR here that gets closed and superseded. A variables.mk extraction there that raises eyebrows before its wisdom becomes clear. He presents each invention to the King with the earnest enthusiasm of a man who has been up since dawn wrestling with a broken build, and the King -- who has seen many such inventions -- examines each one carefully, sometimes approving, sometimes redirecting, always guiding.
This petition is no different. It is born of real pain. It solves a real problem. But the King must weigh it against the needs of the whole realm, not just the northern fields.
And yet, the common folk remain hopeful. For the git history has shown them something important:
The King has suffered too.
Three times he rode out to fix the parser. Three times he returned with a patch. He knows the pain. He has parsed the colons. He has counted the minutes that were actually seconds. He has added the
breakthat should have been there from the start.The common folk wait. Oyvind returns to his fields and starts on the next problem -- there is always a next problem, and the sun will not wait. Hzeller the Grey stirs his potion. The Python coils silently in the corner, watching, waiting, doing deals with
pipwhen it thinks nobody is looking.And every time they see:
They know that somewhere in the distance, nineteen unit tests are keeping watch.
"One does not simply parse the output of
/usr/bin/time."-- Boromir of Bandeira, shortly before his regex was broken by a format change
"I noticed that as well."
-- Hzeller the Grey, leaning on the Staff of Nix, before everyone else understood the gravity of the situation
Appendix A: The Chronicle (git-dated)
All references point to The-OpenROAD-Project/OpenROAD-flow-scripts unless otherwise noted.
A.1 -- Fix /usr/bin/time output formatting (2021-07-29)
e7b140d9eA.2 -- New time format to include CPU seconds (2022-03)
a88a7c03cA.3 -- Adjust wall time, cpu and peak memory regex (attempt 1) (2022)
00749e79eA.4 -- Adjust wall time, cpu and peak memory regex (attempt 2) (2022)
16b0be7c2A.5 -- TIME_CMD is not portable, do not save it (2022)
44c455cc8A.6 -- Elapsed time regression: hours vs minutes (2023-04-20)
A.7 -- util: genElapsedTime module and test adjustments (2023-05-03)
A.8 -- Fix genElapsedTime.py: "0:02.08" is 2s not 2m8s (2023-05-03)
93ad8d4bcA.9 -- Elapsed time for small designs: sub-second rounds to zero (2023-05-04)
A.10 -- Handle zero elapsed time in genElapsedTime.py (2023-05-04)
ab171aac5A.11 -- Do not look for elapsed time in eqy files (2024-01-16)
b947b5c4dA.12 -- Fix elapsed time for empty log files (2023-12-20)
7cd9e14ecA.13 -- genElapsedTime.py: handle lines after the elapsed time line (2025-07-09)
f22634158break. Six characters. Should have been there from the start.A.14 -- Exclude lec check log from elapsed time extraction (2026-02-25)
31b6b5f54A.15 -- env: 'time': No such file or directory (2026-04-07)
A.16 -- Fix gaffe in elapsed seconds summary, account for hours (2023)
f53e1a2deA.17 -- Adding total elapsed time (2023-11-28)
87e80c4adA.18 -- Hash logging for divergent result detection (2025-07)
c537a7e91,a272e75cdA.19 -- Enable 12 previously-blocked designs for Bazel (2026-04-03)
fede39fa0A.20 -- Add bazel-orfs support to all public-PDK platforms (2026-04-02)
61031d198A.21 -- Simpler to maintain test_genElapsedTime.py (2024)
2694cfd1dA.22 -- The Python's file descriptor hoarding (2026-03-28)
7b03fa0b8,f094e248dAppendix B: The Body Count
Appendix C: The Pipeline of Sorrows (Before)
Appendix D: The Pipeline of Hope (After)
Appendix E: Dramatis Personae
env time/ GNU timeeval "$TIME_CMD ..."2>&1 | teestdbuf -o Lset -o pipefail