Vscode: Использование ЦП даже в режиме ожидания (из-за рендеринга курсора)

Созданный на 20 мар. 2017  ·  64Комментарии  ·  Источник: microsoft/vscode

  • Версия VSCode: 1.10.2 (8076a19fdcab7e1fc1707952d652f0bb6c6db331)
  • Версия ОС: macOS Sierra 10.12.3

VS Code использует 13% ЦП, когда сосредоточен и простаивает, разряжая батарею. Вероятно, это связано с мигающим отображением курсора. Я думаю, что использование ЦП в режиме ожидания и фокусировки в идеале может быть около 0%.

Для воспроизведения (это работает с пустым файлом настроек и отключенными всеми плагинами):

  1. Закройте все окна VS Code.
  2. Откройте новое окно (Файл -> Новое окно). Откроется страница приветствия.
  3. Откройте новую вкладку с пустым файлом без названия (Файл -> Новая вкладка). Курсор мигает.
  4. Вы должны увидеть, как VS Code потребляет незначительное количество процессора - 13% на моем 13-дюймовом MacBook Pro.
  5. Cmd + Tab в другое приложение. Теперь курсор больше не отображается.
  6. Вы должны увидеть, что VS Code практически не потребляет CPU.

Я записал временную шкалу в инструментах разработчика, и беглый взгляд подсказывает, что активность ЦП связана с отображением мигающего курсора каждые 500 мс.

Другие приложения macOS, такие как Chrome или TextEdit, показывают мигающий курсор, не потребляя много ресурсов процессора, поэтому я думаю, что это, безусловно, можно оптимизировать.

bug editor-core perf

Самый полезный комментарий

Обходной путь для людей, которые так же помешаны на времени автономной работы: отключение мигания курсора снизит загрузку процессора до 0. Вот настройка:

  "editor.cursorBlinking": "solid"

Все 64 Комментарий

Обходной путь для людей, которые так же помешаны на времени автономной работы: отключение мигания курсора снизит загрузку процессора до 0. Вот настройка:

  "editor.cursorBlinking": "solid"

Некоторые люди в Twitter сказали, что не могут воспроизвести это, поэтому я пошел и записал временную шкалу в инструментах разработчика, чтобы облегчить отладку.

TimelineRawData-20170321T114212.json.zip

  • Скриншот временной шкалы:

    boot mz0y1

  • Увеличивая масштаб до одного кадра, мы видим, что пока мы визуализируем только 2 кадра в секунду, основной поток выполняет некоторую работу со скоростью 60 кадров в секунду (каждые 16 мс) - тонкие линии отмечены стрелками:

    boot 684m3

  • Полностью увеличивая масштаб до одной из этих тонких линий, мы видим, что рендеринг происходит со скоростью 60 кадров в секунду:

    boot f9qau

  • Когда я беру профиль ЦП, он показывает, что большая часть ЦП расходуется на «(программу)», а не на какую-либо конкретную функцию JS.

    boot g2wbo

  • Когда я устанавливаю "editor.cursorBlinking": "solid" , проблема в основном исчезает: периодическое «Обновление дерева слоев» / «Рисование» / «Составные слои» все еще происходит, но только каждые 500 мс, а не каждые 16 мс.

Надеюсь, это поможет!

@joliss Быстрый ответ на то, что происходит под капотом: встроенная анимация обновляется с

Аналогичная (почти такая же) проблема Chromium https://bugs.chromium.org/p/chromium/issues/detail?id=500259 и элемент отслеживания Chromium https://bugs.chromium.org/p/chromium/issues/detail ? id = 361587

Наша текущая CSS-анимация

