σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyロードマップスキル
Ctrl K
AO
+1.2k 人の学習者
ログイン参加する ↗
ロードマップスキル
AO
+1.2k 人の学習者
ログイン
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyロードマップスキル
Ctrl K
AO
+1.2k 人の学習者
ログイン参加する ↗
ロードマップスキル
AO
+1.2k 人の学習者
ログイン
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Cache locality スキル›モジュール 3 · マシン全体›トピック 3.2·~50 分上級

TLBとヒュージページ

スキル上の位置モジュール 3/3 · トピック 2/7
3.2 TLBとヒュージページ
—ラボスコア— / 100合計XP—連続日数—

読了 6分コード例 3件

  1. 012種類のアドレス
  2. 02変換のキャッシュ
  3. 03レコードをランダムに読む
  4. 04これから作るもの

読み出しがキャッシュに届く前に物理アドレスが必要で、その変換には専用の小さなキャッシュ、TLBがあり、エントリは約64個しかありません。それより多くのページの間を飛び回るプログラムは、データキャッシュが好調でも、ほぼ毎回TLBミスを起こしえます。この講義ではTLBを作り、2 MBのページが250ページを1ページにまとめる様子を示します。

01

2種類のアドレス

プログラムが使うアドレスは仮想アドレスです。各プログラムは、ゼロから始まる長いメモリを自分だけが持っていると思っています。マシンは実際のメモリを物理アドレスで持ち、両方の世界をページに区切ります。メモリ上の表であるページテーブルが、各仮想ページをどの物理ページが持つかを示します。すべての読み出しは、まずこの変換が必要です。仮想アドレスのページ番号を取り、それを引き、ページ内のバイト位置を保ちます。キャッシュのラインと同じ分割で、ブロックが大きいだけです。

