eliliot-kweku commited on
Commit
30490c5
·
1 Parent(s): c413b35

The memory wall calculator

Browse files
Files changed (2) hide show
  1. README.md +17 -4
  2. index.html +161 -17
README.md CHANGED
@@ -1,10 +1,23 @@
1
  ---
2
- title: Memory Wall
3
- emoji: 📈
4
- colorFrom: green
5
  colorTo: indigo
6
  sdk: static
 
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: The Memory Wall
3
+ emoji: 📉
4
+ colorFrom: gray
5
  colorTo: indigo
6
  sdk: static
7
+ app_file: index.html
8
  pinned: false
9
+ license: apache-2.0
10
+ short_description: Why your GPU's TFLOPs do not decide your tokens per second
11
  ---
12
 
13
+ # The Memory Wall
14
+
15
+ An interactive calculator for the one equation that governs single-stream
16
+ generation speed:
17
+
18
+ ```
19
+ tokens/second ≤ memory bandwidth ÷ model bytes
20
+ ```
21
+
22
+ No model download, no GPU, runs instantly. Useful on its own, and it is also the
23
+ argument for everything else Exeaon publishes.
index.html CHANGED
@@ -1,19 +1,163 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>The Memory Wall — Exeaon</title>
7
+ <style>
8
+ :root{
9
+ --bg:#fbfbfd; --panel:#fff; --ink:#14151a; --muted:#6b6f7b;
10
+ --line:#e6e7ec; --accent:#4f46e5; --good:#0f9d58; --bad:#d93025;
11
+ --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
12
+ }
13
+ @media (prefers-color-scheme:dark){
14
+ :root{--bg:#0d0e12;--panel:#15171d;--ink:#e9eaee;--muted:#9096a3;
15
+ --line:#252832;--accent:#8b85ff;--good:#4ade80;--bad:#f87171;}
16
+ }
17
+ *{box-sizing:border-box}
18
+ body{margin:0;padding:2rem 1.25rem 4rem;background:var(--bg);color:var(--ink);
19
+ font:16px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,sans-serif;}
20
+ .wrap{max-width:880px;margin:0 auto}
21
+ h1{font-size:2.1rem;letter-spacing:-.03em;margin:0 0 .4rem}
22
+ .sub{color:var(--muted);margin:0 0 2rem}
23
+ .eq{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--accent);
24
+ border-radius:8px;padding:1rem 1.25rem;margin:0 0 2rem;font-family:var(--mono);
25
+ font-size:1.05rem;overflow-x:auto;white-space:nowrap}
26
+ .controls{display:grid;gap:1.25rem;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
27
+ background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:1.25rem;margin-bottom:1.5rem}
28
+ label{display:block;font-size:.82rem;font-weight:600;letter-spacing:.02em;
29
+ text-transform:uppercase;color:var(--muted);margin-bottom:.5rem}
30
+ input[type=range]{width:100%;accent-color:var(--accent)}
31
+ select{width:100%;padding:.55rem;border-radius:6px;border:1px solid var(--line);
32
+ background:var(--bg);color:var(--ink);font-size:.95rem}
33
+ .val{font-family:var(--mono);font-size:1.15rem;font-weight:600}
34
+ .verdict{background:var(--panel);border:1px solid var(--line);border-radius:10px;
35
+ padding:1.25rem 1.4rem;margin-bottom:1.5rem}
36
+ .verdict h2{margin:0 0 .5rem;font-size:1.35rem;letter-spacing:-.02em}
37
+ .verdict p{margin:0;color:var(--muted)}
38
+ .tblwrap{overflow-x:auto;border:1px solid var(--line);border-radius:10px;background:var(--panel)}
39
+ table{border-collapse:collapse;width:100%;font-size:.92rem;min-width:560px}
40
+ th,td{padding:.7rem .9rem;text-align:right;border-bottom:1px solid var(--line);white-space:nowrap}
41
+ th:first-child,td:first-child{text-align:left}
42
+ th{font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);font-weight:600}
43
+ tbody tr:last-child td{border-bottom:none}
44
+ tr.ours{background:color-mix(in srgb,var(--accent) 7%,transparent)}
45
+ td.num{font-family:var(--mono)}
46
+ .yes{color:var(--good);font-weight:600}
47
+ .no{color:var(--bad);font-weight:600}
48
+ .note{color:var(--muted);font-size:.88rem;margin-top:1.75rem;padding-top:1.25rem;border-top:1px solid var(--line)}
49
+ a{color:var(--accent)}
50
+ </style>
51
+ </head>
52
+ <body>
53
+ <div class="wrap">
54
+
55
+ <h1>The Memory Wall</h1>
56
+ <p class="sub">Why your GPU's TFLOPs do not decide your tokens per second.</p>
57
+
58
+ <div class="eq">tokens/second &nbsp;&le;&nbsp; memory bandwidth &nbsp;&divide;&nbsp; model bytes</div>
59
+
60
+ <p>At batch one, a language model reads <strong>every weight from memory to produce
61
+ one token</strong>, and uses each weight exactly once. Arithmetic intensity is about
62
+ <strong>0.5 FLOP per byte</strong>. The accelerator's FLOP rating never enters the
63
+ equation — the only lever on single-stream speed is how many bytes the model is.</p>
64
+
65
+ <div class="controls">
66
+ <div>
67
+ <label for="p">Parameters <span class="val" id="pv">7B</span></label>
68
+ <input type="range" id="p" min="0.5" max="120" step="0.1" value="7">
69
+ </div>
70
+ <div>
71
+ <label for="hw">Hardware</label>
72
+ <select id="hw"></select>
73
+ </div>
74
+ <div>
75
+ <label for="m">Available memory <span class="val" id="mv">16 GB</span></label>
76
+ <input type="range" id="m" min="4" max="192" step="1" value="16">
77
+ </div>
78
+ </div>
79
+
80
+ <div class="verdict"><h2 id="vh"></h2><p id="vp"></p></div>
81
+
82
+ <div class="tblwrap"><table>
83
+ <thead><tr><th>Format</th><th>Bits/weight</th><th>Size</th><th>Fits</th><th>Decode ceiling</th></tr></thead>
84
+ <tbody id="rows"></tbody>
85
+ </table></div>
86
+
87
+ <p class="note">
88
+ <strong>This is a ceiling, not a promise.</strong> Attention, the KV cache, kernel
89
+ overhead and real bandwidth utilisation (typically 70–85% of the spec sheet) all
90
+ put the achievable number below it. Larger batches raise arithmetic intensity and
91
+ change the picture entirely — this models the single-stream case, which is what
92
+ most people run locally. Bandwidth figures are vendor peak.
93
+ </p>
94
+ <p class="note" style="border:none;padding-top:0">
95
+ Compressed models: <a href="https://huggingface.co/Exeaon">huggingface.co/Exeaon</a> ·
96
+ Runtime: <a href="https://github.com/ExeaonLM">github.com/ExeaonLM</a> ·
97
+ Zenux Plimver Technologies LTD, Ghana
98
+ </p>
99
+
100
+ </div>
101
+ <script>
102
+ const HW = {
103
+ "Laptop CPU (DDR5-5600, dual channel)":90,
104
+ "Desktop CPU (DDR5-6000, dual channel)":96,
105
+ "Server CPU (DDR5, 12 channel)":460,
106
+ "Apple M4 Pro":273, "Apple M4 Max":546,
107
+ "NVIDIA T4":320, "NVIDIA RTX 4090":1008, "NVIDIA L40S":864,
108
+ "NVIDIA A100 80GB":2039, "NVIDIA H100 SXM":3350, "NVIDIA B200":8000,
109
+ };
110
+ const FMT = [
111
+ ["FP16 / BF16",16,false],["FP8",8,false],["INT8",8,false],["INT4",4,false],
112
+ ["ℰ-PURE 4-bit",4,true],["ℰ-PURE 3-bit",3,true],
113
+ ];
114
+ const $=id=>document.getElementById(id);
115
+ const sel=$("hw");
116
+ for(const k in HW){const o=document.createElement("option");o.textContent=k;sel.appendChild(o);}
117
+ sel.value="NVIDIA T4";
118
+
119
+ // Weight bytes only. KV cache and activations are extra, which is part of why
120
+ // the printed number is a ceiling rather than an estimate.
121
+ const gb=(p,bits)=>p*1e9*bits/8/2**30;
122
+
123
+ function render(){
124
+ const p=+$("p").value, mem=+$("m").value, bw=HW[sel.value];
125
+ $("pv").textContent=p.toFixed(1).replace(/\.0$/,"")+"B";
126
+ $("mv").textContent=mem+" GB";
127
+
128
+ const rows=FMT.map(([name,bits,ours])=>{
129
+ const size=gb(p,bits);
130
+ return {name,bits,ours,size,fits:size<=mem*0.9,tps:bw/size};
131
+ });
132
+
133
+ $("rows").innerHTML=rows.map(r=>`<tr class="${r.ours?"ours":""}">
134
+ <td>${r.name}</td><td class="num">${r.bits}</td>
135
+ <td class="num">${r.size.toFixed(2)} GB</td>
136
+ <td class="${r.fits?"yes":"no"}">${r.fits?"yes":"no"}</td>
137
+ <td class="num">${r.tps.toFixed(1)} tok/s</td></tr>`).join("");
138
+
139
+ const base=rows[0], fitting=rows.filter(r=>r.fits), best=rows[rows.length-1];
140
+ let h,t;
141
+ if(!fitting.length){
142
+ h=`Nothing fits in ${mem} GB`;
143
+ t=`A ${p.toFixed(1).replace(/\.0$/,"")}B model exceeds this device's memory at every
144
+ format listed. Smaller model, or more memory.`;
145
+ }else if(!base.fits){
146
+ const f=fitting[fitting.length-1];
147
+ h=`${sel.value} cannot run this model in FP16 at all`;
148
+ t=`FP16 needs ${base.size.toFixed(1)} GB against ${mem} GB available. At
149
+ ${f.name} it is ${f.size.toFixed(1)} GB and fits — a step function, not a
150
+ speed-up. The model goes from impossible to running at roughly
151
+ ${f.tps.toFixed(0)} tok/s.`;
152
+ }else{
153
+ h=`${best.tps.toFixed(0)} vs ${base.tps.toFixed(0)} tok/s`;
154
+ t=`Same model, same hardware, same ${bw} GB/s of bandwidth.
155
+ ${(best.tps/base.tps).toFixed(1)}× more tokens purely from moving fewer bytes.`;
156
+ }
157
+ $("vh").textContent=h; $("vp").textContent=t;
158
+ }
159
+ ["p","m","hw"].forEach(id=>$(id).addEventListener("input",render));
160
+ render();
161
+ </script>
162
+ </body>
163
  </html>