Merge ca3-coord 3557bf9e into master (gate: green on 3557bf9e, recorded by tools/ci/pre-push.sh; landed on the build mirror)
This commit is contained in:
commit
d8459e7918
2 changed files with 152 additions and 72 deletions
151
site/build.mjs
151
site/build.mjs
|
|
@ -412,10 +412,12 @@ for (const [file, active] of PAGES) {
|
|||
|
||||
// the public bench table (/miners): one row per card, generator version and miner version, from site/miner-bench.json
|
||||
// (the bench-log numbers that exist today, and rows later jobs append); rendered through the same scrub as /bench.
|
||||
// 7 October 2026 (the founder): the CURRENT class (rows measured on the class v4 program, or class v3 rows re-measured with their
|
||||
// class v4 cost, 6 October on) is the table; the earlier classes (the genesis program, the hourly program, class v3 before
|
||||
// the shadow) sit collapsed below so no reader compares a 228 MH/s genesis row with a 136 MH/s class v3 row as one thing.
|
||||
// Every header sorts on a click (default MH per watt, high first); the sort is a few lines of script in the page.
|
||||
// 7 October 2026 (the founder): the CURRENT class is the table (class v4, or class v3 re-measured with its v4 cost, 6 October
|
||||
// on); cards you can buy first by hash rate, the datacentre rows collapsed, the earlier classes collapsed; one row per
|
||||
// card; the card's vendor mark and name lead, the rate is the big tabular number, MH per wall watt beside it in the ember
|
||||
// tint for the best desktop card, watts and the class v4 cost quiet, the tuned state a pill, the date muted mono; the
|
||||
// Hive flight-sheet values, the source and the note in a row that opens on a tap; headers sort with an arrow glyph, the
|
||||
// active sort underlined in ember; 56 px rows on desktop, a two-line card per row on a phone.
|
||||
{
|
||||
const bj = JSON.parse(readFileSync(join(here, 'miner-bench.json'), 'utf8'));
|
||||
const isCurrent = (r) => r.generator === 'v2' && r.date >= '2026-10-06';
|
||||
|
|
@ -423,51 +425,58 @@ for (const [file, active] of PAGES) {
|
|||
const curAll = bj.rows.filter(isCurrent).sort(byRate);
|
||||
const cur = curAll.filter(r => r.group !== 'datacentre');
|
||||
const dcRows = curAll.filter(r => r.group === 'datacentre');
|
||||
const earlier = bj.rows.filter(r => !isCurrent(r)).sort((a, b) => (a.card < b.card ? -1 : a.card > b.card ? 1 : a.generator < b.generator ? -1 : a.generator > b.generator ? 1 : b.mh_s - a.mh_s));
|
||||
const earlier = bj.rows.filter(r => !isCurrent(r)).sort(byRate);
|
||||
const rows = bj.rows;
|
||||
const fmt = (n) => Number(n).toLocaleString('en-GB', { maximumFractionDigits: 1 });
|
||||
const fmt3 = (n) => Number(n).toLocaleString('en-GB', { maximumFractionDigits: 3 });
|
||||
// Nine compact columns sort; the long fields (the class v4 cost, the Hive values with their label, the miner and driver,
|
||||
// the source and the note) sit in a detail row under each card so a row stays one line wide at 1600 px (the 7 October
|
||||
// capture showed eleven columns clipped at five, every row inflated by off-screen wrapped text). The detail row moves
|
||||
// with its data row on a sort.
|
||||
const heads = [
|
||||
['Card', 'card', 'text'], ['MH/s', 'mh_s', 'num'], ['W', 'watts', 'num'], ['MH per wall watt', 'mh_per_w', 'num'],
|
||||
['v4 cost', 'v4_cost_short', 'text'], ['Tuned', 'tuned_short', 'text'], ['Hive core / mem / PL', 'hive_short', 'text'], ['Date', 'date', 'text'], ['Who', 'by', 'text'],
|
||||
];
|
||||
// the short forms are one clause: the first watts or percent figure of the cost ("+16 W", "+145.3 W unlocked"), the
|
||||
// tune state's first words; the full sentences live in the detail row
|
||||
const best = cur[0];
|
||||
const shortV4 = (r) => { if (r.v4_short) return r.v4_short; const v = r.v4_cost || 'not measured'; if (/^not measured/.test(v)) return 'not measured'; const m = v.match(/^([+-]?[\d.,]+\s*(?:W|percent)(?:\s+(?:unlocked|of rate))?)/); return m ? m[1].replace(' of rate', ' rate') : v.split(/[,;(]| for | at /)[0].trim(); };
|
||||
const shortTuned = (r) => { const v = r.tuned || 'stock, mining'; return v.split(/[:;(]/)[0].replace('full Ember Tune', 'Ember Tune').replace('stock, bench only', 'stock, bench').replace('no lever on Apple silicon', 'no lever').trim(); };
|
||||
const shortHive = (r) => { const h = r.hive; return (h && h.core_mhz != null) ? fmt(h.core_mhz) + ' / ' + fmt(h.mem_mhz) + ' / ' + fmt(h.pl_w) + ' W' : 'stock'; };
|
||||
const cells = (r) => [
|
||||
[r.card, r.card], [r.mh_s_display || fmt(r.mh_s), r.mh_s], [r.watts_display || (r.watts == null ? 'not read' : fmt(r.watts) + (r.watt_basis === 'chip' ? ' (chip watts, not wall)' : '')), r.watts ?? -1],
|
||||
[r.mh_per_w == null ? 'not measured' : (r.watt_basis === 'chip' ? '\u25CB ' + fmt3(r.mh_per_w) + ' (chip watts, not ranked)' : fmt3(r.mh_per_w)), r.watt_basis === 'chip' ? -1 : (r.mh_per_w ?? -1)],
|
||||
[shortV4(r), shortV4(r)], [shortTuned(r), shortTuned(r)], [shortHive(r), r.hive && r.hive.core_mhz != null ? 'a ' + r.hive.core_mhz : 'z stock'], [r.date, r.date], [r.by.replace('measured by the ', '').replace('reported by the ', 'reported, '), r.by],
|
||||
];
|
||||
const tunedState = (r) => { const v = r.tuned || 'stock, mining'; if (/Ember Tune|core lock/.test(v)) return ['tuned', 'Tuned']; if (/no lever/.test(v)) return ['nolever', 'No lever']; return ['stock', 'Stock']; };
|
||||
const effCell = (r) => {
|
||||
if (r.mh_per_w == null) return ['not measured', -1];
|
||||
if (r.watt_basis === 'chip') return ['<span class="hollow" title="chip watts (GPU plus DRAM), not wall; not ranked">○ ' + fmt3(r.mh_per_w) + '</span>', -1];
|
||||
return [(best && r === best ? '<span class="eff best">' : '<span class="eff">') + fmt3(r.mh_per_w) + '</span>', r.mh_per_w];
|
||||
};
|
||||
const detail = (r) => {
|
||||
const parts = [];
|
||||
parts.push('<b>Generator:</b> ' + esc(r.generator));
|
||||
parts.push('<b>Class v4 cost:</b> ' + esc(r.v4_cost || 'not measured'));
|
||||
parts.push('<b>Tuned:</b> ' + esc(r.tuned || 'stock, mining'));
|
||||
if (r.hive && r.hive.core_mhz != null) parts.push('<b>Hive flight sheet:</b> core lock ' + esc(fmt(r.hive.core_mhz)) + ' MHz, mem ' + esc(fmt(r.hive.mem_mhz)) + ' MHz, PL ' + esc(fmt(r.hive.pl_w)) + ' W (' + esc(r.hive.label) + ')');
|
||||
else if (r.hive && r.hive.label) parts.push('<b>Hive flight sheet:</b> ' + esc(r.hive.label));
|
||||
parts.push('<b>Miner:</b> ' + esc(r.miner + (r.driver_os ? ' (' + r.driver_os + ')' : '')));
|
||||
parts.push('<b>Source:</b> ' + esc(r.source));
|
||||
if (r.note) parts.push('<b>Note:</b> ' + esc(r.note));
|
||||
return parts.join(' · ');
|
||||
if (r.hive && r.hive.core_mhz != null) parts.push('<b>Hive flight sheet</b> core lock ' + esc(fmt(r.hive.core_mhz)) + ' MHz, mem ' + esc(fmt(r.hive.mem_mhz)) + ' MHz, PL ' + esc(fmt(r.hive.pl_w)) + ' W (' + esc(r.hive.label) + ')');
|
||||
else parts.push('<b>Hive flight sheet</b> stock' + (r.hive && r.hive.label ? ' (' + esc(r.hive.label.replace(/^stock \(|\)$/g, '')) + ')' : ''));
|
||||
parts.push('<b>Class v4 cost</b> ' + esc(r.v4_cost || 'not measured'));
|
||||
parts.push('<b>Tuned</b> ' + esc(r.tuned || 'stock, mining'));
|
||||
parts.push('<b>Generator</b> ' + esc(r.generator) + ' · <b>Miner</b> ' + esc(r.miner + (r.driver_os ? ' (' + r.driver_os + ')' : '')));
|
||||
parts.push('<b>Source</b> ' + esc(r.source) + ' · <b>Who</b> ' + esc(r.by));
|
||||
if (r.note) parts.push('<b>Note</b> ' + esc(r.note));
|
||||
return parts.map(x => '<span class="d">' + x + '</span>').join('');
|
||||
};
|
||||
const render = (list, id) => '<div class="tbl"><table class="sortable bench" id="' + id + '"><thead><tr>' +
|
||||
heads.map(([h, k, t]) => `<th data-key="${k}" data-type="${t}" aria-sort="${k === 'mh_s' ? 'descending' : 'none'}"><button type="button" class="sort">${h}</button></th>`).join('') +
|
||||
'</tr></thead><tbody>' + list.map(r => '<tr class="row">' + cells(r).map(([c, v]) => `<td data-v="${esc(String(v))}">${esc(String(c))}</td>`).join('') + '</tr>' +
|
||||
`<tr class="detail"><td colspan="${heads.length}">${detail(r)}</td></tr>`).join('') + '</tbody></table></div>';
|
||||
const heads = [['Card', 'card', 'text'], ['MH/s', 'mh_s', 'num'], ['MH per wall watt', 'mh_per_w', 'num'], ['Watts', 'watts', 'num'], ['Tuned', 'tuned', 'text'], ['', 'more', 'none']];
|
||||
const render = (list, id) => {
|
||||
const body = list.map((r, i) => {
|
||||
const [effHtml, effV] = effCell(r); const [tcls, tlabel] = tunedState(r);
|
||||
const sub = '<span class="gen">class v4 ' + esc(shortV4(r)) + ' <span class="dot">\u00B7</span> <span class="date">' + esc(r.date) + '</span></span>';
|
||||
const cells = [
|
||||
['lead', r.card, esc(r.card) + sub],
|
||||
['big tnum', r.mh_s, esc(r.mh_s_display || fmt(r.mh_s))],
|
||||
['tnum effc', effV, effHtml],
|
||||
['quiet tnum', r.watts ?? -1, r.watts_display ? esc(r.watts_display) + ' W' : (r.watts == null ? 'not read' : esc(fmt(r.watts)) + ' W' + (r.watt_basis === 'chip' ? ' <span class="basis">chip, not wall</span>' : ''))],
|
||||
['pillc', tlabel, '<span class="pill state ' + tcls + '">' + tlabel + '</span>'],
|
||||
['morec', '', '<button type="button" class="more" aria-expanded="false" aria-controls="' + id + '-d' + i + '">Details</button>'],
|
||||
];
|
||||
return '<tr class="row">' + cells.map(([c, v, h]) => `<td class="${c}" data-v="${esc(String(v))}">${h}</td>`).join('') + '</tr>' +
|
||||
`<tr class="detail" id="${id}-d${i}" hidden><td colspan="${heads.length}">${detail(r)}</td></tr>`;
|
||||
}).join('');
|
||||
return '<div class="tbl bench2wrap"><table class="bench2" id="' + id + '"><thead><tr>' +
|
||||
heads.map(([h, k, t]) => t === 'none' ? '<th></th>' : `<th data-key="${k}" data-type="${t}" aria-sort="${k === 'mh_s' ? 'descending' : 'none'}"><button type="button" class="sort">${h}</button></th>`).join('') +
|
||||
'</tr></thead><tbody>' + body + '</tbody></table></div>';
|
||||
};
|
||||
const table = render(cur, 'bench-current');
|
||||
const dcTable = render(dcRows, 'bench-datacentre');
|
||||
const earlierTable = render(earlier, 'bench-earlier');
|
||||
const bestLine = best ? `<p class="lede"><strong>Best desktop card:</strong> ${esc(best.card.replace(/ \(.*$/, ''))}, ${esc(fmt(best.mh_s))} MH/s, ${esc(fmt3(best.mh_per_w))} MH per wall watt tuned (measured, ${esc(best.date)}).</p>` : '';
|
||||
const sortScript = `<script>
|
||||
(function(){
|
||||
// header sort on the bench tables: a click sorts by that column (numbers by value, text by locale), a second click flips it;
|
||||
// each data row carries its detail row with it
|
||||
document.querySelectorAll('table.sortable').forEach(function(t){
|
||||
var ths=t.querySelectorAll('th'),tb=t.querySelector('tbody');
|
||||
ths.forEach(function(th,i){th.querySelector('button').addEventListener('click',function(){
|
||||
document.querySelectorAll('table.bench2').forEach(function(t){
|
||||
var ths=t.querySelectorAll('th[data-key]'),tb=t.querySelector('tbody');
|
||||
ths.forEach(function(th){var i=Array.prototype.indexOf.call(th.parentNode.children,th);th.querySelector('button').addEventListener('click',function(){
|
||||
var cur=th.getAttribute('aria-sort'),dir=cur==='descending'?'ascending':'descending',num=th.getAttribute('data-type')==='num';
|
||||
ths.forEach(function(o){o.setAttribute('aria-sort','none');});th.setAttribute('aria-sort',dir);
|
||||
var rows=Array.prototype.slice.call(tb.querySelectorAll('tr.row'));
|
||||
|
|
@ -475,15 +484,48 @@ for (const [file, active] of PAGES) {
|
|||
pairs.sort(function(a,b){var x=a[0].children[i].getAttribute('data-v'),y=b[0].children[i].getAttribute('data-v');var c=num?(parseFloat(x)-parseFloat(y)):x.localeCompare(y,'en');return dir==='descending'?-c:c;});
|
||||
pairs.forEach(function(p){tb.appendChild(p[0]); if(p[1]) tb.appendChild(p[1]);});
|
||||
});});
|
||||
t.querySelectorAll('button.more').forEach(function(b){b.addEventListener('click',function(){var d=document.getElementById(b.getAttribute('aria-controls'));if(!d)return;var open=d.hasAttribute('hidden');if(open)d.removeAttribute('hidden');else d.setAttribute('hidden','');b.setAttribute('aria-expanded',open?'true':'false');b.textContent=open?'Close':'Details';});});
|
||||
});
|
||||
})();
|
||||
</script>`;
|
||||
const sortStyle = '<style>th .sort{all:unset;cursor:pointer;font:inherit;color:inherit;white-space:nowrap}th .sort::after{content:" \\2195";opacity:.45}th[aria-sort="descending"] .sort::after{content:" \\2193";opacity:1}th[aria-sort="ascending"] .sort::after{content:" \\2191";opacity:1}table.bench{min-width:0;width:100%;table-layout:auto}table.bench tr.row td{border-bottom:0;white-space:normal;overflow-wrap:anywhere}table.bench tr.row td:nth-child(2),table.bench tr.row td:nth-child(3),table.bench tr.row td:nth-child(4),table.bench tr.row td:nth-child(8){white-space:nowrap}table.bench tr.row td:first-child{min-width:150px}table.bench tr.row td:nth-child(5),table.bench tr.row td:nth-child(6){white-space:nowrap}table.bench tr.row td:nth-child(7){white-space:nowrap}table.bench tr.detail td{font-size:13px;color:var(--ash);padding-top:0;overflow-wrap:anywhere;white-space:normal}table.bench tr.detail td b{color:var(--ink-2);font-weight:600}details.earlier{margin:var(--s-4) 0}p.best{font-size:18px;margin:0 0 14px}details.earlier summary{cursor:pointer;color:var(--bone)}</style>';
|
||||
const table = render(cur, 'bench-current');
|
||||
const dcTable = render(dcRows, 'bench-datacentre');
|
||||
const best = cur.slice().sort(byRate)[0];
|
||||
const bestLine = best ? `<p class="best"><strong>Best desktop card:</strong> ${esc(best.card.replace(/ \(.*$/, ''))}, ${esc(fmt(best.mh_s))} MH/s, ${esc(fmt3(best.mh_per_w))} MH per wall watt tuned (measured, ${esc(best.date)}).</p>` : '';
|
||||
const earlierTable = render(earlier, 'bench-earlier');
|
||||
const sortStyle = `<style>
|
||||
.lede{font-size:18px;line-height:1.5;color:var(--bone);margin:0 0 var(--s-4)}
|
||||
.grp{font:500 10px/1.4 var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ash);margin:var(--s-5) 0 10px;padding-bottom:8px;border-bottom:1px solid var(--line)}
|
||||
details.grp summary{cursor:pointer;list-style:none}details.grp summary::-webkit-details-marker{display:none}details.grp summary::after{content:" \\u25BE";opacity:.6}details.grp[open] summary::after{content:" \\u25B4"}
|
||||
.tbl.bench2wrap{overflow-x:auto;border:0;background:none;border-radius:0;max-width:100%}
|
||||
table.bench2{min-width:0;width:100%;border-collapse:collapse;font-size:14px;line-height:1.4}
|
||||
table.bench2 th{font:500 10px/1.4 var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash);text-align:left;padding:0 12px 10px;border-bottom:1px solid var(--line);white-space:nowrap}
|
||||
table.bench2 th .sort{all:unset;cursor:pointer;font:inherit;color:inherit;letter-spacing:inherit;text-transform:inherit;padding-bottom:3px;border-bottom:2px solid transparent}
|
||||
table.bench2 th .sort::after{content:" \\u2195";opacity:.4}
|
||||
table.bench2 th[aria-sort="descending"] .sort,table.bench2 th[aria-sort="ascending"] .sort{color:var(--bone);border-bottom-color:var(--ember)}
|
||||
table.bench2 th[aria-sort="descending"] .sort::after{content:" \\u2193";opacity:1;color:var(--ember)}table.bench2 th[aria-sort="ascending"] .sort::after{content:" \\u2191";opacity:1;color:var(--ember)}
|
||||
table.bench2 tr.row td{height:56px;padding:0 12px;border-bottom:1px solid var(--line);background:none;vertical-align:middle;white-space:nowrap;color:var(--ink-2)}
|
||||
table.bench2 tr.row:hover td{background:var(--hover)}
|
||||
table.bench2 td.lead{color:var(--bone)}@media(min-width:1101px){table.bench2 tr.row td.lead{white-space:normal;min-width:220px;max-width:360px;padding-top:8px;padding-bottom:8px}}
|
||||
table.bench2 td.lead .cardname{display:inline-flex;align-items:center;gap:10px}
|
||||
table.bench2 td.lead .gen{display:block;font:12px var(--mono);color:var(--ash);letter-spacing:.02em;margin-top:3px;white-space:normal;overflow-wrap:anywhere}table.bench2 td.lead .gen .dot{color:var(--line-2);margin:0 4px}
|
||||
table.bench2 td.big{font:600 22px/1 var(--f-display,var(--f-sans));color:var(--bone);font-variant-numeric:tabular-nums}
|
||||
table.bench2 td.tnum{font-variant-numeric:tabular-nums}
|
||||
table.bench2 .eff{font:500 15px/1 var(--f-sans);color:var(--ink-2)}table.bench2 .eff.best{color:var(--ember-text,var(--ember));font-weight:600}
|
||||
table.bench2 .hollow{color:var(--ash)}
|
||||
table.bench2 td.quiet{color:var(--ash);font-size:13px}table.bench2 .basis{font:10px var(--mono);letter-spacing:.06em;text-transform:uppercase;color:var(--ash);margin-left:6px}
|
||||
table.bench2 .pill.state{padding:5px 8px;font-size:9px}table.bench2 .pill.state.tuned{color:var(--ember-text,var(--ember));border-color:color-mix(in srgb,var(--ember) 35%,transparent);background:color-mix(in srgb,var(--ember) 8%,transparent)}table.bench2 .pill.state.stock{color:var(--ash)}table.bench2 .pill.state.nolever{color:var(--ash);border-style:dashed}
|
||||
table.bench2 button.more{all:unset;cursor:pointer;font:500 10px/1.4 var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash);padding:6px 0;border-bottom:1px solid var(--line-2)}table.bench2 button.more:hover{color:var(--bone)}
|
||||
table.bench2 tr.detail td{padding:12px 12px 16px;border-bottom:1px solid var(--line);font-size:13px;line-height:1.55;color:var(--ash);white-space:normal;overflow-wrap:anywhere}
|
||||
table.bench2 tr.detail .d{display:block;margin:0 0 4px}table.bench2 tr.detail b{color:var(--ink-2);font-weight:600;margin-right:6px}
|
||||
@media(max-width:1100px){
|
||||
table.bench2,table.bench2 tbody,table.bench2 tr.detail,table.bench2 tr.detail td{display:block}
|
||||
table.bench2 thead{display:none}
|
||||
table.bench2 tr.row{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"lead big" "eff eff" "w pill" "more more";gap:4px 12px;padding:10px 0;min-height:44px;border-bottom:1px solid var(--line);align-items:center}
|
||||
table.bench2 tr.row td{display:block;height:auto;padding:0;border:0;white-space:normal;min-width:0}
|
||||
table.bench2 tr.row td.lead{grid-area:lead;max-width:none;min-width:0}table.bench2 td.lead .cardname{display:flex;align-items:center;gap:8px}table.bench2 td.lead .cardname .badge{flex:none}
|
||||
table.bench2 td.big{grid-area:big;font-size:20px;text-align:right;white-space:nowrap}
|
||||
table.bench2 td.effc{grid-area:eff;font-size:13px}table.bench2 td.effc .eff::before,table.bench2 td.effc .hollow::before{content:"MH per wall watt ";color:var(--ash);font-weight:400}
|
||||
table.bench2 td.quiet.tnum{grid-area:w}table.bench2 td.pillc{grid-area:pill;text-align:right}
|
||||
table.bench2 td.morec{grid-area:more;text-align:right}
|
||||
table.bench2 tr.detail td{padding:8px 0 14px}
|
||||
}
|
||||
</style>`;
|
||||
// Ember Tune's fleet priors (site/miner-priors.json, tools/tuning.mjs --priors --site): one row per card model,
|
||||
// driver major and program class; a row under the sample floor shows its count and no point
|
||||
const pj = JSON.parse(readFileSync(join(here, 'miner-priors.json'), 'utf8'));
|
||||
|
|
@ -503,19 +545,20 @@ for (const [file, active] of PAGES) {
|
|||
sortStyle,
|
||||
'<h2 id="table">The table</h2>',
|
||||
bestLine,
|
||||
'<p>One row per card on the current class: the class v4 program (the latency-shadow block over the class v3 hash), or a class v3 row re-measured with its class v4 cost on 6 October 2026 or later. Cards you can buy first, sorted by hash rate; click a column header to sort. MH per wall watt uses board or wall power; a row whose watts are the chip\'s (Apple silicon: GPU plus DRAM from IOReport) says so and is not ranked on that column. Integrated GPUs are not listed. Datacentre cards and the earlier classes sit below, collapsed.</p>',
|
||||
'<p><strong>Why the rate fell from the first bench to today.</strong> The genesis program did 104 dependent random 4-byte loads per hash over a 1 GiB dataset; the hourly program and class v3 do 128, with the mixer between them; class v4 adds about 100,000 integer operations per hash that ride in the memory wait. So the hash is bound by random-read bandwidth by design, and a card\'s MH/s is a relative number: the difficulty follows it, and the same card earns the same share of blocks at 136 MH/s on class v3 as it did at 228 MH/s on the genesis program. What a miner compares is hash per watt, and what the chain cares about is the chip edge, which the shadow work is there to cut.</p>',
|
||||
'<p>One row per card on the current class: the class v4 program (the latency-shadow block over the class v3 hash), or a class v3 row re-measured with its class v4 cost on 6 October 2026 or later. MH per wall watt uses board or wall power; a row whose watts are the chip\'s (Apple silicon: GPU plus DRAM from IOReport) says so and is not ranked on that column. Integrated GPUs are not listed.</p>',
|
||||
'<h3 class="grp" id="buy">Cards you can buy</h3>',
|
||||
table,
|
||||
`<p>Cards you can buy on the current class: ${cur.length}. Each row names the engineering log entry or the job it came from.</p>`,
|
||||
'<details class="earlier"><summary>Datacentre cards (' + dcRows.length + ' rows, rented for the measurement; about three times the rented dollars per hash of a desktop card)</summary>',
|
||||
'<p>Rented cards measured on the class v4 program by the fleet, stock clocks. They mine; they are not what a home miner buys.</p>',
|
||||
`<p class="gen">${cur.length} cards. Details opens a card\'s Hive flight-sheet values, its full class v4 cost, miner, source and note.</p>`,
|
||||
'<details class="grp"><summary>Datacentre (' + dcRows.length + ' cards, rented for the measurement; about three times the rented dollars per hash of a desktop card)</summary>',
|
||||
dcTable,
|
||||
'</details>',
|
||||
'<p><strong>The Hive flight sheet column.</strong> Where a card has a measured tune point, the column gives the core clock lock, the memory clock and the power limit to copy into a HiveOS flight sheet (core / mem / PL); the line under each row carries the label with the date, the class v4 cost in full, the miner and driver, the source and the note. Stock means no tune point has been measured yet. The Hive package mines at these settings through Hive\'s own overclock controls; the desktop app\'s Ember Tune lands on them by itself.</p>',
|
||||
'<details class="earlier"><summary>Earlier classes (the genesis program, the hourly program, class v3 before the shadow): ' + earlier.length + ' rows, not comparable with the table above</summary>',
|
||||
'<p>These rows are the bench numbers of 3 and 4 October 2026: the genesis program (104 loads per hash), the hourly program and the first class v3 miner. A higher MH/s here is a different hash, not a faster card.</p>',
|
||||
'<details class="grp"><summary>Earlier classes (' + earlier.length + ' rows: the genesis program, the hourly program, class v3 before the shadow; not comparable with the table above)</summary>',
|
||||
'<p>The bench numbers of 3 and 4 October 2026. A higher MH/s here is a different hash, not a faster card.</p>',
|
||||
earlierTable,
|
||||
'</details>',
|
||||
'<details class="grp"><summary>Why the rates changed</summary>',
|
||||
'<p>The genesis program did 104 dependent random 4-byte loads per hash over a 1 GiB dataset; the hourly program and class v3 do 128, with the mixer between them; class v4 adds about 100,000 integer operations per hash that ride in the memory wait. So the hash is bound by random-read bandwidth by design, and a card\'s MH/s is a relative number: the difficulty follows it, and the same card earns the same share of blocks at 136 MH/s on class v3 as it did at 228 MH/s on the genesis program. What a miner compares is hash per watt, and what the chain cares about is the chip edge, which the shadow work is there to cut.</p>',
|
||||
'</details>',
|
||||
'<h2 id="how">How a row gets here</h2>',
|
||||
'<p>Every row names the engineering log entry or the job it came from. "Measured by the team" means our own hardware and our own log. "Reported by the fleet" or "measured by the fleet" means a machine we rent or do not own, read from the status lines its miner uploads or from a bench run on it.</p>',
|
||||
'<p>MH per watt needs the card\'s power draw during the run. The app reads it on NVIDIA cards through the driver. Rows get the figure when a run records it. The class v4 cost column is what the latency-shadow work costs that card against the class v3 control, in watts and rate, where it was measured. The tuned column is the card\'s state at the row: a full Ember Tune names its point; stock means the card as it came, bench only or mining.</p>',
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue