σμ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.4·~1 سمتقدم

تأثيرات NUMA

الموضع في المسارالوحدة 3 من 3 · الموضوع 4 من 7
3.4 تأثيرات NUMA
—درجة المختبر— / 100إجمالي XP—التتابع—

4 دقيقة قراءة3 أمثلة برمجية

  1. 01ذاكرة لها مسافة
  2. 02من يقرر أين تقيم الصفحة
  3. 03عدّ الوصولات المحلية والبعيدة
  4. 04ما ستبنيه

في خادم بمقبسين قد تكلّف القراءة نفسها 80 ns أو 130 ns بحسب المقبس الذي تقيم فيه الصفحة. ويُحدَّد مكان إقامة الصفحة عند أول لمسة لها. يضع هذا الدرس نموذجًا لعقدتين ويبيّن كيف يجعل خيط واحد يهيّئ البيانات نصف العمل بعيدًا ويصلح ذلك بجعل كل خيط يلمس جزأه أولًا.

01

ذاكرة لها مسافة

للخادم الكبير مقبسا معالج ولكل مقبس وحدات ذاكرة خاصة به. تقرأ النواة ذاكرة مقبسها مباشرة. ولقراءة ذاكرة المقبس الآخر يعبر الطلب رابطًا بين المقبسين وهذا يستغرق وقتًا أطول. هذا الجهاز NUMA. يشكّل كل مقبس وذاكرته عقدة وعقدة الخيط هي حيث تقع نواته. في نموذجنا عقدتان بخيطين لكل منهما: الخيطان 0 و1 على العقدة 0 والخيطان 2 و3 على العقدة 1. الوصول المحلي يكلّف 80 ns والبعيد 130 ns.

main.pyPython
print([node_of_thread(thread, 2) for thread in range(4)])for thread_node in (0, 1):    print("thread on node", thread_node, [LOCAL_NS if page_node == thread_node else REMOTE_NS for page_node in (0, 1)])
[0, 0, 1, 1]
thread on node 0 [80.0, 130.0]
thread on node 1 [130.0, 80.0]

كل سطر هو منظور خيط: يدفع 80 ns للصفحات على عقدته و130 ns للصفحات على العقدة الأخرى. الفرق 50 ns يبدو صغيرًا لكنه ينطبق على كل وصول يبلغ الذاكرة.

02

من يقرر أين تقيم الصفحة

يمنح نظام التشغيل الذاكرة للبرنامج صفحات ويختار عقدة الصفحة لحظة استعمالها أول مرة. القاعدة الافتراضية هي اللمسة الأولى: تذهب الصفحة إلى عقدة الخيط الذي يلمسها أولًا وتبقى هناك. والبديل التشابك الصفحات على العقد. يطبّق الكود أدناه القاعدتين على قائمة قصيرة من الوصولات مكتوبة (خيط، عنوان).

main.pyPython
def first_touch_placement(trace, threads_per_node):    placement = {}    for thread, address in trace:        page = address // PAGE_BYTES        if page not in placement:            placement[page] = node_of_thread(thread, threads_per_node)    return placementdef interleaved_placement(trace, n_nodes):    return {page: page % n_nodes for page in {address // PAGE_BYTES for _, address in trace}}trace = [(0, 0), (0, 4096), (3, 8192), (1, 4100)]print(first_touch_placement(trace, 2))print(interleaved_placement(trace, 2))
{0: 0, 1: 0, 2: 1}
{0: 0, 1: 1, 2: 0}

لمس الصفحتين 0 و1 أولًا الخيط 0 الواقع على العقدة 0 فتذهبان إلى العقدة 0. ولمس الصفحة 2 أولًا الخيط 3 على العقدة 1 فتذهب إلى العقدة 1. والوصول اللاحق للخيط 1 إلى الصفحة 1 لا ينقلها. أما التشابك فيتجاهل من يلمس ماذا: تذهب الصفحة 1 إلى العقدة 1 لمجرد أن 1 modulo 2 يساوي 1.

03

عدّ الوصولات المحلية والبعيدة

تقسّم مهمة متوازية نموذجية جدولًا إلى أجزاء جزء لكل خيط. ثم يقرأ كل خيط جزأه فقط فيُفترض أن تكون كل صفحة يقرؤها على عقدته. تبني الدوال أدناه نمط الوصول هذا لـ400 سجل على أربعة خيوط وتعدّ الوصولات المحلية والبعيدة وزمنها لثلاثة أنماط وضع. في الأول "single" هيّأ خيط واحد كل البيانات فوضعت اللمسة الأولى كل صفحة على العقدة 0. وفي الثاني هيّأ أصحاب الأجزاء أجزاءهم بأنفسهم. وفي الثالث تتشابك الصفحات.

main.pyPython
def access_costs(trace, placement, threads_per_node):    local = 0    remote = 0    for thread, address in trace:        if placement[address // PAGE_BYTES] == node_of_thread(thread, threads_per_node):            local += 1        else:            remote += 1    return {"local": local, "remote": remote, "ns": local * LOCAL_NS + remote * REMOTE_NS}def partition_trace(n_records, n_threads, record_bytes):    chunk = n_records // n_threads    return [(thread, record * record_bytes) for thread in range(n_threads) for record in range(thread * chunk, (thread + 1) * chunk)]work = partition_trace(400, 4, 512)single = first_touch_placement([(0, address) for _, address in work], 2)owners = first_touch_placement(work, 2)spread = interleaved_placement(work, 2)for name, placement in (("single", single), ("owners", owners), ("interleaved", spread)):    print(name, access_costs(work, placement, 2))
single {'local': 200, 'remote': 200, 'ns': 42000.0}
owners {'local': 400, 'remote': 0, 'ns': 32000.0}
interleaved {'local': 208, 'remote': 192, 'ns': 41600.0}
average access time = local share × 80 ns + remote share × 130 ns(1)إذا كان نصف الوصولات بعيدًا: 0.5 × 80 + 0.5 × 130 = 105 ns بدل 80 ns

مع خيط واحد يهيّئ كل شيء يكون نصف الوصولات بعيدًا ويستغرق العمل 42000 ns لـ400 قراءة. وحين يهيّئ أصحاب الأجزاء أجزاءهم لا يكون شيء بعيدًا ويستغرق 32000 ns أي أسرع بنحو 1.3 مرة للبرنامج نفسه تمامًا. ولا يفيد التشابك هنا: فبما أن كل خيط يقرأ جزءًا متجاورًا تضع الصفحات المتشابكة نصف بياناته على العقدة الخطأ. التشابك للبيانات التي يقرؤها كل خيط في كل مكان حيث لا يصلح وضع واحد للجميع.

التهيئة في خيط واحد هي الخطأ المعتاد

يقرر خيط رئيسي يخصّص مصفوفة كبيرة ويملؤها قبل تشغيل العمال وضع كل صفحة على عقدته. البرنامج صحيح ولا يُظهر المحلل شيئًا خاطئًا سوى تباطؤ يزداد مع عدد المقابس. دع كل عامل يهيّئ الجزء الذي سيستعمله.

أدوات تتحكم في الوضع

في Linux يوزّع numactl --interleave=all صفحات البرنامج على العقد ويثبّت numactl --cpunodebind و--membind الخيوط والذاكرة على عقد ويبيّن numastat كم وصولًا كان محليًا. وعادةً ما تثبّت أنظمة التداول كل خيط على نواة وتمنحه ذاكرة من عقدته.

ما تقوله البيانات الحقيقية4000 سجل لـ SPY بحجم 512 بايت (500 صفحة)، 4 خيوط على عقدتين، 80 ns محلي و130 ns بعيد
هُيِّئ بخيط واحد420,000ns2000 وصول بعيد من 4000
هُيِّئ بأصحاب الأجزاء320,000nsكل الوصولات محلية
صفحات متشابكة420,000nsنصف البيانات على العقدة الخطأ
كسب اللمسة الأولى من أصحاب الأجزاء1.31×البرنامج نفسه والبيانات نفسها
زمن 4000 قراءة بالميكروثانية
خيط واحد420
أصحاب الأجزاء320
متشابك420
04

ما ستبنيه

يتبع المختبر الدرس: عقدة الخيط وقاعدتا الوضع ونمط وصول مهمة مجزّأة وعدّ الوصولات المحلية والبعيدة والدراسة على سجلات SPY.

  • الدالة · السؤالتعتمد على
  • node_of_thread(thread, threads_per_node)على أي عقدة يعمل خيط؟القسمة الصحيحة
  • first_touch_placement(trace, threads_per_node)أين تضع اللمسة الأولى كل صفحة؟node_of_thread
  • interleaved_placement(trace, n_nodes)والتشابك؟حساب بسيط
  • partition_trace(n_records, n_threads, record_bytes)ما الوصولات التي يجريها كل خيط؟حساب بسيط
  • access_costs(trace, placement, threads_per_node)كم وصولًا محليًا وبعيدًا وكم من الوقت؟node_of_thread
  • study(bars)كم يكلّف الوضع الخاطئ على سجلات SPY؟partition_tracefirst_touch_placementaccess_costs

أهم الخلاصات

  • للذاكرة مسافة. في خادم متعدد المقابس تكلّف صفحة على العقدة الأخرى 130 ns بدل 80 ns فالوضع جزء من الأداء.
  • اللمسة الأولى تقرر. تقيم الصفحة حيث يعمل أول من لمسها؛ وخيط رئيسي يملأ كل شيء يترك نصف العمل بعيدًا.
  • طابق البيانات بقارئها. دع كل عامل يهيّئ الجزء الذي يقرؤه: أسرع 1.3 مرة هنا؛ ولا تُشابك إلا البيانات التي يقرؤها كل الخيوط في كل مكان.
تحقق سريع
كل خيط من أربعة يقرأ ربعه من جدول فقط. أي وضع هو الأفضل؟
اختر إجابة.

الموضوع التالي: مكان إقامة البايتات نصف الحكاية فقط، وكيفية توزيعها مهمة أيضًا. في المخصصات وأحواض الذاكرة يطلب برنامج كثيرًا من الكائنات الصغيرة ويحدد ترتيب توزيع المخصص لها وأماكنه عدد أسطر الذاكرة المخبئية التي يمسّها عبور لاحق.

المختبر: ما الذي يُقيَّم

6 مهام · 100 نقطة
  • عقدة خيط5 نقطة
  • وضع اللمسة الأولى20 نقطة
  • الوضع المتشابك10 نقطة
  • مهمة مجزّأة15 نقطة
  • الوصولات المحلية والبعيدة25 نقطة
  • الدراسة على جدول SPY25 نقطة
المستكشف · lab-cl-10
▾ lab-cl-10
▾ data
…
bash · داخل المتصفح
learner@quantcraft:~/lab-cl-10$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

هل تريد إعادة ضبط هذا الموضوع؟

سيعود كل ما في lab-cl-10 إلى الملفات الابتدائية وستُمسح الطرفية. ستفقد حلّك الحالي ولا يمكن التراجع عن ذلك.

سيُعاد ضبطه
  • main.py ← الشيفرة الابتدائية
  • سجل الطرفية ومخرجات الاختبارات
  • التغييرات غير المُرسلة
سيُحتفظ به
  • أفضل درجة في المختبر
  • نقاط XP والتتابع
  • تقدّم المحاضرة والملاحظات