Vscode: Uso de CPU incluso cuando está inactivo (debido a la representación del cursor)

Creado en 20 mar. 2017  ·  64Comentarios  ·  Fuente: microsoft/vscode

  • Versión de VSCode: 1.10.2 (8076a19fdcab7e1fc1707952d652f0bb6c6db331)
  • Versión del sistema operativo: macOS Sierra 10.12.3

VS Code usa un 13% de CPU cuando está enfocado e inactivo, lo que agota la batería. Es probable que esto se deba a que el cursor parpadea. Creo que el uso de la CPU cuando está enfocado e inactivo podría ser idealmente cercano al 0%.

Para reproducir (esto funciona con un archivo de configuración vacío y todos los complementos deshabilitados):

  1. Cierre todas las ventanas de VS Code.
  2. Abra una nueva ventana (Archivo -> Nueva ventana). Mostrará la página de bienvenida.
  3. Abra una nueva pestaña con un archivo vacío sin título (Archivo -> Nueva pestaña). El cursor parpadea.
  4. Debería ver que VS Code consume una cantidad no despreciable de CPU: 13% en mi MacBook Pro de 13 ".
  5. Cmd + Tab en alguna otra aplicación. Ahora el cursor ya no está visible.
  6. Debería ver que VS Code prácticamente no consume CPU.

Grabé una línea de tiempo en las herramientas de desarrollo, y una mirada superficial sugiere que la actividad de la CPU proviene de renderizar el cursor parpadeante cada 500 ms.

Otras aplicaciones de macOS como Chrome o TextEdit muestran un cursor parpadeante sin consumir mucha CPU, por lo que creo que esto seguramente podría optimizarse.

bug editor-core perf

Comentario más útil

Una solución para las personas que están igualmente obsesionadas con la duración de la batería: deshabilitar el parpadeo del cursor hará que el uso de la CPU caiga a 0. Aquí está la configuración:

  "editor.cursorBlinking": "solid"

Todos 64 comentarios

Una solución para las personas que están igualmente obsesionadas con la duración de la batería: deshabilitar el parpadeo del cursor hará que el uso de la CPU caiga a 0. Aquí está la configuración:

  "editor.cursorBlinking": "solid"

Algunas personas en Twitter dijeron que no podían reproducir esto, así que fui y grabé una línea de tiempo en las Herramientas para desarrolladores para ayudar a depurar.

TimelineRawData-20170321T114212.json.zip

  • Captura de pantalla de la línea de tiempo:

    boot mz0y1

  • Al hacer zoom en un solo cuadro, vemos que mientras renderizamos solo 2 fps, el hilo principal está realizando un trabajo a 60 fps (cada 16 ms), las líneas delgadas marcadas con flechas:

    boot 684m3

  • Haciendo zoom hasta el final en una de esas delgadas líneas, vemos que algo de renderizado ocurre a 60 fps:

    boot f9qau

  • Cuando tomo un perfil de CPU, muestra que la mayor parte de la CPU se gasta en "(programa)", no en una función JS específica.

    boot g2wbo

  • Cuando configuro "editor.cursorBlinking": "solid" , el problema en su mayoría desaparece: un "Árbol de capa de actualización" / "Pintura" / "Capas compuestas" periódico todavía está sucediendo, pero solo cada 500ms, no cada 16ms.

¡Espero que esto ayude!

@joliss Respuesta rápida a lo que está sucediendo bajo el capó: una animación nativa se actualiza a 60 hz en Chromium.

Problema de Chromium similar (casi el mismo) https://bugs.chromium.org/p/chromium/issues/detail?id=500259 y elemento de seguimiento de Chromium https://bugs.chromium.org/p/chromium/issues/detail ? id = 361587

Nuestra animación CSS actual

<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;
}

Actualizar

Citando a Paul Irish (chico de Chrome) https://news.ycombinator.com/item?id=13941293