main.pyPython
page_bytes = 4096for address in (0, 4095, 4096, 123456789):    print(address, "-> page", address // page_bytes, "byte", address % page_bytes)1
0 -> page 0 byte 0
4095 -> page 0 byte 4095
4096 -> page 1 byte 0
123456789 -> page 30140 byte 3349
  1. 1ページ番号はアドレスをページサイズで割った値で、余りがページ内のバイト位置です。
02

変換のキャッシュ

読み出しのたびにメモリ上のページテーブルをたどると、メモリアクセスのコストが2倍になってしまいます。そのためプロセッサは、直近の変換結果をTLBという小さく速い表に保持します。ページがTLBにある読み出しはヒットで、ほぼコストがかかりません。ない読み出しはTLBミスで、数十ナノ秒かかるページテーブルの巡回が起きます。第1レベルのデータTLBは約64エントリを持ちます。ラインではなくページを保持する点を除けば、これまでのキャッシュと同じ動きで、最も長く使われていないものから出ていきます。

main.pyPython
class TLB:    def __init__(self, entries):        self.entries = entries        self.pages = []        self.hits = 0        self.misses = 0    def access(self, address, page_bytes):        page = address // page_bytes        if page in self.pages:            self.pages.remove(page)            self.pages.append(page)            self.hits += 1            return True        self.misses += 1        self.pages.append(page)        if len(self.pages) > self.entries:            self.pages.pop(0)        return Falsedef tlb_misses(trace, entries, page_bytes):    tlb = TLB(entries)    for address in trace:        tlb.access(address, page_bytes)    return tlb.missesfor n_pages in (48, 64, 65, 80):    trace = [page * 4096 for page in range(n_pages)] * 5    print(n_pages, "pages, 5 rounds:", tlb_misses(trace, 64, 4096), "misses")
48 pages, 5 rounds: 48 misses
64 pages, 5 rounds: 64 misses
65 pages, 5 rounds: 325 misses
80 pages, 5 rounds: 400 misses

48ページや64ページのループは、最初の周回でしかミスしません。1ページ増えて65ページになると、5周のすべての読み出しでTLBミスが起き、325回中325回です。これは、ワーキングセットのトピックと同じLRUの崖が、今度はページで起きたものです。大事なのは到達範囲、つまりTLBが一度に覆えるメモリの量です。

TLB reach = entries × page size(1)64エントリ × 4 KB = 256 KB。2 MBページなら同じ64エントリで128 MBに届きます
03

レコードをランダムに読む

1レコード512バイトのレコード2,000件の表を考えます。1日分のデータに追加フィールドがついたものです。全体で1,000 KB、4 KBのページで250ページで、TLBが保持できる64ページの4倍近くです。レコードを順に読むのは穏やかで、1ページを8レコードで共有するので、TLBミスはページごとに1回、250回です。ランダムな順に読むのは厳しく、各読み出しが250ページのどこにでも当たりえて、TLBは64ページしか覚えていません。次のコードは、4 KBページと2 MBページの両方で測ります。

main.pyPython
import randomorder = list(range(2000))shuffled = random.Random(7).sample(order, len(order))for name, records in (("in order", order), ("shuffled", shuffled)):    trace = [record * 512 for record in records]    print(name, "4 KB pages:", tlb_misses(trace, 64, 4096), "- 2 MB pages:", tlb_misses(trace, 64, 2 * 1024 * 1024))
in order 4 KB pages: 250 - 2 MB pages: 1
shuffled 4 KB pages: 1541 - 2 MB pages: 1

順に読むと、4 KBページでは250ミスです。シャッフルすると2,000回の読み出しのうち1,541回、77%がミスし、6倍になります。2 MBページなら1,000 KBがすべて1ページに収まり、順序に関わらず1回のミスです。巡回1回30 nsとして、シャッフルした読み出しは変換だけで46マイクロ秒を使い、これは10万回の足し算に相当します。

ヒュージページの実際

Linuxでは、透過的ヒュージページや明示的な hugetlbfs ページでヒュージページを要求でき、トレーディングシステムは大きな表をそこに固定することがよくあります。効果が出るのは、不規則な順に読む大きな表で、小さな表や順に読む走査では出ません。

ヒュージページはタダではない

ヒュージページは連続した2 MBの物理メモリを必要とし、何週間も動いたマシンでは確保しにくいことがあります。ページより小さい表でも、ページ全体を占有します。必要な少数の表のために、起動時に早めに確保しましょう。

実データが示すものSPYの512バイトのレコード2,000件(1,000 KB、250ページ)、64エントリのTLB
日付順:4 KBページ250TLBミス、巡回7,500 ns
日付順:2 MBページ11ページが表全体を持つ
出来高順:4 KBページ784読み出しの39%がTLBミス
出来高順:ヒュージページでの節約23,490ns巡回783回を回避
読み出し順とページサイズ別のTLBミス
日付順・4 KB250
出来高順・4 KB784
どちらの順でも・2 MB1
04

これから作るもの

ラボは講義の順に進みます。アドレスのページ、LRU置換のTLB、ミスの数え上げ、トレースが触れるページ、ある順序でのレコードのアドレス、ページサイズの比較、そしてSPYのレコードでの研究です。

  • 関数 · 問い前提
  • page_of(address, page_bytes)このアドレスはどのページにあるか?整数除算
  • TLB(entries).access(address, page_bytes)この変換はTLBヒットか?page_of
  • tlb_misses(trace, entries, page_bytes)トレースは何回TLBミスを起こすか?TLB
  • pages_touched(trace, page_bytes)トレースは何種類のページに触れるか?page_of
  • record_trace(order, record_bytes)この順でレコードを読むとどのアドレスに触れるか?単純な算術
  • compare_pages(trace, entries)ヒュージページはどれだけ効くか?tlb_misses
  • study(bars)SPYのレコードでヒュージページは何を節約するか?compare_pagespages_touchedrecord_trace

重要ポイント

  • 変換にもキャッシュがある。 どの読み出しもページの変換を必要とします。TLBは最近の変換を約64個保持し、ミスすると遅いページテーブルの巡回が起きます。
  • 到達範囲はエントリ数×ページサイズ。 4 KBの64エントリは256 KBに届きます。1,000 KBの表をランダムな順に読むと、大半の読み出しでミスします。
  • ヒュージページが到達範囲を広げる。 2 MBページなら同じ64エントリで128 MBを覆えます。表は1ページに収まり、ミスは784回から1回に減りました。
クイックチェック
TLBは64エントリで、ページは2 MBです。一度に覆えるメモリはどれだけですか。
答えを選んでください。

次のトピック:ここまでは1つのプログラムと1つのコアでした。フォルスシェアリングとパディングでは、同じキャッシュラインにある2つの別々の変数に2つのコアが書き込み、ラインが両者の間を行き来します。無効化の回数を数え、パディングで直します。

ラボ:採点される内容

7タスク · 100点
  • アドレスのページ10点
  • LRUのTLB25点
  • トレースのTLBミス10点
  • 触れたページ数10点
  • ある順序でレコードを読む10点
  • 4 KBページと2 MBページ15点
  • SPYの表での研究20点
エクスプローラー · lab-cl-8
▾ lab-cl-8
▾ data
…
bash · ブラウザ内
learner@quantcraft:~/lab-cl-8$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

このトピックをリセットしますか?

lab-cl-8 の内容はすべてスターターファイルに戻り、ターミナルも消去されます。現在の解答は失われ、元に戻せません。

リセットされるもの
  • main.py → スターターコード
  • ターミナル履歴とテスト出力
  • 未提出の変更
保持されるもの
  • ラボの最高スコア
  • XPと連続日数
  • 講義の進捗とメモ