Від чорного прямокутника в Яндекс.Браузер до прискорення всього Chromium

Сьогодні ми розповімо вам історію про один цікавий ба в Яндекс.Браузері, виправлення якого призвело до значного прискорення відтворення у всьому проекті Chromium. І допоможуть мені в цьому Кирило drBasic Плєшивцев і Вадим Lof Петров, фахівці з нашої команди, яким пощастило і розбиратися з проблемою. Передаю їм слово.



Один не зовсім звичайний баг

Мене звати Кирило, я працюю в групі внутрішніх компонентів Яндекс.Браузера в Новосибірську. В один не зовсім прекрасний день колеги з тестування Яндекс.Браузера відтворили проблему з програванням відео через Flash Player. І оскільки саме наша група відповідає за цю частину браузера (медіа, кодеки, ось це все), завдання дісталася мені. Баг, скажімо так, не претендував на оригінальність. Клік по кнопці Play приводив до чорного прямокутника замість коректного відтворення відео. Цей симптом я зустрічав і раніше, тому розраховував на досить швидку локалізацію проблеми. Але я помилявся.

Буквально в перші ж хвилини вдалося з'ясувати, що чорний прямокутник виникає не завжди, а тільки для flash-елементів за типом transparent, тобто напівпрозорих. Відмінно, вже є за що зачепитися при налагодженні. Збираю debug-версію браузера, запускаю, бага немає. А це вже тривожний дзвінок. Розбіжності в роботі debug і release версій — це завжди дуже весело. Тому наважуюся зібрати ще і релізну версію. Зібрав, запускаю, бага немає.

Задумався. У чому відмінності моєї релизной збірки від тієї, що збирає сервер? Відразу згадав про компоновку бібліотек. Розробники збирають браузер в режимі shared_library. Це збільшує кількість dll, але зате сильно економить час компонування. Поширюється ж браузер, зібраний у режимі static_library, при якому збирається лише кілька великих dll. Виставляю прапор static_library, роблю повну збірку. Спостерігаю, як link.exe повільно з'їдає всю оперативну пам'ять, але немає, 16 ГБ RAM вистачить усім, компонування завершується без допінгу у вигляді файлу підкачки. Запускаю. Бага немає.

Серйозно задумався. Згадав, що складальний сервер збирає релізний Яндекс.Браузер з прапором official, який трохи змінює поведінку (докладніше розповімо трохи пізніше). Збираю з цим прапором. Тремтячою рукою запускаю браузер. Ви вже вгадали? Бага немає.

Тут я не на жарт стривожився і почав думати з усіх сил. Через деякий час звернув увагу на те, що сервер збирає Яндекс.Браузер за допомогою Visual Studio 2013. А я ж використав 2015 версію. Збираю в 2013 версії. Запускаю. Баг є! Хто б міг подумати, що я так буду радіти помилку.

Якщо ви зараз подумали, що вся проблема полягала тільки у версії VS, то помиляєтеся. Баг дійсно не відтворювався в debug-версії браузера. Досвідченим шляхом вдалося встановити, що для появи помилки з чорним прямокутником браузер має бути зібрано не тільки з допомогою VS 2013, але і в статичною компонуванні з прапором official. Про причини такої дивної поведінки ви дізнаєтеся трохи пізніше.

Наступні два дні були не менш цікавими. У ході налагодження мені вдалося зрозуміти, що сам плагін Flash Player відпрацьовує своє завдання коректно: відео відтворюється. Його інтеграція з браузером питань також не викликала. Результат його роботи передавався для малювання, але з якихось причин на екрані ми бачили зовсім інше. А це означає, що баг потрібно було шукати в тій частині браузера, яка відповідає за обробку. І тут я передаю слово Вадиму.

Оптимізують це

Як ви вже зрозуміли, тепер на зв'язку Вадим. Працюю я в групі розробки рендеринг-движка Яндекс.Браузера в Москві. Кілька слів про те, як взагалі відбувається побудова в Яндекс.Браузер або Chromium. Все, що ви бачите у вікні браузера, є результат поєднання різних шарів (веб-сторінка, інтерфейс), майже як в Photoshop. За роботу з цими шарами відповідає компонент Compositor (або chrome для s Compositor == CC). А ось для відтворення кожного шару СС викликає спеціальну опенсорсную бібліотеку Skia.

Замість з Кирилом ми зрозуміли, що сліди бага йдуть в Skia. Залишалося зрозуміти, куди саме. На щастя, у мене була цінна порада. Майже на самому початку Кирил її згадав. Мова про те, що проблема виникає тільки у разі flash-елементів з прозорістю. Щоб промалювати на екрані такий елементи, браузеру необхідно поєднати зображення відео з фоном. І для цього в Skia є спеціальна функція SrcATop, що відповідає за блендінг. Кілька хвилин пошуку, і ось я вже знайшов багрепорт зі схожою проблемою в Chrome, який остаточно розвіяв усі сумніви.

