Archived
deploy.
This commit is contained in:
+341
@@ -0,0 +1,341 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Performance and footprint | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Performance and footprint | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="Release-Upgrading-Performance">
|
||||
<h1 id="performance-and-footprint">Performance and footprint</h1>
|
||||
|
||||
<p>Every figure below is a measurement with its conditions stated, and where a change cost time to buy
|
||||
correctness that is said too. Read the ratios rather than the absolute times: several campaigns were
|
||||
run on Debug builds or on small machines, deliberately, because a paired A/B on one machine answers
|
||||
“did this get faster” far more reliably than an unpaired Release number on a fast one.</p>
|
||||
<h2 id="milling-physics-in-the-native-kernel">Milling physics in the native kernel</h2>
|
||||
<p>The per-step physics moved into <code>core.dll</code> in stages — engagement scan conversion, the force kernel,
|
||||
then the sequential temperature and wear chain. Measured as a same-day paired A/B, managed leg
|
||||
against native leg, on one circular test program:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Per touched step</th>
|
||||
<th>managed</th>
|
||||
<th>native</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Engagement build</td>
|
||||
<td>46.0 ms</td>
|
||||
<td><strong>5.03 ms</strong></td>
|
||||
<td>~9×</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Force (<code>GetMillingFoce</code>)</td>
|
||||
<td>17.1 ms</td>
|
||||
<td><strong>0.75 ms</strong></td>
|
||||
<td>~20×</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Temperature and wear chain</td>
|
||||
<td>3.97 ms</td>
|
||||
<td><strong>0.24 ms</strong></td>
|
||||
<td>~16×</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Whole play</strong></td>
|
||||
<td><strong>59.3 s / 16.1 GB allocated</strong></td>
|
||||
<td><strong>40.6 s / 3.4 GB allocated</strong></td>
|
||||
<td>−32% wall, −79% allocation</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Allocation is where the migration bites hardest: engagement construction alone fell from about
|
||||
5.2 GB to 29 MB per step.</p>
|
||||
<blockquote>
|
||||
<p><strong>Conditions.</strong> Debug x64, <code>EnablePhysics</code> on, collision off, one force worker, a two-core /
|
||||
four-thread laptop, ±10% thermal-throttle noise, single paired run per leg. Absolute times are not
|
||||
representative of a customer machine — the ratios are the claim.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>Numerical parity.</strong> Engagement, force and brief are bit-identical between the two legs <strong>on
|
||||
Windows</strong>. The Linux build is not bit-identical (different libm), so a cross-platform comparison
|
||||
should use a tolerance, not equality.</p>
|
||||
</blockquote>
|
||||
<h2 id="playing-a-long-program-stays-linear">Playing a long program stays linear</h2>
|
||||
<p><code>NcOptOption.Equals</code> ended on a null-propagating comparison of a dictionary that is created on
|
||||
demand and is null on virtually every option, so the whole comparison collapsed to <code>false</code> — an
|
||||
option compared unequal even to a copy of itself. Both record-on-change guards built on it were
|
||||
therefore dead: the session appended an option-map entry for <strong>every played act</strong> instead of only at
|
||||
change points, and the step rewrote unchanged entries. Reading the last recorded option through a
|
||||
LINQ <code>LastOrDefault</code> over a <code>SortedList<,></code> — which has no indexed fast path — then walked the whole
|
||||
map each time, so the two defects together made a long play quadratic.</p>
|
||||
<blockquote>
|
||||
<p>Measured on a 2.35-million-line Siemens program: the option map now holds <strong>1 entry instead of one
|
||||
per line</strong>, and the per-100,000-line rate stays <strong>flat</strong> instead of degrading from 73 s at the
|
||||
start of the file to about 11 minutes by 1.9 million lines.</p>
|
||||
</blockquote>
|
||||
<p>This applies to <strong>every</strong> runner and to sessions doing no optimization at all, because the call site
|
||||
is the session-level play loop. <code>GetHashCode</code> drops the dictionary in the same change, since it
|
||||
hashed by reference and would otherwise disagree with <code>Equals</code> — relevant if you use <code>NcOptOption</code>
|
||||
as a dictionary key.</p>
|
||||
<h2 id="where-the-time-actually-goes">Where the time actually goes</h2>
|
||||
<p>Worth knowing before you tune anything. After the migration, on the measured workload the <strong>whole
|
||||
parallel physics stage is about 3.3% of wall time</strong>, while the <strong>single-worker volume subtraction is
|
||||
about 77%</strong> — and that subtraction is single-worker as a correctness requirement, not as an
|
||||
oversight. Raising the force-worker count therefore buys nothing on any machine; the bottleneck
|
||||
moved rather than disappearing.</p>
|
||||
<p>What did change in the worker derivation is narrower than it sounds. An unmeasured six-core ceiling
|
||||
was removed, but it only ever governed the sweep workers, and only machines with <strong>nine or more
|
||||
logical processors</strong> see a different count; force workers are unchanged everywhere. The throughput
|
||||
benefit on such a machine has <strong>not</strong> been measured — the development machines are smaller — so this
|
||||
is a ceiling removal, not a claimed speedup.</p>
|
||||
<p>Queue depths became fixed item budgets (120 geometry, 3840 physics) rather than scaling with the core
|
||||
count, because those queues bound per-item memory: uncapped, a 64-core machine would have been handed
|
||||
40,960-deep physics queues. On machines with fewer than six cores this is a small <em>increase</em> in
|
||||
bounded-queue memory (from 80 / 2560), which is the honest cost of the change.</p>
|
||||
<h2 id="loading-a-large-stl-workpiece">Loading a large STL workpiece</h2>
|
||||
<p>Building the topology from an STL was quadratic in triangle count — a pointer-derived hash collapsed
|
||||
into a handful of buckets, so lookups degenerated into linear scans. On one 935,000-triangle binary
|
||||
STL, topology construction was <strong>99.6%</strong> of the entire load; reading the file off disk was 0.16% of
|
||||
it. With a multiplicative hash mix the build is linear:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Triangles</th>
|
||||
<th>before</th>
|
||||
<th>after</th>
|
||||
<th></th>
|
||||
<th>worst bucket</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>100,000</td>
|
||||
<td>8,711 ms</td>
|
||||
<td><strong>1,305 ms</strong></td>
|
||||
<td>6.7×</td>
|
||||
<td>2,245 → 21</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>300,000</td>
|
||||
<td>89,036 ms</td>
|
||||
<td><strong>4,750 ms</strong></td>
|
||||
<td>18.7×</td>
|
||||
<td>6,593 → 23</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Per-triangle cost is now flat (0.013 → 0.016 ms/tri across a 3× size increase), which is the real
|
||||
result: the cost grows with the mesh instead of with its square. Extrapolated to the full
|
||||
935,000-triangle mesh that is roughly <strong>14 minutes → 15 seconds</strong>.</p>
|
||||
<p>Deduplication and the resulting topology are unchanged — the equality predicate was not touched, and
|
||||
the 300,000-triangle case produces an identical 899,997 lines before and after. Separately, the
|
||||
managed-to-native STL handoff dropped from three full copies of the buffer (about 86 MB each, plus
|
||||
around twenty doubling reallocations) to two.</p>
|
||||
<blockquote>
|
||||
<p><strong>Conditions.</strong> Native test harness, debug CRT — which inflates container-operation constants, so
|
||||
the absolute milliseconds are an upper bound. The composition breakdown and the complexity change
|
||||
are build-configuration independent. The full-mesh figure is an extrapolation, not a measured run.</p>
|
||||
</blockquote>
|
||||
<h2 id="re-triangulating-after-a-cut">Re-triangulating after a cut</h2>
|
||||
<p>The marching-cubes step gained a lookup table, and produces fewer triangles for the same surface:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tree</th>
|
||||
<th>before</th>
|
||||
<th>after</th>
|
||||
<th></th>
|
||||
<th>triangles</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>17 MB diagnostic</td>
|
||||
<td>0.63 s</td>
|
||||
<td>0.29 s</td>
|
||||
<td>2.17×</td>
|
||||
<td>−35%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>30 MB demo</td>
|
||||
<td>1.29 s</td>
|
||||
<td>0.60 s</td>
|
||||
<td>2.15×</td>
|
||||
<td>−35%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>309 MB customer part</strong></td>
|
||||
<td><strong>14.68 s</strong></td>
|
||||
<td><strong>6.51 s</strong></td>
|
||||
<td><strong>2.25×</strong></td>
|
||||
<td><strong>−43%</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<blockquote>
|
||||
<p><strong>Scope.</strong> This lands on the rebuild burst after a cut invalidates cached geometry, <strong>not</strong> on
|
||||
steady-state rendering, which draws from the display cache and is unchanged.</p>
|
||||
</blockquote>
|
||||
<p>It is also an approximation change, not purely a speedup: a non-finite cut drops its triangles, so a
|
||||
sub-voxel feature vanishes at that level of detail instead of being capped. That is what fixed the
|
||||
broken-face slabs seen on RTCP paths. The contact-loop extraction used by milling physics
|
||||
deliberately still uses the previous walk, so physics results are untouched.</p>
|
||||
<h2 id="session-memory-a-long-program-no-longer-exhausts-the-client">Session memory: a long program no longer exhausts the client</h2>
|
||||
<p>A session retains every executed NC block for its whole lifetime. Once a block leaves the executing
|
||||
window its piece is now frozen to compact UTF-8.</p>
|
||||
<blockquote>
|
||||
<p>Measured on a 25,018-block play: <strong>session retention 406 MB → 142 MB</strong>, about 2.9×.</p>
|
||||
</blockquote>
|
||||
<p>The encoding itself is smaller than that ratio suggests — roughly 12 KB per line live against 1.6 KB
|
||||
frozen, about 12.9× — because a retained piece carries more than its JSON. The 2.9× is the figure
|
||||
that matters for whether a program fits in memory.</p>
|
||||
<p>The trade is explicit: after the freeze the <code>JsonObject</code> getter re-parses on every call and returns a
|
||||
fresh read-only snapshot, with no caching and no write-back. Code that reads the same piece
|
||||
repeatedly should hold the snapshot in a local. The switch is
|
||||
<a class="xref" href="../../api/Hi.MachiningProcs.NcRunnerSessionState.html#Hi_MachiningProcs_NcRunnerSessionState_FreezeExecutedPieces">FreezeExecutedPieces</a>, on by default.</p>
|
||||
<h2 id="sizing-a-meshed-workpiece">Sizing a meshed workpiece</h2>
|
||||
<p>A cube tree costs roughly <strong>3.2× its file size in RAM</strong> while loaded — a 10 GB <code>.wct</code> at 0.125 mm
|
||||
resolution is about 95 million nodes, holding around 25 GB of tree plus 6 GB of index. Tearing down a
|
||||
tree that size used to block the caller for over two minutes; disposal now runs serialized on a
|
||||
background chain, so the thread that dropped it does not wait. The remaining cost is genuine work:
|
||||
the live renderer must not be left showing geometry that no longer exists.</p>
|
||||
<h2 id="cutter-location-files-at-production-scale">Cutter-location files at production scale</h2>
|
||||
<p>Three costs were removed from the CL-to-machine path, and on a production-scale file they are the
|
||||
difference between replaying and appearing to hang: tool-offset resolution walked back to the distant
|
||||
<code>LOAD</code> block for every motion (O(N²), now O(1) through a modal section), the documentary
|
||||
program-to-Pn stamp did the same walk (now stamped once per run), and the program-zero query
|
||||
deep-cloned the whole equipment assembly on every motion block (now a cached per-run matrix over the
|
||||
live assembly). These are complexity changes; they have not been separately timed.</p>
|
||||
<h2 id="smaller-footprint">Smaller footprint</h2>
|
||||
<p>The embedded default font is handed to the display engine from memory, so an <strong>11 MB</strong> <code>.ttf</code> is no
|
||||
longer written into the process working directory on startup. The packages are x64-only, and
|
||||
HiNc-Resource no longer ships a duplicated nested copy of the CT-350 STL set.</p>
|
||||
<h2 id="things-that-cost-more-on-purpose">Things that cost more, on purpose</h2>
|
||||
<p><strong>Five-axis inverse kinematics.</strong> Tightening the orientation envelope from about 1.4e-3 rad to about
|
||||
1e-6 rad — measured maxima 1.5e-8 rad on the hot path and 2.1e-8 on teleport, a tip deviation of
|
||||
0.05 µm on a 50 mm tool — costs roughly eleven solver iterations where one used to do, so a
|
||||
posture-changing call went from about 23 µs to about 251 µs, and a teleport from 418 µs to 1607 µs.
|
||||
Only posture-changing RTCP and arc steps pay it: three-axis programs and constant-posture segments
|
||||
are exempt through the <code>McLinear</code> downgrade. In absolute terms a 1,432-step five-axis replay spends
|
||||
about 0.36 s in the solver. (Debug build including measurement overhead, so those microseconds are an
|
||||
upper bound.)</p>
|
||||
<p><strong>Machine-coordinate linear stepping.</strong> <a class="xref" href="../../api/Hi.Numerical.Acts.ActMcXyzLinearContour.html">ActMcXyzLinearContour</a> derives its
|
||||
step count from the <strong>euclidean</strong> length of the machine XYZ delta rather than the largest single-axis
|
||||
component, so <code>LinearResolution_mm</code> caps actual tool-tip travel per step. A diagonal move therefore
|
||||
produces up to √3× more steps than before at the same setting — more work, for a sampling density
|
||||
that now means what the setting says. Lower the resolution if the old step count was what you were
|
||||
budgeting for.</p>
|
||||
<h2 id="a-tuning-cliff-worth-knowing-about">A tuning cliff worth knowing about</h2>
|
||||
<p><code>MillingCycleDivisionNum</code> saturates. Raising it past roughly 180 buys no additional training accuracy
|
||||
while the cost keeps climbing: a training run that takes about four minutes at 180 takes hours at 720
|
||||
and needs on the order of 100 GB of RAM to do it. The default of 36 is for ordinary simulation; raise
|
||||
it for training, but not past the point where the curve flattens.</p>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user