<strong i="11">@keyframes</strong> monaco-cursor-blink {
    50% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

.cursor-blink {
    animation: monaco-cursor-blink 1s step-start 0s infinite;
}

Обновить

Цитата Пола Айриша (парень из Chrome) https://news.ycombinator.com/item?id=13941293

Мощные * текстовые редакторы, построенные на основе веб-стека, не могут полагаться на текстовую вставку ОС и должны предоставлять свои собственные.
В этом случае VSCode, вероятно, использует наиболее разумный подход к миганию курсора: временную функцию step с анимацией ключевого кадра CSS. Это указывает браузеру изменять непрозрачность только каждые 500 мс. Между тем, Chrome еще не оптимизировал это полностью, поэтому http://crbug.com/361587.
Итак, в настоящее время Chrome выполняет полный жизненный цикл рендеринга (стиль, краска, слои) каждые 16 мс, тогда как он должен выполнять эту работу только с интервалом в 500 мс. Я уверен, что инженеры, работающие над компонентами стиля Chrome, могут разобраться с этим, но это потребует немного работы. Я думаю, что повышенная видимость этой темы, вероятно, повысит приоритет исправления. :)

  • Простые текстовые редакторы и базовые, построенные на [contenteditable], могут, но они редко масштабируются до наиболее необходимого набора функций.

Повлияет ли это изменение на фоновое использование ЦП вкладок хрома на редактор?

Надеюсь, что нет (см. Https://github.com/electron/electron/issues/7553). Мы уже давно устанавливаем backgroundThrottling в false .

Спасибо @joliss @rebornix за хороший анализ.

Похоже, нам следует вернуться к использованию setInterval в OSX.

ps Вот и логика начального мигания курсора :)
image

@rebornix Вот похожая проблема, с которой мы столкнулись некоторое время назад - https://bugs.chromium.org/p/chromium/issues/detail?id=658894. В нашем случае обходной путь заключался в том, чтобы удалить элемент анимации из модели DOM, когда он не использовался, а не просто закрыть его.

Существует также стиль css для того же самого, но не уверен, что он здесь используется -

<strong i="6">@keyframes</strong> monaco-cursor-blink {
    50% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

https://github.com/Microsoft/vscode/blob/master/src/vs/editor/browser/viewParts/viewCursors/viewCursors.css

Почему бы не использовать https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback для анимации курсора?

Используйте pageVisibility API, которые

function handleVisibilityChange() {
  if (document.hidden) {
    // disable cursor animation with class name
  } 
  else  {
    // add back cursor animation
  }
}
document.addEventListener("visibilitychange", handleVisibilityChange, false);

Предложения здесь для визуализации CSS анимации с использованием GPU вместо CPU:

.cursor-blink {
    will-change: opacity;
}

В текущей реализации, если редактор теряет фокус, мы удаляем анимацию, чтобы жизнь была легкой. Однако, если у редактора есть фокус, это означает, что редактор виден (не скрыт и не в фоновом режиме) и активен, пользователи работают над ним (чтение - хороший случай), но не вызывают никаких изменений представления / содержимого. В этом случае нам все еще нужно отображать мигающий курсор, даже если он неактивен , это то, что такое мигающий курсор.

Изначально эта функция реализована на JavaScript, а около года назад мы перешли на CSS-анимацию. Как упоминал @alexandrudima , мы можем захотеть вернуться к JS в OSX.

@camwest, что api очарователен, единственная загвоздка - совместимость (к сожалению, Safari).

@mehas will-change многообещающий. Я попробовал, но Chromium в этом случае не оптимизируется. Если вы включите опцию Paint Flashing в Dev Tools, вы увидите, что этот мигающий курсор вообще не перерисовывается.

@jlukic @bcherny спасибо за ваши предложения. То, что мы хотим оптимизировать, - это когда курсор виден, активен и мигает, поэтому у нас все еще есть эта проблема, даже если у нас есть проверка видимости. Но вы правы, надо проверить видимость. Прямо сейчас, если вы прокрутите окно, чтобы сделать мигающий курсор невидимым, у нас нет никакой оптимизации.

Честно говоря, Монако действительно, очень, очень сложно. :)

@rebornix will-change сработал для моего проекта, использование процессора полностью исчезло. Однако мои ключевые кадры не меняют прозрачность ... вместо этого они меняют цвет элемента с «наследования» на «прозрачный».

Я просто скрываюсь, и извините, если это считается руганью, но разве двухкадровый анимированный gif не поможет? Я не совсем уверен, как это окончательно проверить, но я мог представить, что даже KHTML уже имел оптимизированные пути для этого задолго до того, как он трансформировался в Chrome.