Los editores de texto potentes * construidos en la pila web no pueden depender del símbolo de intercalación de texto del sistema operativo y deben proporcionar el suyo propio.
En este caso, VSCode probablemente esté utilizando el enfoque más razonable para hacer parpadear un cursor: una función de tiempo step con una animación de fotogramas clave CSS. Esto le dice al navegador que solo cambie la opacidad cada 500 ms. Mientras tanto, Chrome aún no lo ha optimizado por completo, de ahí http://crbug.com/361587.
Entonces, actualmente, Chrome está haciendo el ciclo de vida de renderizado completo (estilo, pintura, capas) cada 16 ms cuando solo debería estar haciendo ese trabajo en un intervalo de 500 ms. Estoy seguro de que los ingenieros que trabajan en los componentes de estilo de Chrome pueden resolver esto, pero tomará un poco de trabajo. Creo que la visibilidad adicional sobre este tema probablemente aumentará la prioridad de la solución. :)

  • Los editores de texto simples y los básicos basados ​​en [contenteditable] pueden, pero rara vez se adaptan al conjunto de funciones que más desean.

¿ Este cambio sobre el uso de CPU en segundo plano de las pestañas de cromo afectará al editor?

Ojalá no (consulte https://github.com/electron/electron/issues/7553). Establecemos backgroundThrottling en false desde hace un tiempo.

Gracias @joliss @rebornix por el buen análisis.

Parece que deberíamos volver a usar setInterval en OSX.

ps Aquí está la lógica inicial de parpadeo del cursor :)
image

@rebornix Aquí hay un problema similar con el que nos encontramos hace un tiempo: https://bugs.chromium.org/p/chromium/issues/detail?id=658894. La solución en nuestro caso fue eliminar el elemento de animación del DOM cuando no se usó, en lugar de simplemente ocluirlo.

También hay un estilo CSS para el mismo, aunque no estoy seguro si se usa aquí -

<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

¿Por qué no utilizar https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback para la animación del cursor?

Utilice las API de

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

Sugerencias aquí para renderizar la animación CSS usando la GPU en lugar de la CPU:

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

En la implementación actual, si el editor pierde el foco, eliminaremos la animación para que la vida sea más fácil. Sin embargo, si el editor tiene el foco, significa que el editor está visible (no está oculto ni en segundo plano) y está activo, los usuarios están trabajando en él (la lectura es un buen caso) pero no activa ningún cambio de vista / contenido. En este caso, aún necesitamos mostrar el cursor parpadeante aunque esté un poco inactivo , eso es lo que es un cursor parpadeante.

Inicialmente, esta función se implementó en JavaScript y hace aproximadamente un año, cambiamos a la animación CSS. Como mencionó @alexandrudima , es posible que deseemos volver a JS en OSX.

@camwest que api es encantador, el único

@mehas will-change es prometedor. Lo intenté, pero Chromium no se optimiza en este caso. Si activa la opción Paint Flashing en Dev Tools, puede ver que este cursor parpadeante no se está repintando en absoluto.

@jlukic @bcherny gracias por tus sugerencias. Lo que queremos optimizar es cuando el cursor está visible, activo y parpadeando, por lo que todavía tenemos este problema a pesar de que tenemos control de visibilidad. Pero tienes razón, deberíamos comprobar la visibilidad. En este momento, si desplaza la ventana para hacer invisible el cursor parpadeante, no tenemos ninguna optimización.

Para ser justos, Mónaco es muy, muy, muy complejo. :)

@rebornix will-change funcionó para mi proyecto, el uso de la CPU desapareció por completo. Sin embargo, mis fotogramas clave no cambian la opacidad ... en su lugar, cambian el color del elemento de 'heredar' a 'transparente'.

Solo soy un merodeador, y lo siento si esto se considera una palabrota, pero ¿no sería suficiente un gif animado de dos cuadros? No estoy del todo seguro de cómo probar esto de manera concluyente, pero podría imaginar que incluso KHTML ya tenía rutas optimizadas para eso, mucho antes de que se transgromorfizara en Chrome.

Sería interesante ver @eteeselink , pero el color del cursor debe cambiar y hacer zoom, etc. podría no ser trivial, mientras tanto, volver a js podría ser más fácil.