Ура. Ми локалізували джерело проблеми аж до конкретної функції. А тепер, увага. Цю ділянку коду не містив ніяких помилок. Зовсім ніяких. І працював він ідеально для будь-яких збірок крім самої фінальної, яка і надсилається користувачам. Причому тільки для Visual Studio 2013. І ось у цей момент я зрозумів, чому Кирило називав цей баг «веселим».

Починаю розбиратися в інших відмінностях, які впливають на відтворюваність помилки. Настав час знову згадати про прапор official, що використовуються тільки в самому кінці. Крім усього іншого, цей прапор впливає на оптимізацію, а точніше на параметр /LTCG. Коли він зазначений, компілятор виробляє досить серйозну оптимізацію всієї програми. На це йде дуже багато часу, тому такі збірки просто так не збирають. Але як оптимізація може призвести до помилки? Щоб зрозуміти це, нам знадобиться невеликий флешбек.



У 2011 році проект Chromium став настільки великим і складним, що компонувальник Visual Studio 2010 якось не зміг слинковать його з усіма оптимизациями через брак ресурсів. Щоб вирішити проблему, розробники вирішили за замовчуванням оптимізувати всі підпроекти (а їх більше тисячі) не по швидкості роботи (/O2), а за розміром коду (/O1). І лише для обраних і найбільш критичних, або для тих, чиї власники не проспали цю ситуацію, включили назад /O2. Наприклад, це зробили для CC і Skia. Ось тільки в 2013 році при рефакторинге в Skia оптимізацію випадково втратили. І ніхто б нічого не помітив, якби ще через два роки не трапився ще один рефакторинг Chromium, в результаті якого частина коду зробили шаблонним і перенесли в header. І ось тут-то все і почалося.

А почалося ось що. Коли відбувається збірка релізної браузера з прапором official, бібліотеки, мають різні цілі для оптимізації (по швидкості, за розміром), опиняються в одній dll. Саме по собі це не ознака чогось поганого. Наприклад, в Visual Studio 2015 ніяких проблем це не викликає. Студія пихкає годину над оптимізацією і видає цілком робочий код. Але варто нам замінити її 2013-й версією, і все ламається. Чому?

Функція SrcATop, яка відповідає за блендінг в Skia, приймає два параметри через регістри xmm0 і xmm1. І майже завжди вона працює коректно. Але як мені вдалося з'ясувати в ході налагодження, варто додати сюди VS 2013 і непросту оптимізацію, і функція вироджується до такого ступеня, що починає повертати у відповідь вміст першого регістра. Звідси і з'являвся незмінний чорний фон замість відео. Всьому виною була неправильна кодогенерация в VS 2013.

Прискорюємо веб-серфінг

При великому бажанні баг можна було «виправити» локально, трохи подкрутив SrcATop. Але мені здалося неправильним, що у такого важливого для відтворення компонента, як Skia, відсутня оптимізація швидкості. Тому я зібрав нову збірку, в якій виставив для Skia оптимізацію швидкості. Баг, звичайно ж, пропав. Здавалося б, можна закривати завдання і йти пити чай, але немає. Мені потрібно було зробити ще дещо.

Команда Яндекс.Браузера бере участь у розробці Chromium вже не перший рік. І це стосується не тільки виправлення помилок. Свого часу колеги допомогли з реалізацією server push для HTTP/2 і зі складальної системою проекту для Windows. Тому і в цей раз я запропонував вирішення проблеми і відправив на розгляд готовий коммит, який після невеликого обговорення був прийнятий.

Розробникам з Chromium, так само як і мені, було цікаво поглянути на зміни в плані продуктивності браузера. Тому вони прогнали цілий комплекс performance-тестів. Практично всі показники для Windows підросли. Частина низькорівневих тестів і зовсім показала поліпшення в 2-3 рази. Інтегральний FPS-тест для ключових сайтів (іншими словами, повсякденний веб-серфінг) виріс на 6,5%. Чуйність на введення покращилася на 20-30%. У проекті Chromium далеко не кожен день трапляється оптимізація подібного рівня.



Враховуючи, що VS 2010 вже давно не використовується, я запропонував спробувати включити оптимізацію швидкості для всього проекту. Тим більше що звичайна release-збірка (без прапора official) завжди оптимізувалася по швидкості цілком, і з тестуванням ніколи проблем не було. Але це вже зовсім інша історія.

P. S. окремо взята Ця проблема торкнулася лише два офісу. Насправді розробка Яндекс.Браузера ведеться не тільки в Москві і Новосибірську. У нас є команди ще й у Санкт-Петербурзі, Єкатеринбурзі, Нижньому Новгороді, Мінську та Києві. І якщо вам було б цікаво до них приєднатися, то заглядайте на yandex.ru/jobs.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.