Turbolog: حذف چشمکزدن
پاک کردن کنسول پیش از هر فریم باعث میشد در 70–81% از دفعات ترسیم DevTools، کنسول آشکارا خالی بماند. افزودن فریمها به انتها این میزان را به 1% رساند که تمام آن مربوط به فریم اول بود.
هر فریم Text.js یک فراخوانی console.log است. تا نسخهٔ 0.4، پیش از هر فریم console.clear() هم فراخوانی میشد. زیر بار، کنسول بین فریمها لحظهای خالی میشد.
اندازهگیری چشمکزدن
برای اندازهگیری آن، bench/devtools را ساختیم. این ابزار Chrome for Testing را اجرا میکند، رابط واقعی DevTools را بهصورت یک صفحه باز میکند و آن را برای اندازهگیری مجهز میکند:
- در هر
requestAnimationFrameدر رابط DevTools، بررسی میکند که آیا یک فریم کامل 32 ردیفی در محدودهٔ دید کنسول قرار دارد. ترسیمهایی که چنین فریمی ندارند، ترسیم خالی هستند. - سپس فریمهای
Page.startScreencastرا رمزگشایی میکند تا نتیجه را در سطح پیکسل تأیید کند. - هر فریم در ردیف 0 حاوی
FRAME:<id> · T:<epochMs>است تا رابط بتواند تشخیص دهد کدام فریم را نمایش میدهد و چقدر تأخیر دارد.
با فراخوانی 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 میلیثانیه چیزی نمایش داده نمیشود.
افزودن فریمها به انتها
از نسخهٔ 0.4، Turbolog فریمها را به انتها میافزاید. DevTools در پایین کنسول میماند، بنابراین فریم جدید در یک ترسیم جای فریم قبلی را میگیرد. یک span با عرض صفر در ابتدا و با سبک margin-top:100vh (پرده)، فریمهای قبلی را از دید خارج میکند و خط خودش را پایان میدهد تا پیوند منبع DevTools هرگز عرض ردیف 0 را کم نکند.
کنسول همچنان باید در نهایت خالی شود. پاکسازی فقط در فریم اول، پس از فراخوانی invalidate()، در زمان بیکاری پس از انباشته شدن 100 فریم و در سقف قطعی 300 فریم انجام میشود.
تنظیم آهنگ با محدودکنندهٔ نرخ
ارسال فریمها سریعتر از توان ترسیم DevTools هیچچیز را سریعتر نمیکند. گزارشی که هنگام انتظار محدودکنندهٔ نرخ برسد، آن را از نو راه میاندازد؛ بنابراین فریمها حذف میشوند: با نرخ 60 فریم بر ثانیه، DevTools از 295 فریم ارسالشده، 67 فریم را ترسیم کرد. 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 عرضه میشود. هیچکدام به تغییر کد برنامه نیاز ندارند.