@matthiasg Ahyes, me olvidé del zoom.

De lo contrario, la generación automática de un GIF parpadeante según el color del tema no debería ser demasiado difícil. Probablemente se trate de parchear algunos bytes en un archivo prefabricado porque, si bien los datos de píxeles GIF están codificados en LZW, los datos de la paleta no están comprimidos. Pero apuesto a que hacer zoom en un gif así lo hace borroso, así que tal vez este sea un mal enfoque de todos modos.

Si alguien puede encontrar una forma de hacer que el zoom de un símbolo de intercalación de un gif no sea una mierda, entonces prometo contribuir con un código que tome un color y produzca una URL de datos de gif animados de intermitente intermitente.

@eteeselink , de todos modos, deberías

@eteeselink Si estamos sugiriendo soluciones fuera de lo <blink></blink> ? :guiño:

Absténgase de unirse a la brigada de Reddit para hacer comentarios inútiles sobre problemas y relaciones públicas en los que la gente está tratando de hacer mejoras reales.

si el editor tiene el foco, significa que el editor está visible

Esta es una suposición falsa. Es trivial levantar una ventana sobre otra sin enfocarla. Dos formas que conozco:

  • la sugerencia de WM "dibujar siempre en la parte superior"
  • cuando una ventana se mueve entre escritorios virtuales (dado que el orden de apilamiento es global, si una ventana estaba en primer lugar en el escritorio anterior, es posible que no esté en el nuevo).

Ambos son muy comunes por sí solos, aunque no siempre causan problemas necesariamente.

@ o11c gracias, mi suposición fue demasiado descabellada al escribir. Sí, el foco no significa necesariamente visible, desplazarse por la ventana es un caso (mencioné esto en el mismo párrafo :(). No sé si foco + visible es el caso más común, pero todos deben mitigarse.

Creo que setTimeout o setInterval probablemente se ajusten mejor a este caso de uso que requestIdleCallback. El tiempo de requestIdleCallback no es predecible, y el trabajo que estás haciendo en JS es económico, creo que sería mejor programar temporizadores poco frecuentes.

ex. https://gist.github.com/esprehn/afec30fbc655bba6bb8f3f67c28beef4

También es de destacar que esta animación de intercalación tiene un efecto de pulso suave, pero el cursor del sistema en los navegadores (por ejemplo, el que está dentro de un <input> o <textarea> ) solo está haciendo un encendido / apagado binario . Los controles nativos en Mac y Linux también parpadean. Es menos bonito, pero consumiría considerablemente menos energía.

Gracias @esprehn , eso es exactamente lo que hice para el parpadeo plano en este momento. Y como mencionaste, no es tan bonito como la animación, ni siquiera para decir cursores parpadeantes suaves / expandidos que usan ease-in-out .

espera @eteeselink , ¿no querrías usar un gif de 1px y cambiar su tamaño de todos modos? El desenfoque no debería ser un problema.

Ejemplo: https://jsfiddle.net/mrkev/stxq613s/1/

Con la esperanza de ver pronto ese generador de intermitentes animados;)

@mrkev tu gif de 1px como datos uri: data: image / gif; base64 , R0lGODlhAQABAPAAAAAAAP /// yH / C05FVFNDQVBFMi4wAwEAAAAh + QQFMgABACwAAAAAAAAAQABAAACAkwAABOABALBA

@rmacfadyen dulce! dado que los gifs usan una tabla de colores, en teoría, los 3 bytes que colorean ese píxel de negro en el marco "activado" no deberían ser demasiado difíciles de encontrar (no se almacenan en el marco, por lo que probablemente no sea necesario ir demasiado lejos del encabezado ). Si encuentro algo de tiempo libre mañana, también puedo sumergirme más en él.

Welp, que necesita dormir de todos modos, decidió explorar esto un poco más. Dado que los gifs utilizan una tabla de colores global que siempre comienza en el byte 14, no fue difícil averiguar cómo cambiar el color. Esto hizo que este gif de píxeles parpadeantes se volviera rojo:

