
أول مدقق مخاطر في العالم لمعالجات NVIDIA Blackwell (sm_120)، مع مُجمِّع وجدولة مطابقين تمامًا لمُترجمهم الخاص بايتًا ببايت. الفحص الذي لم يُصدروه أبدًا.
المشكلة · أي وحدات GPU · كيف يعمل · بدء سريع · مُقاس، لا مفترض · النتائج · API · المنهج · خارطة الطريق · غرفة نظيفة
تعليمة NVIDIA GPU طولها 128 بتًا، و21 منها ليست جزءًا من التعليمة إطلاقًا. إنها كلمة تحكم في الجدولة، من stall إلى reuse: عدد دورات الانتظار قبل إصدار التعليمة التالية، وأي لوحات نتائج يجب الإشارة إليها، وأيها يجب انتظاره، وأي المعاملات يمكن تقديمها من ذاكرة التخزين المؤقت لإعادة الاستخدام.
لا يتحقق العتاد من أيٍّ من ذلك. على sm_120 لا يوجد قفل أجهزة (interlock) على التعليمات ذات الكمون الثابت. تثق السيليكون بأي شيء أنتج كلمة التحكم. إذا كان عدد دورات الانتظار أقصر من كمون قيمة تستهلكها التعليمة التالية، فلن يحدث أي خطأ، ولن يحدث أي انتظار، ولن يُصدر أي تحذير. تقرأ التعليمة سجلًا لم يُكتب بعد وتُجري الحساب على بيانات قديمة، بكامل السرعة، في كل مرة.
هذا نوع غريب من الأخطاء البرمجية. لا يسبب انهيارًا. لا يظهر في مصحح الأخطاء. ينتج أرقامًا خاطئة فحسب، وهو ما يعني في عملية ضرب المصفوفات أو نواة انتباه نموذجًا يتدرب بشكل سيئ قليلًا بدلًا من أن ينهار بشكل مرئي.
أرخص ثلاثة ترميزات هي المعطوبة، ولا شيء في أي مكان يُبلغ عنها. لاحظ أيضًا ما يفعله الشريط الأيسر: stall بقيمة صفر لا يعني صفر دورة، بل هو ترميز آمن مميز ينتظر النتائج المعلقة ويكلف نحو تسعة أضعاف تعليمة مجدولة. أي مدقق يقرؤها على أنها صفر سيصف البرامج الصحيحة بأنها معطوبة.
الأدوات التي تُولّد كود الآلة لهذه البنية تُسند بتات التحكم هذه من نموذج كمون. basalt هو الشيء الذي يتحقق من الإجابة.
NVIDIA تمنحك مُجمّعًا يكتب تلك الـ21 بتًا. لا تمنحك أي شيء يقرأها ويعيد إخبارك بأنها آمنة، ولا يفعل ذلك أي شخص آخر.
مُجمّعات وحدات معالجة الرسوم من NVIDIA موجودة منذ عقد من الزمن، وقد تمت هندسة ترميز Blackwell بشكل عكسي من قبل، وهناك توصيفات منشورة على مستوى دورات الساعة لـ sm_120، ويوجد مُجمّع عام واحد لهذه البنية يُسند بتات التحكم في الجدولة بنفسه ويُشغّل نواة خاصة به على بطاقة ليتحقق من أن الإجابات صحيحة. كل هذا صحيح، لكن لا شيء منه هو الادعاء:
لا يمكن تسليم أي أداة أخرى ملف cubin لم تُنتجه وتكليفها بالقول ما إذا كانت بتات التحكم في الجدولة الخاصة به آمنة.
مُجمّعك هو من أصدر ذلك cubin، أو مكتبة صدّرته، أو شخص كتبه يدويًا، وحتى الآن لم تكن هناك طريقة للسؤال. على بنية لا تحتوي على قفل أجهزة، هذا هو الفرق بين "لقد عمل" و"إنه صحيح"، والفرق غير مرئي: stall أقصر بدورة واحدة يقرأ سجلًا قديمًا ويعيد رقمًا خاطئًا بكامل السرعة، دون أي خطأ ودون أي تحذير، في كل مرة.
كل ما عدا ذلك هنا موجود لجعل تلك الجملة قابلة للاختبار. المُجمّع هو ما يبني برنامجًا مع تقصير متعمد لدورة انتظار واحدة. المجدول هو ما يُجبر النموذج على الالتزام بإجابة بدلًا من تقييم إجابة شخص آخر. والتدقيق هو المكان الذي تتوقف فيه الجملة عن كونها غيابًا وتصبح قياسًا: basalt مُوجَّه إلى 2,473 ملف cubin من sm_120 تُصدرها NVIDIA في cuBLAS وcuSOLVER وcuSPARSE وNPP وغيرها.
لماذا لم يكن موجودًا، على لسان المجال نفسه. يقول أكثر مُجمّعات SASS استخدامًا في توثيقه الخاص إن "التحقق من الصحة الدقيقة للبرنامج بأكمله … [ليس] ممكنًا إلى حد بعيد دون دعم رسمي. لذلك، يُترك للمستخدم ضمان صحة البرنامج، بمساعدة محدودة جدًا من المُجمّع." SIP, بخصوص الضبط التلقائي لجدول SASS, يذكر أن "التحقق مستحيل لأكواد التجميع الأصلية لوحدات معالجة الرسوم لأن الدلالات الرسمية لـ sass مغلقة المصدر."
كلاهما يتعلق بالصحة الدلالية: ما إذا كانت النواة تحسب ما يفترض أن تحسبه. basalt لا يجيب عن ذلك، ولا شيء هنا يدّعي ذلك. إنه يجيب عن سؤال أصغر بكثير، والنقطة أن السؤال الأصغر قابل للحسم دون الدلالات:
هل تغطي بتات التحكم في هذا البرنامج تبعيات بياناته الخاصة؟
يتطلب ذلك بنية التبعيات، التي يوفرها الترميز، ونموذج كمون، الذي توفره السيليكون تحت القياس. لا يتطلب أيٌّ منهما معرفة ما تحسبه أي تعليمة. يمكن لنواة أن تجتاز هذا الفحص ومع ذلك تكون الخوارزمية الخاطئة؛ ما لا يمكنها فعله هو قراءة سجل قبل وصول القيمة.
ثانيًا، لا يُقاس أي شيء آخر ببايتات البائع نفسه. مرجع basalt هو مخرجات ptxas، لذا فإن أي اختلاف هو خطأ في basalt حتى يثبت العكس. يجب على مُجمّعه إعادة إنتاج الـ128 بتًا الدقيقة للمُجمّع. يجب على المجدول التخلص من كل بت تحكم اختاره المُجمّع، وحساب بتات جديدة، وجعل GPU يحسب الإجابة نفسها.
معيار واحد لكل ذلك: طابق البائع تمامًا، أو اذكر لماذا لا.
والجزء الذي عادة ما يصمت عنه المجدول: كم تكلف الصحة. جداول basalt تستهلك 1.05x من دورات إصدار البائع، أبطأ على 111 من أصل 1,323 زوجًا من النوى ومستويات التحسين وأرخص على 842، مع بقاء كل نواة قابلة للمقارنة مطابقة بايتًا ببايت على GPU.
الصف الثالث هو الذي غيّر الصفوف الثلاثة الأخرى. المدقق الذي يُمعهر على مجموعة مرجعية لا يمكن أن يفشل على تلك المجموعة: أصغر فجوة شوهد المُجمّع يتركها هي الحد الأدنى، بالبناء، بالضبط للكود الذي قِيس عليه. في المرة الأولى التي رأى فيها هذا المدقق كودًا من مكان آخر، أبلغ عن ستة وعشرين خطرًا لكل نواة في مفكك JPEG لم يُرجع قط بكسلًا خاطئًا، وكل الـ6,593 كانت أخطاء basalt. إصلاح تلك الأخطاء أوصله إلى الصفر، والصفر على مكتبة واحدة لم يكن دليلًا أيضًا: توسيع المجموعة المستبعدة إلى ثلاث مكتبات و5.2 مليون تعليمة أعاده مباشرة إلى 940، ووجد خمسة أخطاء إضافية في النموذج فوق الثمانية الأولى. ثلاثة عشر تصحيحًا، ولا أحد منها من NVIDIA، والمتطلب الذي أُعيد استخراجه من 24,311 نواة مُصدَّرة وضع مسند حماية عند 13 دورة عبر 229,567 ملاحظة، وهو الرقم الذي قاسه حقن الأعطال على هذه البطاقة عن طريق كسر برنامج عمدًا. انظر النتيجة 32.
كونك أرخص من البائع ليس ادعاءً يستحق الافتخار. basalt يجدول كل تبعية عند أضيق فجوة شوهد ptxas يتركها لذلك الزوج المحدد، وptxas يوازن بين ضغط السجلات والذاكرة إلى جانب كمون الإصدار بينما يحسّن هذا أداة رقمًا واحدًا. كما أنه لم يُصدَّق بمجرد النظر: في المرة الأولى التي انخفضت فيها النسبة تحت 1.0 انكسر اختبار الرحلة الكاملة عبر العتاد، ولم يثبت الرقم إلا بعد إصلاح الخطأ الذي كشفه. لهذا السبب تُثبَّت النسبة من الجانبين في مجموعة الاختبارات.
العمود الأوسط هو النقطة. مدقق ومجدول يتشاركان نموذج كمون يتفقان مع بعضهما بينما كلاهما مخطئ، لذا لا يُعتبر أي منهما دليلًا على الآخر؛ فقط السيليكون لا مصلحة لها في الجدال. تشغيل المجدول على سبع نوى مكتوبة يدويًا اجتاز سبعًا من سبع لفترة طويلة. تشغيله على ثلاثمائة وجد إحدى وأربعين نواة خاطئة، وكل تصحيح في النتائج جاء من مراقبة ذلك الرقم وهو يتحرك.
الأمر نفسه ينطبق على المدخلات. القراءة القديمة لا تغير الإجابة إلا عندما تختلف القيمة القديمة عن الجديدة، لذا فإن نمطًا واحدًا من البايتات هو فرصة واحدة للاكتشاف، وتشغيل كل نواة ضد نمط ثانٍ وثالث ورابع وجد فورًا مُسند حمل (carry-out predicate) كان نموذج المعاملات يقرؤه كمصدر منذ البداية. لقد نجا من كل فحص حتى تلك اللحظة، بما في ذلك الرحلة الكاملة نفسها.
نفس الانضباط يحدد ما يُسمح للمُجمّع بفعله، ومن الجدير الفصل بين الرقمين اللذين بحوزته.
التغطية 99.9% من المجموعة المرجعية و87.5% من كود المكتبات المُصدَّرة. الصحة 100%، وهذا هو الرقم المثبَّت باختبار. الفجوة بينهما هي تعليمات يرفضها basalt بالاسم، كلٌّ منها يسمي الحقل الذي لم يستطع تحديده، لأن أداة تخمّن ستصل إلى تغطية كاملة بإصدار كلمات تُفكك إلى النص الصحيح وتحسب شيئًا آخر. لم يُصدر أيًّا منها عبر 59,760 تعليمة في المجموعة المرجعية و5,237,448 تعليمة مُصدَّرة.
لم يصل إلى ذلك إلا بعد ثماني جولات منفصلة من الثقة الخاطئة:
كل واحدة من تلك أنتجت كلمة تُجمَّع، وتُفكك إلى النص نفسه الذي جاءت منه تمامًا، وتحسب شيئًا آخر. هذا هو الفشل نفسه الذي وُجد باقي هذا المستودع لاصطياده، ولهذا تُرفض الآن جميع الحالات الثماني مع سبب يسمي ما يحتويه الحقل فعلًا، ولهذا فإن عدد التعليمات التي تُجمَّع إلى بايتات خاطئة هو اختبار مثبَّت عند الصفر وليس رقمًا في جدول.
ظهرت حالة تاسعة في أول مرة وُجّه فيها المُجمّع إلى كود آلة لم يُنتجه، وكانت من نوع مختلف. c[0x0][UR4] يُفهرس إزاحته بسجل حيث تحمل الصيغة المسجلة رقمًا، وقد أثار المُرمِّز (encoder) خطأً بدلًا من الرفض. الانهيار على مدخلات خارجية أسوأ من حكم خاطئ، لأن المتصل لا يحصل على أيٍّ منهما.
sm_120 ليس رقم طراز. إنها إمكانية الحوسبة المشتركة بين خط Blackwell الاستهلاكي بأكمله، لذا فإن ترميز التعليمات وقاعدة البيانات والمُجمّع والمدقق تنطبق على كل بطاقة فيه:
ptxas يستهدف أيضًا sm_121، وهي شريحة مختلفة في العائلة نفسها. basalt لم يعمل قط على واحدة، ولا يدّعي دعمها. ما يمكنه قوله مُقاس: المُجمّع يُصدر كودًا مطابقًا بايتًا ببايت، بما في ذلك كلمات التحكم، لجميع الأهداف الستة التي يقدمها هنا، لذا فإن الجدولة التي تحتاجها النواة هي خاصية للبنية وليست للشريحة
(النتيجة 28). إذا لم يكن ذلك صحيحًا، لكان مُجمّع NVIDIA نفسه يُصدر جدولة غير آمنة لإحداها.
كل رقم قِيس على السيليكون يأتي من بطاقة مادية واحدة، مُسمّاة بدقة، لأن "5070 Ti" ليست كافية لإعادة إنتاج تشغيل:
معظم basalt لا يحتاج GPU إطلاقًا. كلا الأوراكل، وقاعدة بيانات التعليمات، والمُجمّع ومدقق المخاطر تعمل مع ptxas وnvdisasm كعمليات فرعية عادية، ولهذا تعمل في CI على جهاز لا يحتوي على بطاقة رسوميات. 237 من أصل 252 اختبارًا في هذه المجموعة، و200 منها لا تحتاج بطاقة ولا ملفات NVIDIA الثنائية.
كل ما قِيس هنا قِيس على بطاقة واحدة، وbasalt يسجّل SKU بجانب كل قياس بدلًا من تقديمها كحقائق عامة. بطاقة 5090 تحتوي على أكثر من ضعف عدد SMs وسلوك ساعة خاص بها؛ سيكون الترميز مطابقًا، لكن يجب إعادة قياس الكمونات بدلًا من افتراضها:```bash python -m basalt.cli measure -o my-card.json python -m basalt.cli verify kernel.cubin --latencies my-card.json
هذا ليس تواضعًا. نموذج زمن الاستجابة المشترك بين المدقّق والمجدول هو بالضبط
المكان الذي يختبئ فيه رقم خاطئ، لذا فإن البطاقة الثانية هي أكثر شيء مفيد يمكن لأي شخص أن يساهم به.
</details>
## كيف يعمل
يعتمد كل شيء على أوراكلَين اثنين، وكلاهما ثنائيات NVIDIA قياسية تُدار كعمليات خارجية. لا يتم استخدام أو إعادة توزيع أي من كود مصدر NVIDIA أو ملفات الرأس أو المكتبات.
| الأوراكل | الاستدعاء | ما يقدمه |
| :--- | :--- | :--- |
| **الحقيقة الأساسية** | `ptxas` → cubin → `nvdisasm -c -hex` | الترميزات التي يصدّرها مترجم البائع فعليًا. دلالات لا تقبل الجدل. |
| **المسبار** | `nvdisasm -b SM120a` على البايتات الخام | يفكّ ترميز كلمات لن يُصدرها `ptxas` أبدًا، مما يحوّل فضاء الترميز إلى شيء قابل للبحث بدلاً من شيء يُخمَن. |
أوراكل المسبار هو الأهم. الأداة المقتصرة على مخرجات المترجم لا يمكنها إلا أن تعيد اكتشاف ما يفعله المترجم بالفعل. إن تغذية كلمات مُصنَّعة بطول 128 بت مباشرةً إلى وحدة فك الترميز تعني أن مجموعة التعليمات يمكن *قياسها*.
لا يحتاج أيٌّ من الأوراكلَين إلى GPU، لذا فإن قاعدة بيانات التعليمات بأكملها يُعاد بناؤها في CI على أي جهاز.
### اشتقاق الترميز بتغييره
basalt لا يقرأ جدول رموز التشغيل (opcodes) من أي مكان. إنه يأخذ ترميزًا تم تجميعه، يقلب بِتة واحدة، يفك ترميز النتيجة، ويسجّل ما تغيّر. البِتة التي تغيّر سجل الوجهة هي بِتة وجهة؛ البِتة التي تغيّر رمز العملية (mnemonic) هي مُحدِّد؛ البِتة التي لا تغيّر شيئًا ملحوظًا هي خاملة.
عند تشغيله على `IADD R5, R5, 0x2a`، تظهر نتيجة القياس كما يلي:```
operand[0] bits 16:23 flip 16 -> R4, flip 17 -> R7 destination register
operand[1] bits 24:31 plus bit 72, which negates it source register
operand[2] bits 32:63 flip 32 -> 0x2b, flip 33 -> 0x28 32-bit immediate
opcode bits 2, 4, 12:15
inert 36 bits no observable effect
invalid 11 bits the decoder rejects the mutation
| المكوّن | ما يفعله | كيف يُفحص | النتيجة |
|---|
| المُجمّع | نص SASS إلى الكلمة ذات الـ128 بتًا | إعادة تجميع كل تعليمة أصدرها ptxas ومقارنة البايتات، على المجموعة المرجعية وعلى 5.2M تعليمة من كود مكتبات مُصدَّر لم يره من قبل | 59,693 من أصل 59,760 تعليمة في المجموعة المرجعية و4,585,336 من أصل 5,237,448 تعليمة مُصدَّرة مطابقة تمامًا، والباقي مرفوض بالاسم، 0 خاطئ في كلٍّ منهما |
| المدقق | يقرأ جدولة ويُبلغ عن المخاطر | يجب أن تتحقق مخرجات البائع بنفسها كسليمة، ويجب اكتشاف stall مُقصَّر عمدًا | 0 أخطاء عبر 1,323 زوجًا من نوى البائع ومستويات التحسين، 0 مفقود على 233 نواة معطوبة |
| التدقيق | المدقق نفسه، على المكتبات المُصدَّرة | تشغيله على نوى sm_120 الإنتاجية المستبعدة من كل جدول يقرؤه | 0 أخطاء عبر 2,762 نواة و10,218,030 تبعية، وكل النوى الـ2,762 محللة بالكامل |
| المجدول | يُسند كل بت تحكم من الصفر | تجاهل بتات البائع، وحساب بتات جديدة، وتشغيلهما على GPU مقابل ثمانية مدخلات، ومقارنة بايتات المخرجات | 439 من 439 نواة قابلة للمقارنة مطابقة بايتًا ببايت، عند مستويات التحسين الثلاثة جميعها |
| البطاقة | إمكانية الحوسبة | مغطاة |
|---|
| GeForce RTX 5090, 5090D | 12.0 (sm_120) | نعم |
| GeForce RTX 5080, 5070 Ti, 5070 | 12.0 (sm_120) | نعم |
| GeForce RTX 5060 Ti, 5060, 5050 | 12.0 (sm_120) | نعم |
| إصدارات الحواسيب المحمولة من سلسلة GeForce RTX 50 | 12.0 (sm_120) | نعم |
| بطاقات محطات العمل RTX PRO Blackwell | 12.0 (sm_120) | نعم |
| مراكز البيانات Blackwell (B100, B200, GB200) | 10.0 (sm_100) | لا، ترميز مختلف |
| البطاقة | ما هي بالضبط |
|---|
| اللوحة | Gigabyte GeForce RTX 5070 Ti EAGLE OC |
| ما يُبلغ عنه برنامج التشغيل | NVIDIA GeForce RTX 5070 Ti |
| إمكانية الحوسبة | 12.0 |
| معالجات التدفق المتعددة | 70 |
| ساعة التعزيز | 2542 MHz |
| مجموعة الأدوات | CUDA 13.3.1, ptxas V13.3.73 |
| يحتاج بطاقة | لماذا |
|---|
measure, probe-stalls | توقيت تعليمة، واكتشاف ما تتطلبه التبعية فعلًا عن طريق كسرها |
scripts/roundtrip_corpus.py | إعادة جدولة كل نواة في المجموعة المرجعية وتشغيل النسختين لمقارنة بايتات المخرجات |
scripts/agreement_sweep.py | تقصير تبعية واحدة لكل نواة وسؤال السيليكون عما إذا كان basalt محقًا |
رفع تردد التشغيل من المصنع لا يحرّك القياسات. كل كمون هنا بوحدة الدورات، وهي خاصية لخط الأنابيب وليست للساعة، ويُسجَّل رقم التعزيز بجانبها فقط لتبقى المقارنة بزمن الحائط ممكنة. ما تؤثر فيه اللوحة فعلًا هو قابلية إعادة الإنتاج، ولهذا يسجّلها basalt measure --board.
حقول تسجيل بعرض 8 بت وقيمة فورية بعرض 32 بت، تم تحديدها بالتجربة لا بالافتراض.
| الحقل | البتات | المعنى |
|---|---|---|
stall | 108:105 | دورات الانتظار قبل إصدار التعليمات التالية |
yield | 109 | تلميح إلى أن مُجدول الالتفاف قد يبدّل بين الالتفافات |
write_barrier | 112:110 | لوحة تسجيل للإشارة عند كتابة النتيجة (7 = لا شيء) |
read_barrier | 115:113 | لوحة تسجيل للإشارة عند قراءة المعامل (7 = لا شيء) |
wait_mask | 121:116 | لوحات التسجيل التي يجب أن تكون فارغة قبل الإصدار |
reuse | 125:122 | أعلام ذاكرة تخزين مؤقت لإعادة استخدام المعاملات، علم واحد لكل خانة مصدر |
يُثبت هذا التخطيط صحته عند أول استخدام. في نواة بسيطة، يعيّن S2R القيمة write_barrier=0، وتحمل تعليمة IMAD التي تستهلك نتيجته wait_mask=0x01؛ ويعيّن LDCU.64 القيمة write_barrier=1 وتحمل تعليمة STG.E التابعة له wait_mask=0x02. كل زوج من المُنتِج والمُستهلك يتطابقان، والتعليمات التي تُعلّق عليها nvdisasm بـ.reuse لديها بت إعادة الاستخدام المطابق مضبوطًا.
لا يتطلب تثبيت CUDA ولا GPU. يجلب سكربت سلسلة الأدوات ملفات إعادة توزيع مثبّتة الإصدار، بحجم يقارب 45 ميغابايت، دون صلاحيات مسؤول، ودون إضافة أي شيء إلى مسار PATH الخاص بك.```bash git clone https://github.com/sunnypatell/basalt.git cd basalt python -m venv .venv && source .venv/bin/activate # Windows: ..venv\Scripts\Activate.ps1 pip install -e ".[dev]"
python scripts/fetch_toolchain.py # pinned ptxas + nvdisasm python -m basalt.cli doctor # verify both oracles end to end python scripts/verify_all.py # every control in this README, in order
لم يتم توفير أي محتوى للترجمة في هذه القطعة (المدخل فارغ).```console
$ python -m basalt.cli doctor
ok toolchain V13.3.73 in third_party/cuda/13.3.1/bin
ok ptxas assembled sm_120a
ok cubin oracle 16 instructions with encodings
ok probe oracle 16/16 mnemonics round-tripped
both oracles healthy. no GPU required for anything above.
pip install basalt-sass يثبّت CLI والمكتبة وجداول القياس الثلاثة جميعًا، دون
أي تبعيات وقت تشغيل. استخدم هذا إذا كان CUDA مثبتًا بالفعل على الجهاز؛ أما الاستنساخ أعلاه
فهو ما تريده إذا لم يكن كذلك، أو إذا كنت تنوي إعادة إنتاج القياسات.```bash
pip install basalt-sass
basalt doctor
basalt verify kernel.cubin
### أين يبحث عن `ptxas` و`nvdisasm`
يقوم basalt بتشغيلهما كعمليتين خارجيتين ولا يعيد توزيع أيٍّ منهما، لذا يجب عليه العثور على نسخة.
يأخذ أول نسخة تستجيب، و**أي تثبيت CUDA 13 سيفي بالغرض**: لا يجب أن يكون أيٌّ منهما هو
الحزمة القابلة لإعادة التوزيع المثبّتة.
| الترتيب | المكان |
| ---: | :--- |
| 1 | `--cuda-bin`، يُمرَّر عبر سطر الأوامر |
| 2 | `BASALT_CUDA_BIN`، وهو دليل يحتوي على الملفين التنفيذيين معًا |
| 3 | `CUDA_PATH` أو `CUDA_HOME` أو `CUDA_ROOT`، كلٌّ منها مضافًا إليه `/bin` |
| 4 | `ptxas` في `PATH` الخاص بك |
| 5 | `third_party/cuda/<version>/bin` في نسخة مستخرجة من المستودع، الأحدث أولاً |
`basalt doctor` يطبع أيًّا منها تم تحديده، ويخرج برمز غير صفري عندما لا يتمكن من العثور على واحد، لذا
فهو يعمل كشرط مسبق لخطوة البناء وليس مجرد شيء للقراءة.
الاستعلام عن قاعدة بيانات التعليمات لا يتطلب أي سلسلة أدوات على الإطلاق، لأن قاعدة البيانات تُقاس
مسبقًا وتُضمَّن داخل الحزمة:```bash
basalt isa --stats
basalt isa --opcode QMMA
أعد بناء قاعدة بيانات التعليمات من الصفر، أو استعلم عن القاعدة المُلتزمة:```bash python -m basalt.cli build-isa # harvest, probe, write src/basalt/data/isa/sm_120a.json python -m basalt.cli isa --stats python -m basalt.cli isa IMAD.WIDE.U32 # one form, with its measured field layout python -m basalt.cli isa --opcode QMMA # every form of one opcode
### افحص كود الآلة الذي لم تكتبه
هذا هو الجزء الذي لا يفعله أي شيء آخر، ولا يتطلب GPU ولا وسائط. نموذج
زمن الاستجابة المُقاس وجدول المتطلبات المُستخرج كلاهما مُودَعان في المستودع، لذا يمكن توجيه استنساخ جديد
مباشرة إلى ملف cubin، أيًا كان ما أنتجه:```bash
python -m basalt.cli verify kernel.cubin
I need to translate the content, but the INPUT section appears to be empty—no actual Markdown content was provided after "INPUT:". There is nothing to translate.```console $ python -m basalt.cli verify nvjpeg.sm_120.cubin 25 kernels, 0 with an error 7984 instructions in 789 blocks, 11580 dependencies checked across blocks: 0 errors, 3 warnings pair data: 3957 pairings from 25634 kernels, 427 producers with enough observations to use latency model: measured on NVIDIA GeForce RTX 5070 Ti
مكتبة ELF تحتوي على مئات النوى (kernels) ويتم فحص كل واحد منها على حدة، لأن الإزاحات (offsets) تبدأ من الصفر من جديد ولا يمر شيء من واحدة إلى التالية. أضف `--strict` للخروج برمز غير صفري عند وجود خطر، وهذا هو المطلوب في خطوة بناء. إذا كان لديك بطاقة sm_120 وتريد قياس النموذج على السيليكون الخاص بك بدلاً من الموجود في هذا المستودع:```bash
python -m basalt.cli measure -o my-card.json # needs a GPU, once
python -m basalt.cli verify kernel.cubin --latencies my-card.json
| الأمر | ما يفعله | يحتاج إلى GPU |
|---|---|---|
doctor | يفحص كلا الأوراكل من البداية إلى النهاية | لا |
build-isa | يجمع ويستكشف، ويكتب قاعدة بيانات التعليمات | لا |
isa | يستعلم عن صيغة، أو opcode، أو التغطية | لا |
validate-isa | يُثبت إمكانية الكتابة عبر الحقول المقاسة | لا |
mine-stalls | يستخرج متطلبات كل زوج من جدولة المترجم | لا |
verify | يفحص بتات التحكم في ملف cubin بحثًا عن مخاطر البيانات | لا |
schedule | يعين بتات التحكم في ملف cubin من الصفر ويتحقق من النتيجة | لا |
assemble | يشفر نص SASS، أو ملف cubin كامل، ويعيد قراءته لإثبات ذلك | لا |
measure | يقيس زمن استجابة التعليمات على السيليكون الحقيقي | نعم |
probe-stalls | يجد التوقف المطلوب بتعطيل البرامج عن قصد | نعم |
كل ما يفعله CLI قابل للاستيراد، وواجهة المكتبة مع أمثلة قابلة للتشغيل موجودة
في docs/API.md.
وأما الضابطان اللذان يُبقيان البقية صادقة. الأول يحتاج إلى بطاقة؛ والثاني يحتاج إلى المكتبات المرفقة ولا يحتاج إلى أي عتاد على الإطلاق:```bash python scripts/roundtrip_corpus.py # reschedule all 441 corpus kernels, run both on the GPU
python scripts/fetch_toolchain.py --libs # ~1.2 GB, no admin, nothing on PATH python scripts/audit_shipped.py --libs third_party/cuda/13.3.1/libs
لم يتم توفير نص المصدر للترجمة.```console
$ python -m basalt.cli verify kernel.cubin --latencies src/basalt/data/latency/rtx-5070-ti.json
kernel.cubin
32 instructions in 3 blocks, 23 dependencies checked: clean
latency model: measured on NVIDIA GeForce RTX 5070 Ti
الأرقام هنا تُطبع بواسطة الأدوات وتُعاد توليدها من سحب نظيف. الأوامر أعلاه هي مصدر الحقيقة؛ هذه الجداول لقطات.
قاعدة بيانات التعليمات. كل إدخال يحمل ترميزًا جُمِّع فعلًا وبنية المُصرِّف التي أنتجته.
| قاعدة بيانات التعليمات | العدد |
|---|---|
| نماذج التعليمات | 345 |
| رموز تشغيل متميزة | 90 |
| نماذج بخريطة معاملات كاملة | 339 |
| نماذج نوى التنسور | 46 |
| بُني باستخدام | ptxas V13.3.73 |
تغطية التنسور هي حيث يعيش عتاد الدقة المنخفضة: HMMA وIMMA وQMMA عبر أنواع FP8 وFP6 وFP4 بما في ذلك أزواج المعاملات غير المتماثلة، ونماذج عامل المقياس QMMA.SF وOMMA.SF التي تحمل أسًا لكل كتلة، وIMMA.SP المتناثر، وتعليمات حركة المصفوفات LDSM وSTSM وMOVM بكل الأشكال بما في ذلك المتغيرات المنقولة.
الكمون، على بطاقة RTX 5070 Ti. 70 SM، كل ملاءمة R² ≥ 0.9998. قِيس بتوقيت السلاسل المعتمدة وأخذ الميل، مع قراءة طول السلسلة من SASS المُجمَّع بدلًا من افتراضه.
| التعليمات | الدورات |
|---|---|
IMAD IADD3 FFMA FADD FMUL LOP3 SHF | 4 |
POPC | 18 |
I2FP + F2I معًا | 24 |
MUFU | 44 |
DADD DFMA | 64 |
ثلاثة منها تناقض النموذج المفترض الذي صدرت به basalt: افترض DADD بمقدار 48، وPOPC بمقدار 4، وكل تحويل بمقدار 6 مقابل 24 مُقاسًا للرحلة ذهابًا وإيابًا.
نموذج الكمون المفترض ليس تقريبًا صغيرًا لنموذج مُقاس، وهذه هي الحجة الكاملة للقياس.
والتعليق (stall) بقيمة صفر ليس صفر دورة. إنه ترميز آمن مميز ينتظر النتائج المعلقة، ويكلف حوالي 37 دورة بينما تكلف التعليمة المجدولة 4. لهذا يُصدر ptxas -O0 كلمة تحكم مُصفَّرة بالكامل ومع ذلك يحسب الكود بشكل صحيح، لكنه أبطأ بنحو تسعة أضعاف.
stall | دورات/تعليمة | النتيجة |
|---|---|---|
| 0 | 36.85 | صحيح |
| 1 | 4.88 | خاطئ |
| 2 | 4.88 | خاطئ |
| 3 | 5.88 | خاطئ |
| 4 | 6.88 | صحيح |
إنه يتفق مع مُصرِّف البائع على كل نواة في المجموعة. كل نواة يبنيها ptxas من المجموعة تُتحقق مقابل جدولتها الخاصة، عند كل مستوى تحسين يُجري جدولة: 30,421 اعتمادًا، صفر أخطاء. يعمل ذلك المسح في CI عند كل push، وكل خطأ نمذجة ارتكبه هذا المشروع التُقط بواسطته لا بالاستدلال.
الأحكام تطابق الشريحة. لكل تعليق قابل للترميز على مُنتِج معتمد، يتوافق جواب basalt الثابت مع ما يحسبه العتاد فعلًا، بما في ذلك حالة الصفر. ذلك محفوظ كاختبار، لا يُدَّعى هنا. الأدلة الكاملة، بما فيها ثلاث طرق مستقلة للتعليق المطلوب والتصحيحات التي أُجريت على طول الطريق، موجودة في findings.
وعندما يقول إن جدولة ما غير آمنة، توافقه الشريحة. خُذ جدولة البائع العاملة نفسها لـ 233 نواة، واقصُر اعتمادًا حقيقيًا واحدًا في كل منها، وقارِن حكم basalt بما تحسبه البطاقة: 79 وصفها بأنها معطوبة كانت معطوبة فعلًا، ولا شيء وصفه بأنه آمن أعطى جوابًا خاطئًا. بدأ ذلك الرقم بـ 34 فائتة لا صفر، ويقول findings ما كان السبب وما كلفه إصلاحه من إنذارات كاذبة، لأن مسحًا لا يُبلِّغ إلا رقمه النهائي يساوي أقل من مسح يُبلِّغ عن رقمه الأول.
المُتحقِّق يجيب عما إذا كانت الجدولة آمنة. والمُجدوِل يجيب عما ستكون عليه الجدولة الآمنة، من القياسات نفسها: يتجاهل كل بت تحكم أنتجه ptxas، ويحسب ما يخصه، ويعيد النتيجة إلى المُتحقِّق، ثم يشغّلها على البطاقة بجانب نسخة البائع من النواة نفسها.
عند تشغيله على المجموعة كلها على البطاقة، عند كل مستوى تحسين يُنتج جدولة، تخرج كل النوى الـ 439 القابلة للمقارنة بحساب نتائج مطابقة بايتًا ببايت لجدولة البائع، من بتات تحكم اشتقتها basalt بنفسها. أما النواتان المستثنيتان فتقرآن الساعة ومعرّف الشبكة، لذا لا تتفقان مع نفسيهما أيضًا، ويقول ذلك findings بدلًا من إدراجهما في نسبة مئوية.
ذلك التحكم هو سبب جدارة كل ما تبقى بالثقة. يقرأ المُدقِّق والمُجدوِل نموذج الكمون نفسه، لذا فإن أي إدخال خاطئ فيه يُرضيهما معًا فيتوافقان مع بعضهما بينما كلاهما خاطئ. والشريحة وحدها لا مصلحة لها في الجدل. تشغيل المُجدوِل على سبع نوى مكتوبة يدويًا نجح سبعًا من سبع لفترة طويلة؛ وتشغيله على ثلاثمئة وجد واحدًا وأربعين خاطئة، وكل تصحيح للنموذج منذ ذلك الحين خرج من مراقبة ذلك الرقم وهو يتحرك.
تلك الحلقة هي مصدر الأخطاء الحقيقية. التعليق الذي يُقضى خارج النافذة بين المُنتِج والمستهلك لا يساوي شيئًا، وقضاؤه هناك ينهي البحث ببرنامج لا يزال ناقصًا. تعليق مُثبَّت على الترميز الآمن كانت تمريرة لاحقة تكتب فوقه، فتُبدِّل ضمانة برقم صغير. معاملات fp64 تحتل أزواج سجلات دون ما يشير إلى ذلك في الاسم الرمزي، لذا كان نصف كل اعتماد fp64 غير مرئي لكل من المُدقِّق والمُجدوِل. المسند المستخدم كحارس لتعليمة يحتاج ثلاث عشرة دورة بينما يحتاج المسند نفسه المقروء كبيانات خمس دورات، لأن الحارس يجب أن يُحسم قبل أن تُصدَر التعليمة أصلًا. والانتظار على لوحة النتائج لا يحسم الاعتماد تمامًا: إذ يبقى على المُنتِج تعليق صغير خاص به، دورتان لإضافة fp64، ودورة واحدة أقل تكون خاطئة بصمت. لم يُكتشف أي من تلك بالاستدلال؛ كل واحد اكتُشف بتشغيل المخرجات والحصول على رقم خاطئ.
[!NOTE] 1.0، ودقيق بشأن ما يعنيه ذلك. ما أُنجز: المرجعان معًا، وقاعدة بيانات التعليمات بحقولها المُثبت أنها قابلة للكتابة، ومُدقِّق التعارضات على رسم بياني حقيقي لتدفق التحكم، وكمون مُقاس على SKU واحد بثلاث طرق مستقلة، ومُجدوِل يُمرِّر كل نواة مجموعة قابلة للمقارنة عبر العتاد ويعيدها بايتًا ببايت، وتدقيق 2,762 نواة إصدار مُستبعدة من كل جدول يقرؤه المُدقِّق. ما لم يُنجز: 12 نواة من المجموعة غير قابلة للتشغيل ببنيتها، ونواتان مخرجات البائع فيهما غير حتمية، كلها مُسمّاة في findings؛ وعشرة رموز تشغيل ما تزال تحمل كمونًا مفترضًا لا مُقاسًا، ولا واحد منها مُنتِج في أيٍّ من الكودين؛ وبطاقة رسوميات واحدة فقط قِيست، وهو أمر يُظهره finding 28 أنه أقل أهمية مما يبدو. وحيث يُستنتج شيء بدلًا من قياسه، تقول الأدوات ذلك بدلًا من تقريبه إلى حقيقة. انظر roadmap وmethod.
```
src/basalt/
toolchain.py Locating and driving ptxas / nvdisasm
encoding.py The 128-bit instruction word and its control fields
disasm.py Both oracles: cubin ground truth and raw-word probe
harvest/ PTX corpus generation and encoding extraction
probe/ Differential bit probing and field inference
isa/ The generated instruction database and its builder
asm/ The assembler, and the ELF reader that rewrites words in place
sched/ Assigning the control bits, and costing the result
verify/ Register def-use analysis, hazard model, latency checking
gpu/ Driver-API bindings and the latency measurement harness
src/basalt/data/ The measured tables, inside the package so an installed copy
has them: the ISA database, the latency model and the mined
stall requirement
docs/ Findings, method, the Python API, roadmap, artwork sources
scripts/ Toolchain fetch, asset rendering, drift check, and the two
hardware controls: the corpus round trip and the agreement sweep
tests/ Unit tests, plus toolchain- and GPU-marked suites
</details>
## موقف الغرفة النظيفة
basalt عمل مستقل قائم على مبدأ الغرفة النظيفة من أجل قابلية التشغيل البيني. لا يحتوي على أي كود مصدري أو ملفات رؤوس أو مكتبات أو توثيق من NVIDIA، ولا يعيد توزيع أيًّا منها. يراقب سلوك الملفات التنفيذية الموزعة علنًا ويسجّله، وهو الأساس الذي قام عليه هذا النوع من العمل لأكثر من عقد.
NVIDIA وCUDA وBlackwell علامات تجارية لشركة NVIDIA Corporation. هذا المشروع ليس تابعًا لشركة NVIDIA، وليس معتمدًا منها، وليس برعاية منها.
مرخّص بموجب [Apache-2.0](https://github.com/sunnypatell/basalt/blob/main/LICENSE). اختيرت Apache بدلًا من ترخيص أكثر تقييدًا عن قصد: أداة التحقق من الصحة التي لا يُسمح لأحد بالبناء عليها هي أداة لا يشغّلها أحد، ومنح براءات الاختراع مهمٌّ لعملٍ بهذا القرب من العتاد.
## المساهمة
المساهمة الأعلى قيمة هي ترميز (encoding) يخطئ فيه basalt. انظر [`CONTRIBUTING.md`](https://github.com/sunnypatell/basalt/blob/main/CONTRIBUTING.md) و[قالب فجوة ISA](https://github.com/sunnypatell/basalt/blob/main/.github/ISSUE_TEMPLATE/isa_gap.yml)، الذي يجمع ما يكفي لإعادة الإنتاج دون الحاجة إلى جهازك.
يُبيّن [`SUPPORT.md`](https://github.com/sunnypatell/basalt/blob/main/SUPPORT.md) أين تُوجَّه الأسئلة، و[`GOVERNANCE.md`](https://github.com/sunnypatell/basalt/blob/main/GOVERNANCE.md) ما الذي يجب أن يجتازه أي تغيير، و[`RELEASING.md`](https://github.com/sunnypatell/basalt/blob/main/RELEASING.md) كيف يُصدَر الإصدار ويُتحقَّق منه، و[`SECURITY.md`](https://github.com/sunnypatell/basalt/blob/main/SECURITY.md) كيف يُبلَّغ عن الثغرات بشكل خاص.
## الاستشهاد بـ basalt
إذا كان basalt مصدر إلهام أو أساسًا لورقة بحثية أو أداة أو نموذج أو تقرير خطأ، فيُرجى الاستشهاد به. يقرأ GitHub ملف [`CITATION.cff`](https://github.com/sunnypatell/basalt/blob/main/CITATION.cff) بشكل أصلي، لذا فإن خيار **استشهد بهذا المستودع** في الشريط الجانبي يمنحك صيغتَي APA وBibTeX دون أي نسخ يدوي. الملف نفسه هو ما يتحلّله Zenodo وبرامج إدارة الاستشهادات، وهو السجلّ المعتمد للتأليف.
المفتاح أدناه هو ما يولّده GitHub، لذا فإن النسخ من هنا والنسخ من الشريط الجانبي يعطيان نفس الإدخال بدلًا من إدخالين يبدوان كعملين مختلفين:```bibtex
@software{Patel_basalt_a_hazard_2026,
author = {Patel, Sunny},
license = {Apache-2.0},
month = aug,
title = {{basalt: a hazard checker, assembler and scheduler for NVIDIA consumer Blackwell (sm\_120)}},
doi = {10.5281/zenodo.22072811},
url = {https://github.com/sunnypatell/basalt},
version = {1.0.0},
year = {2026}
}
استشهد بـ DOI المفاهيمي، 10.5281/zenodo.22072811، بدلاً من DOI إصدار أو هذا الرابط. فهو يُحيل إلى أحدث إصدار، لذا يبقى صحيحًا دون أن يُعدَّل مرة أخرى. CITATION.cff يحمله، لذا فهو موجود بالفعل بالصيغتين أعلاه.
إذا أعدت استخدام الجداول المُقاسة (src/basalt/data/) أو أعدت إنتاج شكل بياني، فاستشهد بالإصدار الذي جاءت منه بدلاً من main: فالأرقام تُعاد توليدها بواسطة scripts/verify_all.py عند commit معيّن، والوسم (tag) هو ما يجعل ذلك قابلاً لإعادة الإنتاج.
الإسناد شرط ترخيص، وليس مجاملة. يشترط Apache-2.0 §4 أن تُرفق LICENSE وNOTICE بأي إعادة توزيع أو عمل مشتق، ويتضمن NOTICE معلومات التأليف وبيان الغرفة النظيفة. تحتفظ جميع الفروع (forks) والنسخ المضمّنة (vendored copies) والعبوات المعاد تغليفها (repackaged wheels) بالملفين معًا.
Sunny Patel · sunnypatel.net · github.com/sunnypatell