Turbolog: إزالة الوميض
كان مسح وحدة التحكم قبل كل إطار يتركها فارغة بوضوح في 70–81% من عمليات الرسم في DevTools. خفّض إلحاق الإطارات النسبة إلى 1%، وكلها في الإطار الأول.
كل إطار في Text.js هو استدعاء واحد للدالة console.log. حتى الإصدار 0.4، كان كل إطار مسبوقًا أيضًا باستدعاء console.clear(). تحت الحمل، كانت وحدة التحكم تومض فارغة بين الإطارات.
قياس الوميض
لقياسه، أنشأنا bench/devtools. يشغّل Chrome for Testing، ويفتح الواجهة الأمامية الفعلية لأدوات DevTools كصفحة ويزوّدها بأدوات القياس:
- عند كل
requestAnimationFrameفي الواجهة الأمامية لأدوات DevTools، يتحقق من وجود إطار كامل من 32 صفًا في نطاق عرض وحدة التحكم. تُعد عمليات الرسم التي لا تحتوي على إطار كامل عمليات رسم فارغة. - يفك ترميز إطارات
Page.startScreencastلاحقًا لتأكيد النتيجة على مستوى البكسل. - يحمل كل إطار
FRAME:<id> · T:<epochMs>في الصف 0، لتتمكن الواجهة الأمامية من تحديد الإطار الذي تعرضه ومقدار تأخره.
مع استدعاء console.clear() قبل كل إطار، كانت لوحة معلومات بأبعاد 100×32 وبمعدل 15 إطارًا في الثانية فارغة في 70.6% من عمليات الرسم في DevTools. وعند 60 إطارًا في الثانية، بلغت النسبة 81.1%.
السبب
يتعامل ConsoleView في DevTools مع الاستدعاءين بطريقتين مختلفتين:
- تستدعي
console.clear()الدالةconsoleCleared()، التي تبطل نطاق العرض تزامنيًا. تختفي كل الرسائل ضمن المهمة نفسها. - تستدعي
console.log()الدالةaddConsoleMessage()، التي تكتفي بجدولة تحديث عبرviewportThrottler، وهوThrottlerبمهلة 50 ms.
لذا يزيل كل إطار الإطار القديم فورًا ويرسم الجديد لاحقًا. عند 15 إطارًا في الثانية، لا يظهر شيء خلال نحو 50 من كل 66 ms.
إلحاق الإطارات
منذ الإصدار 0.4، يلحق Turbolog الإطارات. تظل DevTools عند أسفل وحدة التحكم، فيحل الإطار الجديد محل القديم ضمن عملية رسم واحدة. يدفع span في البداية بعرض صفري وبالسمة margin-top:100vh (الستار) الإطارات السابقة خارج نطاق العرض، وينهي سطره الخاص حتى لا يضيّق رابط المصدر في DevTools الصف 0 مطلقًا.
لا بد من إفراغ وحدة التحكم في نهاية المطاف. يحدث المسح فقط عند الإطار الأول، وبعد invalidate()، وعند الخمول بعد تراكم 100 إطار، وعند بلوغ الحد الأقصى البالغ 300.
ضبط الوتيرة وفق محدّد المعدل
لا يؤدي إرسال الإطارات بسرعة تفوق قدرة DevTools على رسمها إلى تسريع أي شيء. يعيد السجل الوارد أثناء انتظار محدّد المعدل تشغيله، فتُسقط إطارات: عند 60 إطارًا في الثانية، رسمت DevTools عددًا قدره 67 من أصل 295 إطارًا مرسلًا. يضبط Turbolog وتيرة الإطارات بفاصل لا يقل عن 66 ms، أي نحو 15 إطارًا في الثانية، ويظل يعرض الإدخال المنفصل تزامنيًا حين يسمح الفاصل بذلك.
كسر قفل الطور
أضافت عمليات المسح أيضًا تأخرًا بنحو 50 ms إلى كل إطار لاحق. بعد المسح، تدرج DevTools صفًا اصطناعيًا يحمل Console was cleared. يشغل هذا الصف خانة التنفيذ الفوري لمحدّد المعدل ويدفع الإطار التالي إلى المؤقت ذي المهلة 50 ms، ومع وتيرة ثابتة بفاصل 66 ms يظل كل إطار لاحق مقيدًا بذلك المؤقت.
ينتظر العارض الآن 110 ms مرة واحدة بعد أي مسح. بعد ذلك، يصل كل إطار بعد أكثر من 50 ms من اكتمال التحديث السابق ويسلك مسار التنفيذ الفوري في DevTools. انخفض وسيط تأخر العرض من 63 ms إلى 10.4 ms.
النتائج
bun bench/devtools/run.ts --strategy=native,clear --fps=15,60 --seconds=5، لوحة معلومات بأبعاد 100×32، والواجهة الأمامية الفعلية لأدوات DevTools:
| آلية التشغيل | إطارات في الثانية | عمليات الرسم الفارغة | المرسوم / المرسل | التأخر p50 |
|---|---|---|---|---|
| مسح لكل إطار | 15 | 70.6% | 70 / 75 | 60.4 ms |
| إلحاق (1.0) | 15 | 1.0% | 74 / 75 | 10.4 ms |
| مسح لكل إطار | 60 | 81.1% | 45 / 300 | 9.8 ms |
| إلحاق، دون ضبط الوتيرة | 60 | 0.8% | 67 / 295 | 31.2 ms |
تعود نسبة 1% المتبقية إلى الإطار الأول، الذي يمسح عمدًا. تعرض عمليات الرسم الفارغة فيه الصف Console was cleared، لا وحدة تحكم فارغة.
خصائص أقل لكل span
أظهرت الشيفرة المصدرية لأدوات DevTools تكلفة أخرى. فهي تنسخ كل خاصية مفصّلة من نمط %c إلى كل غلاف سطر، لذا توسّعت الصيغ المختصرة font: و margin: إلى نحو 33 خاصية لكل span. تستخدم عناصر span الآن الخصائص المفصّلة فقط، نحو 7 لكل منها، مع ألوان بالنظام الست عشري.
صدر وضع الإلحاق في Text.js 0.4، ويصدر إصلاح قفل الطور في 1.0. لا يتطلب أي منهما تغييرات في شيفرة التطبيق.