Как загрузить процессор js
solutions for other browsers I do not know. Any idea how to do it? maybe webgl has access to information about your computer? or flash? or any other technology?
Thank you very much
In google chrome you can use console.memory to find out the amount of memory available in the JS heap.
I'd have a look at whether a Flash shim might help. I haven't seen any cross-browser API for hardware info before.
2. Решение проблемы блокирующего JS-кода без инспектора
Предположим, так случилось, что в коде закрался бесконечный цикл или другая ошибка, приводящая к полной блокировке выполнения JS-кода на сервере. В этом случае единственный поток NodeJs будет заблокирован, сервер перестанет отвечать на запросы, а загрузка ядра CPU достигнет 100%. Если инспектор еще не запущен, то его запуск вам не поможет выловить виновный кусок кода.
В этом случае на помощь может прийти дебаггер gdb.
Для докера нужно использовать
--cap-add=SYS_PTRACE
и установить пакеты
apt-get install libc6-dbg libc-dbg gdb valgrind
Итак, нужно подключиться к nodejs процессу (зная его pid):
sudo gdb -p
После подключения ввести команды:
Я не буду вдаваться в подробности, что делает каждая команда, скажу лишь, что тут используются некоторые внутренние ф-ии движка V8.
В результате этого выполнение текущего блокирующего JS-кода в текущем “тике” будет остановлено, приложение продолжит свою работу (если вы используете Express, сервер сможет обрабатывать поступающее запросы дальше), а в стандартный поток вывода NodeJs-приложения будет выведен stack trace.
Он довольно длинный, но в нем можно найти полезную информацию — стек вызовов JS функций.
Находите строки такого вида:
Они должны помочь определить “виноватый” код.
Для удобства написал скрипт для автоматизации этого процесса с записью стека вызовов в отдельный лог-файл: loop-terminator.sh
Также см. пример приложения с его наглядным использованием.
Результаты
После того, как тестовая страница исследована с помощью Puppeteer, можно проанализировать результаты измерений производительности, перейдя в браузере по адресу chrome://tracing и загрузив только что записанный файл trace.json .
Визуализация trace.json
Здесь можно видеть результаты вызова метода performance.measure('my mark') . Вызов measure() нужен исключительно для отладочных целей, на тот случай, если разработчику захочется открыть файл trace.json и посмотреть его. Всё, что произошло со страницей, заключено в блок my mark .
Вот фрагмент trace.json :
Фрагмент файла trace.json
Для того чтобы выяснить то, что нам нужно, достаточно вычесть показатель количества инструкций процессора ( ticount ) маркера Start из такого же показателя маркера End . Это позволяет узнать о том, сколько инструкций процессора нужно для вывода компонента в браузере. Это — то самое число, которое можно использовать для того, чтобы выяснить, стал ли компонент быстрее или медленнее.
4. Используйте дочерние процессы
Если в вашем серверном приложении есть ресурсоемкий код, изрядно нагружающий CPU, хорошим решением может стать вынесение его в отдельный дочерний процесс. Например, это может быть серверный рендеринг React-приложения.
Говоря о производительности, другой не менее важной метрикой является потребление RAM. Существуют инструменты и техники для поиска утечек памяти, но это тема для отдельной статьи.
Давайте немного поговорим о том, как наблюдать за тем, какой объём ресурсов процессора потребляет JavaScript-код приложений. При этом предлагаю построить наш разговор вокруг компонентов — базовых строительных блоков приложения. При таком подходе любые усилия по улучшению производительности (или усилия по поиску причин замедления программ) можно сосредоточить на (хочется надеяться) маленьких самодостаточных фрагментах проекта. Я предполагаю при этом, что ваше фронтенд-приложение, как и многие другие современные проекты, создано путём сборки небольших фрагментов интерфейса, подходящих для многократного использования. Если это не так, то наши рассуждения можно будет применить и к другому приложению, но вам придётся найти собственный способ разделения своего крупномасштабного кода на фрагменты и надо будет подумать над тем, как анализировать эти фрагменты.
Зачем это нужно?
Зачем измерять потребление ресурсов процессора JavaScript-кодом? Дело в том, что в наши дни производительность приложений чаще всего привязана к возможностям процессора. Позвольте мне вольно процитировать слова Стива Содерса и Пэта Минана из интервью, которое я брал для Planet Performance Podcast. Оба они говорили о том, что производительность приложений больше не ограничивается возможностями сетей или сетевыми задержками. Сети становятся всё быстрее и быстрее. Разработчики, кроме того, научились сжимать текстовые ответы серверов с помощью GZIP (или, скорее, с применением brotli) и разобрались с оптимизацией изображений. Это всё очень просто.
Узким местом производительности современных приложений стали процессоры. Особенно это актуально в мобильной среде. И, в то же время, выросли наши ожидания относительно интерактивных возможностей современных веб-приложений. Мы ожидаем, что интерфейсы таких приложений будут работать очень быстро и плавно. А для всего этого требуется всё больше и больше JavaScript-кода. Кроме того, нам нужно помнить о том, что 1 Мб изображений — это не то же самое, что 1 Мб JavaScript. Изображения загружаются прогрессивно, а приложение в это время решает другие задачи. А вот JavaScript-код — это часто такой ресурс, без которого приложение оказывается неработоспособным. Для обеспечения функционирования современного приложения требуются большие объёмы JS-кода, которые, прежде чем они начинают реально работать, нужно распарсить и выполнить. А это — задачи, которые сильно зависят от возможностей процессора.
3. Обновляйте NodeJs (и npm-пакеты)
Иногда вы не виноваты :)
Смысл в том, что приложение запускает WebSocket-сервер (на socket-io) и запускает один дочерний процесс через child_process.fork() . Следующая последовательность действий гарантированно вызывает 100% загрузку 1 ядра CPU:
- К WS-северу подключается клиент
- Дочерний процесс завершается и пересоздается
- Клиент отключается от WS
Причем приложение все еще работает, Express сервер отвечает на запросы.
Вероятно, баг находится в libuv , а не в самой ноде. Истинную причину этого бага и исправляющий его коммит в changelog’ах я не нашел. Легкое “гугление” привело к подобным багам в старых версиях:
Решение простое — обновить ноду до v8.5.0+.
5 Answers 5
You can profile your app with node-tick.
- Install node-tick by npm -g install tick
- Run your app with enabled profile node --prof ./app.js
- After some time with CPU 100% usage stop your app
- You can see v8.log in your app directory, now you can read it with node-tick-processor
- Run node-tick-processor and explain results
Oh man, this helped me discover that I removed a module while also requiring it in a service. Good grief.
UPDATE 2019 !!
You better use the built in --prof-process to process v8 profiling data, the generated file is no longer v8.log and node-tick-processor won't help you much, so to profile your app and read the v8 profiling data you can proceed as follows:
Node will generate a file with a name like this isolate-0x103800000-v8.log in your current directory, now you use this file to generate a profiling report
Constantly running at 100% CPU is typical for infinite loop. This is a real problem in singlethreaded nodejs but unfortunately there is a lack of info on it.
Eventually I have found the only useful article: How to track the deadloop in nodejs:
Connect to you server via SSH. Identify nodejs process id (let it be 4702, for example). Now, let’s tell the process to listen for debugging requests. Yes, we’re using a command called kill. No, we’re not killing the process. We’re sending it a different signal.
Once you do this, the process is open to a debugger connection. In fact, it will print a special URL to its console log, and you can open that URL in Chrome to debug the process! But, maybe you don’t want to drill a hole through a firewall and a container configuration just to make that connection. Yeah, me neither. So let’s debug at the command line instead:
You’ll see this prompt:
And you get back:
Yes! We have our first hint. The app was executing line 555 in file something.js. That might be enough to see the bug right away. But usually we need more information than that. You can type backtrace to get a complete stack trace:
При работе многопоточного Java + SWT - приложения процесс javaw никогда не загружает процессор более чем на 50% (процессор, соответственно, двухядерный). Проверял на ОC Windows. 50% загрузки - это реальное значение? Или ОС просто делит уровень общей загрузки CPU Java-приложением на количество "доступных процессоров"? Если реальное, то как заставить Java-машину работать "на все 100"?
Хотите 100% - делаейте хотя бы ещё один тред. Так как в Вашей программе подозреваю только один тред, то он не может загрузить более одного ядра. Ядер 2, поэтому не более 50% от общего.
Выжимку (в смысле многопоточности) из кода приведите. Вообще-то много ресурсов (в смысле параллельности использования CPU) может уходить на синхронизацию (не знаю, у Вас она есть ?).
Можно и в многопоточном код так написать, что он будет грузить только на 50% (например классика жанра - тред вызывает внешний метод, который синхронизированный).
2 ответа 2
Загрузка ядер зависит от версии работающего JVM. Более-менее нормальная поддержка многоядерных процессоров работает начиная с версии Java 1.6, также имеет смысл обратить внимание на битность работающего JVM'а - x64 или x86. Если ось 64-х разрядная имеет смысл установить оба JRE поскольку в разных ситуациях могут быть задействованы разные JRE 64-х или 32-х разрядные.
Вообще скорость работы JVM в многопоточных приложениях лимитируется скоростью аллокации объектов (т.н. allocation wall) - читай проще скоростью записи в RAM - то есть бутылочное горлышко проходит там. Более подробно читать здесь. В общем надо сначала "расшить" эту сторону и тогда можно говорить об увеличении загрузки процессора.
если в программе один тред (и нет неявных других), то как бы java не напрягалась, загрузить более одного ядра не получится. (если только компилятор не сможет придумать, как распараллелить код)
@KoVadim я бы не был так категоричен. JVM в состоянии загрузить все ядра - просто распараллеливание будет не на уровне нитей/тредов, а на уровне процессов
На уровне процессов - тут понятно. Я думаю, если бы ТС запустил две копии своей программы, то вполне бы и на 100% загрузило бы:)
Chrome DevTools Inspector
В первую очередь, это профайлер, встроенный в Chrome DevTools, который будет связываться с NodeJs приложением через WebSocket (стандартный порт 9229 ).
Запустите nodejs-приложение с флагом --inspect
(по умолчанию будет использоваться стандартный порт 9229 , который можно изменить через --inspect= ).
Если NodeJs сервер в докер-контейнере, нужно запускать ноду с --inspect=0.0.0.0:9229 и открыть порт в Dockerfile или docker-compose.yml
Откройте в браузере chrome://inspect
Найдите ваше приложение в “Remote Target” и нажмите “inspect” .
Откроется окно инспектора, схожее со стандартным “браузерным” Chrome DevTools.
Нас интересует вкладка “Profiler” , в которой можно записывать CPU профайл в любое время работы приложения:
После записи собранная информация будет представлена в удобном таблично-древовидном виде с указанием времени работы каждой ф-ии в ms и % от общего времени записи (см. ниже).
Возьмем для экспериментов простое приложение (можно склонировать отсюда), эксплуатирующее узкое место в либе cycle (используемой в другой популярной либе winston v2.x) для эмуляции JS кода с высокой нагрузкой на CPU.
Будем сравнивать работу оригинальной либы cycle и моей исправленной версии.
Установите приложение, запустите через npm run inspect . Откройте инспектор, начните запись CPU профайла. В открывшейся странице http://localhost:5001/ нажмите "Run CPU intensive task" , после завершения (алерта с текстом “ok”) завершите запись CPU профайла. В результате можно увидеть картину, которая укажет на наиболее прожорливые ф-ии (в данном случае — runOrigDecycle() и runFixedDecycle() , сравните их %):
Сильный сигнал
Если ответственно подойти к решению вопроса о том, что именно измеряется, то можно получить по-настоящему стабильный сигнал, отражающий влияние на производительность любых изменений. Мне нравится то, насколько гладкими получились линии на следующем графике.
Стабильные результаты измерений
На нижнем графике показаны результаты измерений 10 операций рендеринга простого элемента в React. Ничего больше в эти результаты не входит. Оказывается, что на выполнение этой операции нужно от 2.15 до 2.2 миллиона инструкций процессора. Если же обернуть в тег
, то для вывода такой конструкции надо уже около 2.3 миллиона инструкций. Меня поражает такой уровень точности. Если разработчик может увидеть разницу в производительности, появляющуюся при добавлении на страницу единственного элемента
, это значит, что в руках разработчика находится по-настоящему мощный инструмент.
То, как именно представлять измерения такой точности — дело разработчика. Если подобная точность ему не нужна, он всегда может измерять производительность рендеринга более крупных фрагментов.
Пример
А вот — пример использования компонента Button . Как видите, в данном случае имеются два варианта компонента, в которых используются разные свойства.
Вот страница test.html , которая может загружать любые компоненты. Обратите внимание на вызовы методов объекта performance . Именно с их помощью мы, по своему желанию, делаем записи в файл журнала производительности Chrome. Совсем скоро мы этими записями воспользуемся.
4 Answers 4
This code will print GPU infos an will list all info you can have with the performance object of this browser (there is no standard for the BOM so it changes for each browser).
Output in Chrome :
Output in Firfox :
Output in Safari :
I really appreciate the no-IE thing, anyway, why should we wonder about a browser with less than 10% worldwide market-share. Vote+1
If you're interested in this question, you may like to know that Firefox has started "bucketing" GPU names -- quite a lot of GPUs now show up as "GTX 980". It's an anti-fingerprinting measure.
Currently Chrome Canary supports returning the amount of CPU cores using:
This worked for me in Chrome Canary 37.
Is this cores or threads? Because when I did this I got the number 4 back, but my processor only has two cores (it does have 4 threads though). I'm guessing this is because I have an i7?
@Johannes with processors supporting Hyperthreading the system sees your double core processor as quad core. Not browsers only, but OS itself.
I wrote this quick script to get the cpu speed:
Note that this depends on browser tabs, memory use, etc. but I found it pretty accurate if you only run it once, say at the loading of a page.
This may not be accurate for desktop devices, especially PCs, but I use it in my website only when other solutions like the first one fail, for getting the average speed of mobile devices (allows me to estimate cores used) using only client-side JS. It may not be the best, but it does pretty well.
If you would like you can change the _speedconstant to change the speed, just calculate it with the equation (knowncpuspeed*knowntimetocomplete)/knowncycles. Hope you find this useful!
UPDATE 10/19/17: Changed _speedconstant for the new chrome V8 JS engine and added section about what I use it for.
Из-за однопоточной архитектуры Node.js важно быть настороже высокой производительности вашего приложения и избегать узких мест в коде, которые могут привести к просадкам в производительности и отнимать ценные ресурсы CPU у серверного приложения.
В этой статье речь пойдет о том, как производить мониторинг загрузки CPU nodejs-приложения, обнаружить ресурсоемкие участки кода, решить возможные проблемы со 100% загрузкой ядра CPU.
Поиск кода для исследования
Для того чтобы найти код для исследования, мы можем обратиться к любому руководству по стилям, или к любой дизайн-системе. В целом — нас устроит что угодно, предоставляющее краткие, изолированные примеры использования компонентов.
Что такое «руководство по стилям»? Обычно это — веб-приложение, демонстрирующее все компоненты или «строительные блоки» элементов пользовательского интерфейса, доступные разработчику. Это может быть как некая библиотека компонентов стороннего разработчика, так и что-то, созданное вашими силами.
Занимаясь поиском подобных проектов в интернете, я наткнулся на недавнюю ветку обсуждения в Твиттере, речь в которой шла об относительно новых библиотеках React-компонентов. Я взглянул на несколько упомянутых там библиотек.
Неудивительно то, что современные качественные библиотеки снабжены документацией, включающей в себя рабочие примеры кода. Здесь представлена пара библиотек и реализованные их средствами компоненты Button . В документации к данным библиотекам есть примеры использования этих компонентов. Речь идёт о библиотеке Chakra и о библиотеке Semantic UI React.
Документация Chakra, посвящённая компоненту Button
Документация Semantic UI React, посвящённая компоненту Button
Это — именно то, что нам нужно. Это — те примеры, код которых мы можем исследовать на предмет потребления ими ресурсов процессора. Подобные примеры могут находиться в недрах документации, или в комментариях к коду, написанных в стиле JSDoc. Возможно, если вам повезёт, вы обнаружите такие примеры, оформленные в виде отдельных файлов, скажем — в виде файлов модульных тестов. Наверняка будет именно так. Ведь все мы пишем модульные тесты. Правда?
Средство для запуска тестов
Для того чтобы загрузить тестовую страницу в Chrome, мы можем воспользоваться Node.js-библиотекой Puppeteer, которая даёт нам доступ к API для управления браузером. Пользоваться этой библиотекой можно в любой операционной системе. В ней имеется собственная копия Chrome, но её можно применять и для работы с уже существующим на компьютере разработчика экземпляром Chrome или Chromium различных версий. Chrome можно запустить так, что его окно будет невидимым. Тесты выполняются автоматически, разработчику при этом видеть окно браузера необязательно. Chrome можно запустить и в обычном режиме. Это полезно для целей отладки.
Вот пример Node.js-скрипта, запускаемого из командной строки, который загружает тестовую страницу и пишет данные в файл журнала производительности. Всё, что происходит в браузере между командами tracing.start() и end() , записывается (хочется отметить, весьма подробно) в файл trace.json .
Разработчик может управлять «детальностью» данных о производительности, указывая «категории» трассировки. Список доступных категорий можно увидеть, если перейти в Chrome по адресу chrome://tracing , нажать Record и открыть в появившемся окне раздел Edit categories .
Настройка состава данных, записываемых в журнал производительности
NodeJs Profiler
Другой вариант — использование встроенного в NodeJs профайлера для создания отчетов о CPU производительности. В отличие от инспектора, он покажет данные за все время работы приложения.
Запустите nodejs-приложение с флагом --prof
В папке приложения будет создан файл вида isolate-0xXXXXXXX-v8.log , в который будут записываться данные о “тиках”.
Данные в этом файле неудобны для анализа, но из него можно сгенерировать человеко-читаемый отчет с помощью команды
node --prof-process
Пример такого отчета для тестового приложения выше тут
(Чтобы сгенерировать самому, запустите npm run prof )
Показатель производительности
Мы будем использовать такой показатель скорости работы фрагментов кода, как количество инструкций процессора, необходимое на их обработку. Это позволит нам отделить измерения от свойств конкретного компьютера и от того, в каком состоянии он находится в момент измерений. В метриках, основанных на измерении времени (вроде TTI) слишком много «шума». Они зависят от состояния сетевого соединения, а так же от чего угодно другого, происходящего на компьютере в момент измерений. Например, на временные показатели производительности могут повлиять некие скрипты, выполняемые во время загрузки исследуемой страницы, или вирусы, которые чем-то заняты в фоновых процессах. То же самое можно сказать и о браузерных расширениях, которые могут потреблять немало системных ресурсов и замедлять страницу. При подсчёте же количества инструкций процессора, с другой стороны, время неважно. Подобные показатели могут быть, как вы скоро увидите, по-настоящему стабильными.
Вот идея, положенная в основу нашей работы: нужно создать «лабораторию», в которой код будет запускаться и исследоваться при внесении в него изменений. Под «лабораторией» я понимаю обычный компьютер, возможно, тот, которым вы постоянно пользуетесь. Системы контроля версий дают в наше распоряжении хуки, с помощью которых можно перехватывать определённые события и выполнять некие проверки. Конечно, измерения в «лаборатории» можно выполнять после выполнения коммитов. Но вы, наверняка, знаете о том, что изменения в код, достигший стадии коммита, будут вноситься медленнее, чем в код, находящийся в процессе написания (если вообще будут вноситься). То же самое касается и исправления кода бета-версии продукта, и исправления кода, который попал в продакшн.
Нам нужно, чтобы при каждом изменении кода проводилось бы сравнение его производительности до и после внесения изменений. При этом мы стремимся к тому, чтобы исследовать компоненты в изоляции. В результате мы сможем ясно видеть проблемы и сможем точно знать о том, где они возникают.
Хорошо то, что подобные исследования можно проводить в настоящем браузере, используя, например, Puppeteer. Это — инструмент, который позволяет управлять браузером без пользовательского интерфейса из среды Node.js.
Итоги
Можно ли всем, о чём шла тут речь, пользоваться уже сегодня? Да, можно. Для этого понадобится Chrome версии 78 или выше. Если в trace.json имеются показатели ticount и tidelta , то вам вышеописанное доступно. В более ранних версиях Chrome таких показателей нет.
К сожалению, сведения о количестве инструкций процессора нельзя получить на платформе Mac. Windows я пока не пробовал, поэтому ничего определённого об этой ОС сказать не могу. В общем — наши друзья — это Unix и Linux.
Надо отметить, что для того, чтобы браузер мог бы выдавать сведения об инструкциях процессора, понадобится использовать пару флагов — это --no-sandbox и --enable-thread-instruction-count . Вот как передать их браузеру, запускаемому средствами Puppeteer:
Надеюсь, теперь вы сможете вывести анализ производительности своих веб-приложений на новый уровень.
We're having a problem where every once in a while one of our environments our node app runs on 100% CPU. The server isn't very active and usually runs on 0%-2% CPU. I was wondering what are the common issues that might cause this problem and what would be the best way to find out what causing this issue.
node version 0.8.14
ubuntu 11.10
Intel(R) Xeon(R) CPU E5645 @ 2.40GHz
Node packages used:
Дополнительные сведения о производительности
Теперь, когда в распоряжении разработчика имеется система нахождения численных показателей, очень точно характеризующих производительность мельчайших фрагментов кода, разработчик может воспользоваться этой системой для решения различных задач. Так, с помощью performance.mark() можно записывать в trace.json дополнительные полезные сведения. Можно сообщать членам команды разработчиков о том, что, происходит, и что вызывает рост количества инструкций процессора, необходимых для выполнения некоего кода. Можно включать в отчёты о производительности сведения о количестве узлов DOM, или о количестве операций записи в DOM, выполняемых React. На самом деле, тут можно выводить сведения об очень многом. Можно подсчитывать число пересчётов макета страницы. Средствами Puppeteer можно делать скриншоты страниц и сравнивать то, как выглядит интерфейс до и после внесения изменений. Иногда рост количества инструкций процессора, необходимых для вывода некоей страницы, выглядит совершенно неудивительно. Например — в том случае, если в новую версию страницы добавлено 10 кнопок и 12 полей для редактирования и форматирования текста.
Дьявол кроется в деталях
Сейчас мы измерили лишь показатели, характеризующие первый вывод на страницу единственного компонента. И ничего больше. Настоятельно необходимо измерять показатели, относящиеся к как можно меньшему объёму выполняемого кода. Это позволяет уменьшить уровень «шума». Дьявол кроется в деталях. Чем меньше то, производительность чего измеряется, тем лучше. После измерений нужно убрать из полученных результатов то, что находится за пределами влияния разработчика. Например — данные, относящиеся к операциям сборки мусора. Компонент не контролирует такие операции. Если они выполняются, то это значит, что браузер, в процессе рендеринга компонента, сам решил их запустить. В результате из итоговых результатов нужно убрать те процессорные ресурсы, которые ушли на сборку мусора.
Блок данных, относящийся к сборке мусора (этот «блок данных» правильнее называть «событием»), носит имя V8.GCScavenger . Его показатель tidelta нужно вычесть из количества инструкций процессора, уходящих на рендеринг компонента. Вот документация по событиям трассировки. Она, правда, устарела, и не содержит сведений о нужных нам показателях:
- tidelta — количество инструкций процессора, потребовавшихся на обработку некоего события.
- ticount — количество инструкций на начало события.
10 операций рендеринга одного и того же компонента
Вот ещё одна деталь: если компонент выполняет некие асинхронные операции (например, пользуется setTimeout() или fetch() ), то нагрузка на систему, создаваемая асинхронным кодом, не учитывается. Может — это хорошо. Может — плохо. Если вы исследуете производительность подобных компонентов — подумайте об отдельном изучении асинхронного кода.
1. CPU-профайлинг приложения. Инструменты
К счастью, у разработчиков есть удобные инструменты для обнаружения и визуализации “хот-спотов” загрузки CPU.
Файлы
Представим, ради демонстрации описываемого метода анализа производительности, что в исследуемой нами библиотеке есть компонент Button , код которого находится в файле Button.js .К этому файлу прилагается файл с модульным тестом Button-test.js , а также — файл с примером использования компонента — Button-example.js . Нам нужно создать некую тестовую страницу, в окружении которой может быть запущен тестовый код. Нечто вроде test.html .
Компонент
Вот простой компонент Button . Я тут использую React, но ваши компоненты могут быть написаны с использованием любых удобных вам технологий.
Читайте также: