В этом посте автор Chromium Ахмед Эльвасефи рассказывает, как он стал участником Google Summer of Code, а также о проблемах с доступностью, которые он выявил и исправил.
Когда я приближался к последнему году обучения в области компьютерной инженерии в Немецком университете в Каире, я решил изучить возможности внести свой вклад в открытый исходный код. Я начал изучать список проблем Chromium, удобных для новичков, и обнаружил, что меня особенно привлекает доступность. Поиски руководства привели меня к Аарону Левенталю, чей опыт и готовность помочь вдохновили меня объединиться с ним для реализации проекта. Это сотрудничество стало моим опытом Google Summer of Code , где меня приняли на работу в группу по обеспечению специальных возможностей Chromium.
После успешного завершения Google Summer of Code я продолжил решать нерешенную проблему с прокруткой, вызванную желанием улучшить производительность. Благодаря двум грантам программы Google OpenCollective я смог продолжить работу над этим проектом, а также взял на себя дополнительные задачи, направленные на оптимизацию кода для повышения производительности.
В этом сообщении блога рассказывается о моем опыте работы с Chromium за последние полтора года и подробно описываются технические улучшения, которые мы сделали, особенно в области производительности.
Как код доступности влияет на производительность в Chrome
Код доступности Chrome помогает вспомогательным технологиям, таким как программы чтения с экрана, получать доступ к Интернету. Однако если он включен, это может повлиять на время загрузки, производительность и срок службы батареи. Поэтому, если он не нужен, этот код остается неактивным, чтобы избежать снижения производительности. Примерно у 5–10% пользователей включен код доступа, часто из-за таких инструментов, как менеджеры паролей и антивирусное программное обеспечение, которые используют API специальных возможностей платформы. Эти инструменты используют эти API для взаимодействия и изменения содержимого страницы, например для поиска полей паролей для менеджеров паролей и заполнителей форм.
Общий уровень ухудшения основных показателей пока неизвестен, но недавний эксперимент под названием Auto Disable Accessibility (отключение специальных возможностей, когда он не используется) показывает, что он довольно высок. Проблема возникает из-за огромных объемов вычислений и взаимодействия в двух основных областях кодовой базы специальных возможностей Chrome: средстве рендеринга и браузере. Средство визуализации собирает информацию о веб-содержимом и изменениях в нем, вычисляя свойства доступности для дерева узлов. Любые «грязные» узлы затем сериализуются и отправляются по каналу в основной поток пользовательского интерфейса процесса браузера. Этот поток получает и десериализует эту информацию в идентичное дерево узлов, а затем, наконец, преобразует ее в форму, подходящую для сторонних вспомогательных технологий, таких как программы чтения с экрана.
Улучшения доступности Chromium
Следующие проекты были завершены во время Summer of Code, а затем и при финансовой поддержке программы Google OpenCollective.
Улучшение кэша
В Chrome существует специальная структура данных, называемая деревом доступности , которая отражает дерево DOM. Он используется, чтобы помочь вспомогательным технологиям получить доступ к веб-контенту. Иногда, когда устройству нужна информация из этого дерева, оно может быть не готово, поэтому браузеру приходится планировать эти запросы на потом.
Раньше это планирование осуществлялось с помощью метода замыканий, который включал помещение обратных вызовов в очередь. Этот подход добавил дополнительную работу из-за того, как обрабатываются замыкания.
Чтобы улучшить это, мы перешли на систему, использующую перечисления. Каждой задаче присваивается определенное значение перечисления, и как только дерево доступности будет готово, вызывается правильный метод для этой задачи. Это изменение облегчило понимание кода и повысило производительность более чем на 20% .
Поиск и устранение проблем с производительностью прокрутки
Далее я исследовал, как улучшается производительность, когда мы отключаем сериализацию ограничительной рамки. Ограничивающие рамки — это позиции и размеры элементов на веб-странице, включая такие детали, как ширина, высота и их положение относительно родительского элемента.
Чтобы проверить это, мы временно удалили код, обрабатывающий ограничивающие рамки, и запустили тесты производительности, чтобы увидеть влияние. Один из тестов, focus-links.html, показал огромное улучшение примерно на 1618%. Это открытие стало основой для дальнейших работ.
Исследование медленного теста
Я начал исследовать, почему этот конкретный тест был медленным с ограничивающими рамками. Все, что делал тест, — это фокусировался на нескольких ссылках одна за другой. Следовательно, основной проблемой должна быть либо фокусировка на элементах, либо прокрутка, происходящая с действием фокуса. Чтобы проверить это, я добавил {preventScroll: true}
к вызову focus()
в тесте производительности, остановив прокрутку.
При отключенной прокрутке время теста сократилось до 1,2 миллисекунды, когда были активны вычисления ограничивающей рамки. Это показало, что настоящей проблемой является прокрутка.
Я создал новый тест под названием «scroll-in-page.html», чтобы повторить тест focus-links , но вместо использования фокуса он прокручивает элементы с помощью scrollIntoView()
. Я тестировал как плавную, так и мгновенную прокрутку, с расчетами ограничивающей рамки и без нее.
Результаты показали, что с мгновенной прокруткой и ограничивающими рамками процесс занял около 66 мс. Плавная прокрутка была еще медленнее — около 124 мс. Когда мы отключили ограничивающие рамки, это заняло совсем немного времени, поскольку никакие события не вызывались.
Мы знали об этом случае, но почему это произошло?
Теперь мы узнали, что прокрутка является источником значительной медлительности сериализации специальных возможностей, но нам еще предстояло выяснить, почему. Чтобы проанализировать это, были использованы два инструмента, называемые perf и pprof, для разделения работы, выполняемой в процессе браузера. Эти инструменты часто используются в C++ для профилирования. На следующих графиках показан фрагмент интересной части.
Проведя расследование, мы обнаружили, что проблема заключалась не в самом коде десериализации, а в частоте его вызовов. Чтобы понять это, нам нужно посмотреть, как обновления специальных возможностей работают в Chromium. Обновления не отправляются индивидуально; вместо этого существует центральное расположение под названием AXObjectCache
, в котором хранятся все свойства. При изменении узла различные методы уведомляют кэш о необходимости пометить этот узел как «грязный» для последующей сериализации. Затем все свойства грязных заметок, включая неизмененные, сериализуются и отправляются в браузер. Хотя такая конструкция упрощает код и снижает сложность за счет единого пути обновления, она становится медленной при быстрых событиях «отметки как грязные», например при прокрутке. Единственное, что меняется, — это значения scrollX
и scrollY
; тем не менее, мы каждый раз сериализуем с ними остальные свойства. Скорость обновлений здесь достигала более двадцати раз в секунду!
Сериализация ограничивающей рамки решает эту проблему, используя более быстрый путь сериализации, который отправляет только сведения об ограничивающей рамке, что позволяет быстро обновлять, не затрагивая другие свойства. Этот метод эффективно обрабатывает изменения ограничивающей рамки.
Исправление прокрутки
Решение было очевидным: включить текущие смещения прокрутки с сериализацией ограничивающей рамки. Это гарантирует, что обновления прокрутки будут обрабатываться по быстрому пути, повышая производительность без ненужных задержек. Упаковывая смещения прокрутки в данные ограничительной рамки, мы оптимизируем процесс для более плавных и эффективных обновлений, создавая менее утомительный опыт для пользователей с включенными специальными возможностями. Улучшение после внедрения фикса составляет до 825% в тестах прокрутки.
Упрощение кода
В этот период я сосредоточился на качестве кода в рамках проекта под названием Onion Soup, который упрощает код за счет сокращения или удаления ненужного распределения кода по слоям.
Первый проект был направлен на оптимизацию способа сериализации данных о доступности от средства рендеринга в браузер. Раньше данные должны были пройти через дополнительный уровень, прежде чем достичь места назначения, что добавляло ненужную сложность. Мы упростили этот процесс, разрешив отправку данных напрямую, исключив посредников.
Кроме того, мы выявили и удалили некоторые устаревшие события, которые вызывали ненужную работу в системе, например событие, которое срабатывало при завершении макета. Мы заменили их более эффективным решением.
Были сделаны и другие небольшие улучшения. К сожалению, улучшения производительности для них не было зафиксировано, но мы с гордостью сообщаем, что код стал намного более понятным и самодокументируемым, чем был раньше. Это во многом помогает подготовить почву для будущих улучшений производительности. Вы можете проверить фактические изменения в моем профиле Gerrit .
Заключение
Работа с командой по обеспечению специальных возможностей Chromium оказалась полезным путешествием. Решая различные задачи, от оптимизации производительности прокрутки до упрощения кодовой базы, я получил более глубокое понимание разработки в таком крупномасштабном проекте, а также изучил важные инструменты для профилирования. Кроме того, я понял, насколько важна доступность для создания сети, доступной для всех. Внесенные нами улучшения не только улучшают взаимодействие с пользователем для тех, кто использует вспомогательные технологии, но также способствуют повышению общей производительности и эффективности браузера.
Результаты производительности были впечатляющими. Например, переход на использование перечислений для планирования задач повысил производительность более чем на 20% . Кроме того, наше исправление прокрутки привело к сокращению количества тестов прокрутки на 825% . Изменения, направленные на упрощение кода, не только сделали его более понятным и удобным в сопровождении, но и открыли путь для будущих улучшений.
Я хотел бы выразить благодарность Стефану Загеру, Крису Харрельсону и Мэйсону Фриду за их поддержку и руководство на протяжении всего года, и особенно Аарону Левенталю, без которого эта возможность была бы невозможна. Я также хотел бы поблагодарить Таба Аткинса-Биттнера и команду GSoC за поддержку.
Тем, кто хочет внести свой вклад в значимый проект и развить свои навыки, я настоятельно рекомендую заняться Chromium. Это отличный способ учиться, а такие программы, как Google Summer of Code, станут отличной отправной точкой для вашего путешествия.