screen shot 3

Ahora, lo que es realmente molesto es que en base64 cada dígito codifica solo 6 bits, por lo que las cosas no se alinean correctamente. Son los bits menos significativos del dígito 18 hasta el más significativo del dígito 22 que codifican el color negro en ese gif. Entonces, esencialmente, alguna permutación de caracteres [A-P] [A-/] [A-/] [A-/] [P,f,v,/] en la posición 18-22 dibujará ese píxel en todos los colores.

Aquí hay un ejemplo de ese GIF en un color aleatorio. Básicamente, reemplacé lo que estaba en los caracteres 18-22 con G8ABf (que se ajusta a los criterios de los que hablo anteriormente).

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

No debería ser tan malo crear una función que tome RGB y devuelva este gif en ese color (:

Tengo clase en 7 horas, literalmente estoy jugando a mí mismo.

Pero sea lo que sea, me di cuenta de que probablemente alguien ya había escrito una función de hexadecimal a base64 y una búsqueda rápida de stackoverflow fue suficiente para encontrarla. Así que aquí está la función;

// 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(""))
}

¡Buenas noches a todos!

Maldita sea, @mrkev se me adelantó. De todos modos, aquí está mi implementación de lo mismo:
https://jsfiddle.net/a6g4ob7h/

Puede ser un poco más rápido porque no hay coincidencias ni asignaciones, solo un btoa. Pero dudo que la velocidad importe, y es mejor almacenar en caché el resultado.

Lo que realmente me pregunto es si esto acelera las cosas. No tengo una buena configuración para probar, pero quién sabe, tal vez los gifs animados también se vuelvan a reproducir a 60 fps.

Si desea hacer zoom y no tener un cursor de forma rectangular, también puede usar SVG animado. (El elemento <animate> ya formaba parte de la especificación SVG 1.0).

out

Para mí, permanece en 0 la mayor parte del tiempo (el uso de la CPU es la primera columna - OSX 10.12.3 - MacBook Pro Retina, 15 pulgadas, finales de 2013)

Tengo la configuración predeterminada con respecto al cursor.

Como nadie mencionó Linux, lo tengo alrededor del 5-7% en GNOME Shell con Wayland (Ivy Bridge Graphics).

Acabamos de fusionar PR # 23121 que mitiga esto volviendo a setInterval para el estilo de parpadeo del cursor blink . En el mac mini que tengo a mi disposición, el uso de la CPU cae del 5,9% al 0,9%

¿Alguna vez ha considerado convertirse en nativo y que el sistema operativo proporcione el cursor de forma gratuita?

@justjoeyuk Vea la cita de @rebornix arriba, sobre por qué esto no se puede hacer

@justjoeyuk Si, en cambio, está sugiriendo una aplicación totalmente nativa, no basada en la pila web: cuando atraviesa las probables necesidades de una aplicación multiplataforma, totalmente independiente de DPI y con un tema muy temático como VSCode, lo más probable es que un sustituto de cursor no nativo sea necesario independientemente.

¡NOTICIAS DE ÚLTIMA HORA! Microsoft hace un software lento codificado horriblemente, y los problemas son aún más prominentes en MacOS 10.

¿Quién lo hubiera adivinado, verdad?

@LandonPowell Estás contaminando la discusión real sobre un tema; la brigada de reddit / hackernews aquí es ridícula.

¿Qué pasa con el cursor del terminal? ¿Eso también está causando picos en los ciclos de la CPU?

@mehas

Sugerencias aquí para renderizar la animación CSS usando la GPU en lugar de la CPU:

Eso solo oculta el problema al mover la carga de la CPU a la GPU. En realidad, no lo arregla.

@ Daniel15

Eso solo oculta el problema al mover la carga de la CPU a la GPU. En realidad, no lo arregla.

La carga en la CPU es el problema, optimizar la animación para usar la GPU soluciona este problema.

(Eso está separado de la cuestión de la solución específica que sugerí que es la mejor)

