Site: the GPU bench table reads at 1600 px: nine compact sortable columns one line wide (card, generator, MH/s, watts, MH per watt, class v4 cost short, tuned short, Hive core / mem / PL, date, who), the long fields in a detail row under each card that sorts with it (the 20:58 BST capture showed eleven columns clipped at five, rows inflated by off-screen text)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
bfd4cb5a0f
commit
52513bdb44
2 changed files with 43 additions and 24 deletions
|
|
@ -425,39 +425,56 @@ for (const [file, active] of PAGES) {
|
|||
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'], ['Generator', 'generator', 'text'], ['Best MH/s', 'mh_s', 'num'], ['Watts', 'watts', 'num'], ['MH per watt', 'mh_per_w', 'num'],
|
||||
['Class v4 cost', 'v4_cost', 'text'], ['Tuned', 'tuned', 'text'], ['Hive flight sheet (core, mem, PL)', 'hive', 'text'], ['Miner', 'miner', 'text'], ['Date', 'date', 'text'], ['Source', 'source', 'text'], ['Who measured it', 'by', 'text'],
|
||||
['Class v4 cost', 'v4_cost_short', 'text'], ['Tuned', 'tuned_short', 'text'], ['Hive core / mem / PL', 'hive_short', 'text'], ['Date', 'date', 'text'], ['Who measured it', 'by', 'text'],
|
||||
];
|
||||
const shortV4 = (r) => { const v = r.v4_cost || 'not measured'; const m = v.match(/^([^;(]+?)(?:\s*[;(]|$)/); return m ? m[1].trim() : v; };
|
||||
const shortTuned = (r) => { const v = r.tuned || 'stock, mining'; return v.split(' (')[0]; };
|
||||
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.generator, r.generator], [fmt(r.mh_s), r.mh_s], [r.watts == null ? 'not read' : fmt(r.watts), r.watts ?? -1], [r.mh_per_w == null ? 'not measured' : fmt3(r.mh_per_w), r.mh_per_w ?? -1],
|
||||
[r.v4_cost || 'not measured', r.v4_cost || ''], [r.tuned || 'stock, mining', r.tuned || ''], [hiveCell(r), r.hive && r.hive.core_mhz ? 'a measured ' + r.hive.core_mhz : 'z stock'], [r.miner + (r.driver_os ? ' (' + r.driver_os + ')' : ''), r.miner], [r.date, r.date], [r.source, r.source], [r.by + (r.note ? '. ' + r.note : ''), r.by],
|
||||
[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, r.by],
|
||||
];
|
||||
const hiveCell = (r) => {
|
||||
const h = r.hive; if (!h || h.core_mhz == null) return 'stock' + (h && h.label ? ' (' + h.label.replace(/^stock \(|\)$/g, '') + ')' : '');
|
||||
return 'core lock ' + fmt(h.core_mhz) + ' MHz, mem ' + fmt(h.mem_mhz) + ' MHz, PL ' + fmt(h.pl_w) + ' W (' + h.label + ')';
|
||||
const detail = (r) => {
|
||||
const parts = [];
|
||||
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(' · ');
|
||||
};
|
||||
const render = (list, id) => '<div class="tbl"><table class="sortable" id="' + id + '"><thead><tr>' +
|
||||
heads.map(([h, k, t], i) => `<th data-key="${k}" data-type="${t}" aria-sort="${k === 'mh_per_w' ? 'descending' : 'none'}"><button type="button" class="sort">${h}</button></th>`).join('') +
|
||||
'</tr></thead><tbody>' + list.map(r => '<tr>' + cells(r).map(([c, v]) => `<td data-v="${esc(String(v))}">${esc(String(c))}</td>`).join('') + '</tr>').join('') + '</tbody></table></div>';
|
||||
const table = render(cur, 'bench-current');
|
||||
const earlierTable = render(earlier, 'bench-earlier');
|
||||
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_per_w' ? '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 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
|
||||
// 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(){
|
||||
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'));
|
||||
rows.sort(function(a,b){var x=a.children[i].getAttribute('data-v'),y=b.children[i].getAttribute('data-v');var c=num?(parseFloat(x)-parseFloat(y)):x.localeCompare(y,'en');return dir==='descending'?-c:c;});
|
||||
rows.forEach(function(r){tb.appendChild(r);});
|
||||
var rows=Array.prototype.slice.call(tb.querySelectorAll('tr.row'));
|
||||
var pairs=rows.map(function(r){return [r, r.nextElementSibling && r.nextElementSibling.classList.contains('detail') ? r.nextElementSibling : null];});
|
||||
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]);});
|
||||
});});
|
||||
});
|
||||
})();
|
||||
</script>`;
|
||||
const sortStyle = '<style>th .sort{all:unset;cursor:pointer;font:inherit;color:inherit}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}details.earlier{margin:var(--s-4) 0}details.earlier summary{cursor:pointer;color:var(--bone)}</style>';
|
||||
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:1040px}table.bench tr.row td{white-space:nowrap;border-bottom:0}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}details.earlier summary{cursor:pointer;color:var(--bone)}</style>';
|
||||
const table = render(cur, 'bench-current');
|
||||
const earlierTable = render(earlier, 'bench-earlier');
|
||||
// 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'));
|
||||
|
|
@ -480,7 +497,7 @@ for (const [file, active] of PAGES) {
|
|||
'<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>',
|
||||
table,
|
||||
`<p>Rows on the current class: ${cur.length}. Each row names the engineering log entry or the job it came from.</p>`,
|
||||
'<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, labelled measured with the date; 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>',
|
||||
'<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>',
|
||||
earlierTable,
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue