Pull to refresh
95
0
Вячеслав Егоров @mraleph

Пользователь

Send message
нет, это тривиальные перечислены в habrahabr.ru/post/151690/?reply_to=5153675#comment_5152882
я — Вячеслав :-)
у arguments object достаточно мутная семантика, поэтому если v8 видит, что он используется нетривиальным образом, то она отказывается оптимизировать. это проистекает из соображения, что в коде, для которого важны оптимизации, arguments чаще всего не используется или используется тривиальным способом, поэтому и реализовывать сложную поддержку нет смысла. (меньше сложностей — меньше багов).
это не совсем верно, ряд конструкций поддерживается в оптимизированном коде: arguments[i], arguments.length, func.apply(obj, arguments)

кстати проверить чистится ли WeakMap или нет на чистом JavaScriptе нельзя, он специально так задизайнен чтобы сделать сборку мусора ненаблюдаемой :-)
это не о тех mapах, это о скрытых классах, внутри они называются Map.
> в Map мусор собирается аналогично WeakMap

нет, Mapом все должно удерживаться, как вы проверяли?
Репозиторий на GitHub всего лишь зеркало.

Официальный репозиторий: code.google.com/p/v8/

Памятка для желающих поучаствовать: code.google.com/p/v8/wiki/Contributing
какой факт? что замеры производительности С++ кода на разных машинах, компиляторах и флагах сборки дали разные результаты? это действительно факт.

обратите внимание, я не пытаюсь утверждать, что V8 производит в данном конкретном случае супер код (хотя я посмотрел на него и код достаточно хороший, если не считать бага описнного внизу) или что пересечение границы JS-C++ легче перышка. я утверждаю другое: разница в десятки миллисекунд на таком коде не может быть объяснена задержками при пересечении этой границы.

более того, я даже склоняюсь ко мнению, что у автора что-то со флагами компиляции не так — из-за чего скорость С++ного кода оказалась такой странной. но для подтверждения надо посмотреть на то, что его компилятор породил в этом месте. (еще заметьте, что и время исполнения обычного С++ного варианта и CUDA-вского включают в себя время пересечения границы JS-C++, т.е. оно меньше 17ms).

какой факт? что замеры производительности С++ кода на разных машинах, компиляторах и флагах сборки дали разные результаты? это действительно факт.

обратите внимание, я не пытаюсь утверждать, что V8 производит в данном конкретном случае супер код (хотя я посмотрел на него и код достаточно хороший, если не считать бага описнного внизу) или что пересечение границы JS-C++ легче перышка. я утверждаю другое: разница в десятки миллисекунд на таком коде не может быть объяснена задержками при пересечении этой границы.

более того, я даже склоняюсь ко мнению, что у автора что-то со флагами компиляции не так — из-за чего скорость С++ного кода оказалась такой странной. но для подтверждения надо посмотреть на то, что его компилятор породил в этом месте. (еще заметьте, что и время исполнения обычного С++ного варианта и CUDA-вского включают в себя время пересечения границы JS-C++, т.е. оно меньше 17ms).

omega ~/src/temp/perl_vs_node ∳ git diff                                              [master@368da]
diff --git a/integral.js b/integral.js
index 7b11f22..194adb2 100755
--- a/integral.js
+++ b/integral.js
@@ -18,4 +18,5 @@ function integrateJS(x0,xN,y0,yN,iterations){
     console.log("JS time = "+(new Date().getTime() - time));
 }
 
-integrateJS(-4,4,-4,4,1024);
\ No newline at end of file
+integrateJS(-4,4,-4,4,1024);
+integrateJS(-4,4,-4,4,1024);
omega ~/src/temp/perl_vs_node ∳ node integral.js                                      [master@368da]
JS result = 127.99999736028109
JS time = 132
JS result = 127.99999736028109
JS time = 115
omega ~/src/temp/perl_vs_node ∳ node --nouse-osr integral.js                          [master@368da]
JS result = 127.99999736028109
JS time = 122
JS result = 127.99999736028109
JS time = 55


извиняюсь, коряво вставил консольный лог :-/
у меня на ноде v0.8.8 вылазит баг в V8ом выводе представлений (representation inference) из-за которого замена на стэке (on stack replacement) пораждает совершенно бредовый код, в котором он пытается привести заведомо не целое значение к целому из-за чего происходит деоптимизация… в результате код постоянно крутится в неоптимизированной версии.

если же я запрещаю OSR и вызываю integrateJS дважды, то картина с пиковой производительностью получается примерно такая:

omega ~/src/temp/perl_vs_node ∳ git diff [master@368da] diff --git a/integral.js b/integral.js index 7b11f22..194adb2 100755 --- a/integral.js +++ b/integral.js @@ -18,4 +18,5 @@ function integrateJS(x0,xN,y0,yN,iterations){ console.log("JS time = "+(new Date().getTime() - time)); } -integrateJS(-4,4,-4,4,1024); \ No newline at end of file +integrateJS(-4,4,-4,4,1024); +integrateJS(-4,4,-4,4,1024); omega ~/src/temp/perl_vs_node ∳ node integral.js [master@368da] JS result = 127.99999736028109 JS time = 132 JS result = 127.99999736028109 JS time = 115 omega ~/src/temp/perl_vs_node ∳ node --nouse-osr integral.js [master@368da] JS result = 127.99999736028109 JS time = 122 JS result = 127.99999736028109 JS time = 55

баг я зарапортую на эту тему. причина по моей прикидке в том, что начальное значение переменной result — 0 выглядит как целое число и попадая в phi-функцию на границе между нормальным потоком управления и OSR-entry блоком приводит к неправильному выводу представления для этой phi (https://github.com/v8/v8/blob/d3924c236bfca217385eaf5355a96146f0dcc60d/src/hydrogen-instructions.cc#L2567-2576 < — код увидев 0 выберет целое представление) и почему-то посказки (hint) для HUnknownOSRValue на обратной дуге не сработали.

Кстати, если заменить result = 0, на result = 0.1 баг в representation inference по понятным причинам пропадает.
функция вызывается один раз и выполняется сотни миллисекунд. в таком случае накладные расходы на пересечение границы просто незаметны. они ведь отнюдь не десятками миллисекунд измеряются, а совсем даже долями миллисекунды.
утечка — это когда память болтается непонятно где, не используется и не может быть переиспользована. а здесь не эффективное использование памяти, потому что это память никуда не пропала и занята объектом, на который есть валидные ссылки из другого объекта.
а сами объекты с 9 свойствами, конечно же, помирают… просто они были меньше с словаря, который теперь свисает с каждого testedObject[i], что пораждает иллюзию их живости.
Прежде всего совет: не пытайтесь понять, что удаляется, а что не удаляется по графику потребления памяти — это гадание на кофейной гуще. Просто посмотрите на снапшот кучи.

Объяснение (по крайней мере для Хрома) очень простое: когда вы делаете delete testedObject[i].obj, V8 нормализует объект testedObject[i] — трансформирует его из быстрого компактного представления в медленное и раздутое представление на основе словаря, который еще и выделяется с запасом по размеру. При этом V8 не замечает, что после удаления в словаре будет пусто — и словарь (800 байтов) остается болтаться в воздухе. И так для каждого из ваших объектов.
это не совсем правильный вывод: бенчмарк фокусируется на производительности чистого javascript, который однопоточен по своей природе. (workerы не являются частью ECMAScript стандарта и потому в тестах не используются). поэтому основной поток исполнения бенчмарка просто не может загрузить больше одного ядра.

некоторые JavaScript рантаймы, впрочем, испольуют потоки для различных внутренних целей: например, конкурентная сборка мусора и компиляция в Chakra, параллельная фаза разметки (marking) в JavaScriptCore, фаза sweeping в SpiderMonkey. так что наличие нескольких дополнительных ядер только на пользу.
если игра использует много чисел с плавающей точкой, то результат NavierStokes все-таки имеет отношение к качеству оптимизации такого кода.
Тесты в V8 Benchmark Suite могут со стороны выглядеть совершенно случайными, но на самом деле они тестируют фундаментальные вещи. NavierStokes, например, тестирует качество оптимизаций операций над числами с плавающей точкой и скорость работы массивов содержащих числа с плавающей точкой.

Проблема с большим реальным кодом состоит в том, что в нем сразу множество факторов влияющих на производительность смешиваются, поэтому V8 Benchmark Suite пытался разложить, так сказать, различные факторы по полочкам и каждый бенчмарк был достаточно сфокусирован на фичах языка, которые V8 хотела ускорить: DeltaBlue — полиморфный объектно-ориентированный код, Crypto — побитовые операции и т.д.

Хорошее описание фокуса каждого бенчмарка: developers.google.com/octane/benchmark

Information

Rating
Does not participate
Location
Дания
Date of birth
Registered
Activity