No estoy seguro de cómo reproducirlo. Estoy usando el complemento de emulación vim. No estoy seguro de si está relacionado.

Me gustaría saber cómo va esto.

optimizar la animación para usar la GPU soluciona este problema.

Sin embargo, resultará en una carga GPU innecesaria. Ese es un problema similar, excepto que la carga está en el procesador de la tarjeta gráfica. No es realmente una solución 😛

Jesús nació en África.

De nada.

¿Por qué no usar un gif para el cursor?

Sin embargo, resultará en una carga GPU innecesaria. Eso es un problema similar

Correcto, pero no es este problema, que es el uso de la CPU incluso cuando está inactivo.

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

Oh queridos dioses, este debate irá en círculos hasta que se decida cuál es el objetivo:

  1. Reducir el consumo de batería
  2. Reducir la contención de la CPU

Suponga (1) por el momento. Entonces podemos estar un poco más impulsados ​​por los datos sobre si la descarga de la CPU a la GPU con una carga de trabajo como esta (a) usa la misma cantidad de energía, (b) usa menos energía o (c) usa más energía. No tengo experiencia en estos asuntos, así que no puedo predecir cuál es la verdad.

Sin embargo, supongamos que la descarga de GPU conduce a (b); Si bien no es perfecto, la compensación puede ser lo suficientemente aceptable como para seguir este camino mientras Chromium aborda su problema subyacente. Sin embargo, si el equipo de VSCode considera necesario solucionar este problema de una vez por todas, la descarga será una elección poco probable y es preferible buscar la solución a largo plazo (incluso si lleva bastante tiempo). Al menos en mi insignificante opinión, será suficiente para mí saber que la atención está en este problema y que se priorizará cuando las dependencias habiliten la solución deseada.

(Estoy seguro de que he confundido algunos de los detalles sutiles de las soluciones disponibles / bloqueadas, pero espero que al escribir esto la gente pueda concentrarse en afirmar qué problema esperan resolver en lugar de saltar al espacio de la solución).

¿No estaría la GPU mejor equipada para lidiar con una carga de renderizado de cualquier manera? Eso es exactamente para lo que fue hecho.

De acuerdo, priorizamos lo que usa la CPU y la GPU de manera diferente, tener una función relacionada con los gráficos que use recursos específicos de gráficos tiene más sentido. Una ganancia de CPU no es una pérdida 1: 1 de GPU y viceversa. En su mayoría discutible en este punto (hasta que se corrija el error en Chromium) pero algo relevante ya que la solución actual aún emplea la CPU (aunque con mucho menos peso).

Creo que la gente debería dejar de usar la tecnología web en el escritorio, ya que requiere el envío de un navegador completo con cada programa.
Sin mencionar que, si tiene varios de dichos programas, tiene los mismos binarios duplicados por todas partes.

Necesitamos volver al metal desnudo.

PD: JScript debería haberse abandonado hace 10 años, al igual que debería haber sido Obj-C, si Apple no lo hubiera resucitado.
PPS: ^^^^ esto es una perorata.

PPS: ^^^^ esto es una perorata.

@ bit2shift De hecho lo es, y como tal no pertenece al hilo de comentarios sobre un error muy específico. No utilices los comentarios de problemas de GitHub para despotricar.

@ bit2shift - Si bien estoy de acuerdo con algunas partes (como el hecho de que una aplicación basada en navegador probablemente no se sienta del todo "nativa" en comparación con una verdadera aplicación nativa), ¿qué tan bajo es "bare metal"? ¿Codigo de maquina? Lenguaje ensamblador? ¿C? C ++? C#? Siempre habrá varias capas de abstracción, independientemente de su pila de tecnología.

Sin mencionar que, si tiene varios de dichos programas, tiene los mismos binarios duplicados por todas partes.

Sin embargo, ocurre lo mismo con cualquier aplicación de C # que use paquetes NuGet. Todos los ensamblajes son locales para la aplicación. .NET Core incluso distribuye grandes partes del marco como paquetes NuGet.

ya que requiere el envío de un navegador completo con cada programa.