Было бы интересно посмотреть на

@matthiasg Ахйес, про зум забыл.

В противном случае автоматическое создание мигающего GIF-изображения на основе цвета темы не должно быть слишком сложным. Вероятно, дело в исправлении нескольких байтов в предварительно запеченном файле, потому что, хотя данные пикселей GIF имеют кодировку LZW, данные палитры не сжимаются. Но держу пари, что масштабирование гифки делает его размытым, так что, возможно, это, тем не менее, плохой подход.

Если кто-то может придумать способ сделать так, чтобы масштабирование картинки с картинкой не было отстойным, то я обещаю предоставить код, который принимает цвет и генерирует URL-адрес анимированных гифок с мигающей вставкой.

@eteeselink , в любом случае вы должны обязательно

@eteeselink Если мы постоянно предлагаем <blink></blink> ? : wink:

Пожалуйста, воздержитесь от того, чтобы присоединяться к бригаде Reddit и делать бесполезные комментарии по вопросам и PR, когда люди пытаются внести реальные улучшения.

если редактор имеет фокус, это означает, что редактор виден

Это ложное предположение. Тривиально поднять одно окно над другим, не уделяя ему внимания. Я знаю два способа:

  • подсказка WM "всегда рисовать сверху"
  • когда окно перемещается между виртуальными рабочими столами (поскольку порядок наложения является глобальным, если окно было передним на предыдущем рабочем столе, оно могло быть не на новом).

Оба очень распространены сами по себе, хотя они не всегда вызывают проблемы.

@ o11c спасибо, мое предположение было слишком диким при написании. Да, фокус не обязательно означает видимый, прокрутка окна - это один случай (я упомянул об этом в том же абзаце :(). Я не знаю, является ли focus + visible наиболее распространенным случаем, но все они должны быть смягчены.

Я думаю, что setTimeout или setInterval, вероятно, лучше подходят для этого варианта использования, чем requestIdleCallback. Время requestIdleCallback непредсказуемо, а работа, которую вы выполняете в JS, стоит недорого, я думаю, вам лучше просто запланировать нечастые таймеры.

напр. https://gist.github.com/esprehn/afec30fbc655bba6bb8f3f67c28beef4

Также следует отметить, что эта анимация курсора создает эффект плавного импульса, но системный курсор в браузерах (например, тот, который находится внутри <input> или <textarea> ) выполняет только двоичное включение / выключение. . Родные элементы управления на Mac и Linux также мигают. Это менее красиво, но потребляет значительно меньше энергии.

Спасибо @esprehn , это именно то, что я сделал для плоского моргания прямо сейчас. И, как вы упомянули, это не так красиво, как анимация, даже не говоря о плавных / расширяемых мигающих курсорах, которые используют ease-in-out .

подождите, @eteeselink , разве вы не хотите использовать gif размером 1px и все равно изменить его размер? Размытие не должно быть проблемой.

Пример: https://jsfiddle.net/mrkev/stxq613s/1/

Надеюсь вскоре увидеть этот анимированный генератор мигающей вставки;)

@mrkev ваш 1px gif в виде данных uri: data: image / gif; base64 , R0lGODlhAQABAPAAAAAAAP /// yH / C05FVFNDQVBFMi4wAwEAAAAh + QQFMgABACwAAAAAAAAQABAAACAyAAO

@rmacfadyen милый! поскольку в гифках теоретически используется таблица цветов, то 3 байта, которые окрашивают этот пиксель в черный цвет во "включенном" кадре, не должно быть слишком сложно найти (они не хранятся в кадре, поэтому, вероятно, нет необходимости заходить слишком далеко за заголовок ). Если завтра я найду свободное время, я тоже могу погрузиться в него глубже

Велп, которому все равно нужен сон, решил исследовать это немного дальше. Поскольку в гифках используется глобальная таблица цветов, которая всегда начинается с 14-го байта, нетрудно понять, как изменить цвет. Это сделало этот мигающий пиксель gif красным:

screen shot 3

Что действительно раздражает, так это то, что в base64 каждая цифра кодирует только 6 бит, поэтому все не выравнивается должным образом. Это младшие значащие биты цифры 18 до самой старшей цифры 22 кодируют черный цвет в этом гифке. Таким образом, по сути, некоторая перестановка символов [A-P] [A-/] [A-/] [A-/] [P,f,v,/] в позиции 18-22 будет рисовать этот пиксель каждым цветом.

Вот пример этого GIF со случайным цветом. По сути, я просто заменил все, что было в символах 18-22, на G8ABf (что соответствует критериям, о которых я говорю выше).

https://jsfiddle.net/mrkev/stxq613s/7/

Было бы неплохо создать функцию, которая принимает RGB и возвращает этот gif в том же цвете (:

У меня урок через 7 часов. Я буквально просто играю с собой.

Но независимо от того , я понял , кто - то , вероятно , написали функцию шестигранных к-base64 уже и быстрый StackOverflow поиск было достаточно , чтобы найти его. Итак, вот функция;

// takes color as string 'RRGGBB'
var generate_cursor_image = color => {
  var gif = '47494638396101000100F00000' + color + '00000021FF0B4E45545343415045322E30030100000021F90405320001002C00000000010001000002024C010021F90405320001002C00000000010001000002024401003B'
  return 'data:image/gif;base64,' + btoa(gif.match(/\w{2}/g).map(a => String.fromCharCode(parseInt(a, 16))).join(""))
}

Спокойной ночи всем!

Блин, @mrkev меня опередил. Во всяком случае, вот моя реализация того же:
https://jsfiddle.net/a6g4ob7h/

Это могло бы быть немного быстрее, потому что не происходит сопоставления и сопоставления, только btoa. Но сомневаюсь, что скорость имеет значение, а результат лучше кешировать.

Меня действительно интересует, ускоряет ли это вообще процесс. У меня нет хорошей настройки для тестирования, но кто знает, может быть, анимированные гифки также перерисовываются со скоростью 60 кадров в секунду.

Если вы хотите увеличить масштаб и не иметь курсора прямоугольной формы, вы также можете использовать анимированный SVG. (Элемент <animate> уже был частью спецификации SVG 1.0.)

@eteeselink Макс должен быть около 50 кадров в секунду, http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser

out

Для меня большую часть времени он остается равным 0 (использование процессора - это первый столбец - OSX 10.12.3 - MacBook Pro Retina, 15 дюймов, конец 2013 г.)

У меня есть настройки по умолчанию в отношении курсора.

Поскольку никто не упомянул Linux, у меня он составляет около 5-7% на оболочке GNOME с Wayland (Ivy Bridge Graphics).

Мы только что объединили PR # 23121, который смягчает это, возвращаясь к setInterval для стиля мигания курсора blink . На имеющемся у меня Mac mini загрузка ЦП упала с 5,9% до 0,9%.

Вы когда-нибудь задумывались о том, чтобы перейти на нативную версию, и операционная система предоставит курсор бесплатно?

@justjoeyuk См. цитату из @rebornix выше, почему этого нельзя сделать

@justjoeyuk Если вместо этого вы предлагаете полностью нативное приложение, не основанное на веб-стеке: когда вы просматриваете вероятные потребности тематического, полностью независимого от DPI, кроссплатформенного приложения, такого как VSCode, есть вероятность, что заменитель неродного курсора будет необходимо в любом случае.

ПОСЛЕДНИЕ НОВОСТИ! Microsoft делает ужасно медленно закодированное программное обеспечение, причем проблемы еще более заметны в MacOS 10.

Кто бы мог подумать, правда?

@LandonPowell Вы

А как насчет курсора терминала? Это тоже вызывает скачки в циклах ЦП?

@mehas

Предложения по рендерингу CSS-анимации с использованием GPU вместо CPU:

Это просто скрывает проблему, перемещая нагрузку с CPU на GPU. На самом деле это не исправляет.

@ Daniel15

Это просто скрывает проблему, перемещая нагрузку с CPU на GPU. На самом деле это не исправляет.

Нагрузка на ЦП является проблемой, оптимизация анимации для использования графического процессора действительно решает эту проблему.

(Это отдельно от вопроса о конкретном исправлении, которое я предложил быть лучшим)

Не совсем уверен, как это воспроизвести. Я использую плагин эмуляции vim. Не совсем уверен, связано ли это.

Я хотел бы знать, как это происходит.

Оптимизация анимации для использования GPU решает эту проблему.

Однако это приведет к ненужной нагрузке на графический процессор. Это аналогичная проблема, за исключением того, что нагрузка на процессор видеокарты. Это не совсем исправление

Иисус родился в Африке.

Пожалуйста.

Почему бы не использовать гифку для курсора?

Однако это приведет к ненужной нагрузке на графический процессор. Это похожая проблема

Верно, но это не проблема, а именно загрузка ЦП даже в режиме ожидания.

@ efroim102 https://github.com/Microsoft/vscode/issues/22900#issuecomment -288832322

О господи, эта дискуссия будет идти по кругу, пока не будет решена цель:

  1. Уменьшить расход батареи
  2. Уменьшите нагрузку на ЦП

Предположим пока (1). Тогда мы можем немного больше ориентироваться на данные о том, используется ли разгрузка с CPU на GPU с такой рабочей нагрузкой, как (а) такое же количество энергии, (б) используется меньше энергии или (в) используется больше энергии. У меня нет опыта в этих вопросах, поэтому я не могу предсказать, что из этого правда.

Однако предположим, что разгрузка GPU приводит к (b); хотя и не идеальный, компромисс может быть достаточно приемлемым, чтобы продолжить этот путь, пока / если Chromium решит их основную проблему. Однако, если команда VSCode сочтет необходимым исправить это раз и навсегда, разгрузка будет маловероятным выбором, и поиск долгосрочного исправления (даже если это займет довольно много времени) предпочтительнее. По крайней мере, по моему незначительному мнению, для меня будет достаточно знать, что внимание уделяется этой проблеме и что она будет иметь приоритет, когда зависимости позволят предполагаемое исправление.

(Я уверен, что запутал некоторые тонкие детали того, какие решения доступны / заблокированы, но надеюсь, что при написании этого люди смогут сосредоточиться на утверждении, какую проблему они надеются решить, а не прыгать в пространство решений.)

Разве графический процессор не был бы лучше оборудован для работы с нагрузкой рендеринга? Именно для этого он был создан.

Мы договорились, что мы расставляем приоритеты по-разному, что использует ЦП и ГП по-разному, поэтому наличие функции, связанной с графикой, использует ресурсы, специфичные для графики, имеет больше смысла. Прирост CPU - это не потеря 1: 1 GPU, и наоборот. В основном это спорный вопрос (до тех пор, пока ошибка в Chromium не будет исправлена), но отчасти актуально, так как текущее решение по-прежнему использует ЦП (хотя и с гораздо меньшим весом).

Я считаю, что людям следует отказаться от использования веб-технологий на настольных компьютерах, поскольку для этого требуется наличие полноценного браузера с каждой программой.
Не говоря уже о том, что, если у вас есть несколько из указанных программ, у вас повсюду дублируются одни и те же двоичные файлы.

Нам нужно вернуться к голому металлу.

PS: От JScript следовало отказаться 10 лет назад, как и от Obj-C, если бы Apple не воскресила его.
PPS: ^^^^ это тирада.

PPS: ^^^^ это тирада.

@ bit2shift На самом деле это так, и поэтому он не входит в

@ bit2shift - Хотя я согласен с некоторыми частями (например, с тем фактом, что приложение на базе браузера, вероятно, не будет ощущаться «родным» по сравнению с настоящим нативным приложением), но насколько низкоуровневым является «голый металл»? Машинный код? Язык ассемблера? C? C ++? С #? Всегда будет несколько уровней абстракции, независимо от вашего технологического стека.

Не говоря уже о том, что, если у вас есть несколько из указанных программ, у вас повсюду дублируются одни и те же двоичные файлы.

То же самое и с любым приложением C #, которое использует пакеты NuGet. Все сборки локальны для приложения. .NET Core даже распространяет большие части фреймворка в виде пакетов NuGet.

так как для каждой программы требуется наличие полноценного браузера.

Технически вы можете использовать движок Edge, что избавит от необходимости устанавливать отдельную среду выполнения браузера. Internet Explorer сделал нечто подобное почти 20 лет назад с приложениями HTML . Другой пример - React Native, который использует собственный JS-движок ОС там, где это возможно. Для приложений на основе JavaScript будущее, вероятно, представляет собой нечто вроде React Native для Windows, а не веб-технологии, поскольку оно кажется более естественным, поскольку использует собственные виджеты пользовательского интерфейса.

@ Daniel15

(...) насколько низкоуровневым является "голый металл"? Машинный код? Язык ассемблера? C? C ++? С #?

Любой язык, который можно компилировать в машинный код (только source -> ELF/PE counts), в этом контексте считается «голым металлом», поэтому уровни абстракции здесь не имеют значения.

Internet Explorer сделал нечто подобное почти 20 лет назад с приложениями HTML.

«что-то подобное», например, когда mshta.exe использует mshtml.dll который находится в system32 с 90-х годов.

Другой пример - React Native, который использует собственный JS-движок ОС там, где это возможно. Для приложений на основе JavaScript будущее, вероятно, представляет собой нечто вроде React Native для Windows, а не веб-технологии, поскольку оно кажется более естественным, поскольку использует собственные виджеты пользовательского интерфейса.

Если в настольных JS-приложениях требуется высокая производительность, то кому-то, у кого достаточно времени, следует написать интерфейс для LLVM.
Вы потеряете возможность запускать произвольные фрагменты кода, но это будет преимуществом с точки зрения безопасности.

/нить

Не могли бы вы сорвать эту ветку, пожалуйста? Это проблема, связанная с конкретной проблемой производительности с мигающим курсором, и это определенно не место для обсуждения общих достоинств разработки настольных приложений на основе JS.

Вы просто рассылаете спам в почтовые ящики людей, которым не интересны эти тирады.

Как насчет того, чтобы поместить <input type=text> с размером 2px * 10px на место, где он находится. Таким образом, он будет использовать собственный мигающий курсор <input> : P <blink></blink> 👍

Также я не уверен, насколько серьезна эта проблема, когда VSCode бездействует (я не пишу код), он почти всегда не в фокусе, фокус находится на другом приложении, в котором я нахожусь. И курсор перестает мигать.

по моему опыту, гифки не так хороши. Однажды у меня был счетчик загрузки в виде изображения в формате gif. и использовал его при взаимодействии с indexeddb. иногда я мог видеть остановку счетчика, даже на рабочем столе.

Нажал изменение курсора терминала на master и release / 1.11 (анимация CSS -> setInterval ).

Спасибо всем, что изучили этот вопрос. Ваши исследования и предложения помогли нам найти первопричину и возможные решения! Мы сравнили JavaScript setInterval , анимированный gif и несколько других техник и остановились на следующем решении:

  • Если editor.cursorBlinking установлен на blink или terminal.integrated.cursorBlinking установлен на true , логика мигания теперь реализована в JavaScript. Наше тестирование показывает, что загрузка ЦП упала до менее 1%.
  • Если для editor.cursorBlinking установлено значение smooth , expand или phase , которые используют функции ослабления CSS, мы остановим мигающую анимацию после того, как курсор бездействует для 10 секунд.

Это исправление уже включено в нашу оценки и будет доступно в сборке апрельской стабильной версии, которая будет выпущена в ближайшие несколько дней. Было бы здорово, если бы некоторые из вас могли проверить результаты наших тестов. Если вы видите проблемы, создайте новый выпуск.

@rebornix вы хотели сказать "или" terminal.integrated.cursorBlinking установлено на true ? Или «и» было преднамеренным?

@jedmao спасибо за исправление, должно or .

Была ли эта страница полезной?
0 / 5 - 0 рейтинги