Técnicamente, podría usar el motor Edge, lo que evitaría la necesidad de instalar un tiempo de ejecución del navegador por separado. Internet Explorer hizo algo similar hace casi 20 años con las aplicaciones HTML . Otro ejemplo es React Native, que utiliza el motor JS nativo del sistema operativo cuando está disponible. Para las aplicaciones basadas en JavaScript, algo como React Native para Windows es probablemente el futuro en lugar de las tecnologías web, ya que se siente más nativo ya que usa widgets de UI nativos.

@ Daniel15

(...) ¿qué tan bajo es el "metal desnudo"? ¿Codigo de maquina? Lenguaje ensamblador? ¿C? C ++? C#?

Cualquier lenguaje que sea compilable en código de máquina (solo source -> ELF/PE cuenta) se considera "bare metal" en este contexto, por lo que las capas de abstracción no importan aquí.

Internet Explorer hizo algo similar hace casi 20 años con las aplicaciones HTML.

"algo similar" como tener mshta.exe usar mshtml.dll que reside en system32 desde los años 90.

Otro ejemplo es React Native, que utiliza el motor JS nativo del sistema operativo cuando está disponible. Para las aplicaciones basadas en JavaScript, algo como React Native para Windows es probablemente el futuro en lugar de las tecnologías web, ya que se siente más nativo ya que usa widgets de UI nativos.

Si se desea un alto rendimiento en las aplicaciones JS de escritorio, entonces alguien con suficiente tiempo en sus manos debería escribir una interfaz para LLVM.
Perdería la capacidad de ejecutar fragmentos arbitrarios de código, pero eso sería una ventaja desde el punto de vista de la seguridad.

/hilo

¿No puedes descarrilar este hilo, por favor? Este es un problema sobre un problema de rendimiento específico con un cursor parpadeante y definitivamente no es un lugar para discutir los méritos generales del desarrollo de aplicaciones de escritorio basadas en JS.

Estás enviando spam a los buzones de correo de personas que no están interesadas en estas peroratas.

¿Qué tal poner un <input type=text> con un tamaño de 2px * 10px en el lugar donde está el cursor? De esa manera, usará el cursor parpadeante nativo de <input> : P <blink></blink> 👍

Además, no estoy seguro de la gravedad de este problema, cuando VSCode está inactivo (no estoy escribiendo código) casi siempre no está enfocado, el enfoque está en otra aplicación en la que estoy. Y el cursor deja de parpadear.

por mi experiencia, los gifs no son tan buenos. Una vez tuve una ruleta de carga como una imagen gif. y lo usé mientras interactuaba con indexeddb. a veces podía ver que la ruleta se detenía, incluso en el escritorio.

Presionó el cambio de cursor del terminal a maestro y soltó / 1.11 (animación CSS -> setInterval ).

Gracias a todos por investigar este problema. ¡Sus investigaciones y sugerencias nos ayudaron a encontrar la causa raíz y las posibles soluciones! Comparamos JavaScript setInterval , gif animados y varias otras técnicas, y nos decidimos por la siguiente solución:

  • Si editor.cursorBlinking se establece en blink o terminal.integrated.cursorBlinking se establece en true , la lógica intermitente ahora se implementa en JavaScript. Nuestras pruebas muestran que el uso de la CPU se reduce a menos del 1%.
  • Si editor.cursorBlinking se establece en smooth , expand o phase , que utilizan funciones de suavizado CSS, detendremos la animación parpadeante después de que el cursor esté inactivo 10 segundos.

Esta corrección ya está en nuestra compilación de Insider y estará disponible en nuestra compilación estable de abril, que se lanzará en los próximos días. Sería fantástico si algunos de ustedes pudieran verificar los resultados de nuestras pruebas. Si ve problemas, cree uno nuevo.

@rebornix , ¿quiso decir "o" terminal.integrated.cursorBlinking está configurado en true ? ¿O fue el "y" intencional?

@jedmao gracias por la corrección, debería or .

¿Fue útil esta página
0 / 5 - 0 calificaciones