Как стать автором
Обновить

Комментарии 91

Неплохо было бы написать версии браузеров. Результаты в Firefox 3.6 и 4 могут сильно отличаться.
Учитывая, что LuaJIT позиционируется как высокопроизводительный инструмент для 3D моделирования и игр, то это очень весьма-весьма неожиданно.
В очередной раз порадовала скорость JS в Хроме :)
Только инструмент не для рейтрейсинга, а для написания различных скриптов для ide, внутренней игровой логики, может быть анимации.
Удивило, что LuaJIT отстал даже от Internet Explorer.
Может вы как-то не в курсе, но 9-й эксплорер показывает неплохую скорость на фоне остальных браузеров.
Не хватает версий…
Версий чего? Я не понял. Если версий браузеров по сравнению с которыми IE9 показывает неплохую скорость, то вы сейчас показываете полное незнание вопроса.

Этим сравнениями весь интернет завален. Там последние версии браузеров.
Версий браузеров в топике. IE9 ещё не вышел, интуитивно предполагается что сравнивался восьмой. Отсюда и удивление.
А это?
> Участие принимали Chrome 9.0 Beta, Opera 11.01, Firefox 4.0 Beta 9, Explorer 9 Beta и LuaJIT 2.0 Beta 5.
Lua создавался как дополнительный язык и не предназначен для написание рейтрейсерор, он скорее предназначен чтобы писать расширения части приложений, например логику или задания для игры, а не полноценные приложения.
JavaScript создавался как дополнительный язык и не предназначен для написание рейтрейсерор, он скорее предназначен чтобы писать расширения части приложений, например логику или задания для игры, а не полноценные приложения.
Теперь с приходом HTML5, JavaScript хотят превратить в полноценный язык для написания Веб-приложений, и как ни странно ребятам из WHATWG это удалось.
Вы заблуждаетесь, JavaScript в WHATWG не меняли.
Зачем тогда Lua, если есть JavaScript?
Зачем язык X, если есть язык Y. Это универсальный вопрос и пытаться дать на него ответ бессмысленное занятие.
НЛО прилетело и опубликовало эту надпись здесь
Только вот незадача-то, lua на два года старше JavaScript.
НЛО прилетело и опубликовало эту надпись здесь
Если я правильно понял, то ваша фраза про «поделие времен жестокого прессинга некрософтом нетскейпа» переводится что-то вроде «в те далёкие-далёкие времена, к которым lua отношения не имеет».

Теперь оказывается, что всё наоборот и это всё равно не имеет значения. Забавно.
Он имеет ввиду, что первая версия javascript была реализован Netscape за 7 дней, без особого проектирования. Ходит такая байка.
Какая странная версия. Она противоречит всему, что я знаю об этом языке.
Странно, а везде написано, что JS создавали три человека. Исходник переведённой статьи недоступен (надо будет поискать копии), а процитированные фразы выносят мне мозг.

Например: «что-то вроде PHP, только еще хуже. Его босс Netcsape быстро «зарубил» (в июле 1995, если мне не изменяет память; я сдлелал JS в начале/середине мая), т.к. это был уже третий язык после Java и JS. Было и так трудно обосновать то, что у нас 2 новых языка программирования для web.»

Такое ощущение, что речь идёт о каком-то ещё языке, который был уже после Java и JS. О каком? Так как это выдрано из контекста, в комментариях к статье люди подумали, что это относится к JavaScript.

Я знаю, что был язык до JS, который назывался сначала Cmm, а потом стал называться ScriptEase (очень странное название, рифмующееся у меня со striptease).
> О каком?
Как я понял, о PHP. Его, PHP, босс быстро «зарубил».
Между Lua и JS есть важное отличие: Lua-программа может взаимодействовать с ОС (записывать файлы например), а также Lua-машину можно расширить любым кодом на любом языке (можно dll подключить и вызывать функции из этой dll прямо из кода на Lua). JS ограничен рамками браузера.
JS ограничен рамками браузера.
Толко если это JS в браузере :)
Потому я сейчас и собираюсь запустить тестовый код на node :)
Тестовый код из этого топика? А смысл? Нода ни чуть ни быстрее v8 в Хроме. Разве что вы перепишете часть кода на си и встроите в ноду.
Не будет постоянного вывода на экран, так что должно быть чуть быстрее.
Заодно проверю как node-canvas работает.
Как фанат языка Lua, ни за что не поверю в данные результаты, где то есть подводный камень, который всё это объясняет.
Я тоже фанат Lua и очень хочу найти этот подводный камень :) Этот рейтрейсер на Lua я написал не просто так: я хочу сделать рейстрейсер 4-х мерного пространства, а там нужна производительность хотя бы 1,000,000 RPS. Мне казалось, Lua будет в 20 раз быстрее JS, а оказалось…
Скорее всего в Lua неоптимально реализованы математические функции. Может это «исследование» позволит выявить «слабое звено» и оптимизировать LuaJIT
Рейтрейсеру нужно только уметь делать 4 арифметические операции и находить квадратный корень. Все эти пять действий вычисляются процессором, так что их не получится неоптимально реализовать. Другое дело сама среда Lua — сборщик мусора, создание новых объектов, обращения к полям таблиц — может иметь какие то особенности которых я не знаю.
Для чистоты эксперимента его нужно будет делать и для JS и для Lua.
Поможет, но когда я напишу рейтрейсер на C :) Тот хак для квадратного корня заточен под разрядность числа, а в JS я не знаю сколько бит в числах.
Это довольно сложный. Смотря в каких :) Например, любая битовая операция переводит число в integer.
Интересно что, по тестам shootout.alioth.debian.org/u64/performance.php?test=mandelbrot&sort=elapsed LuaJit лишь немногим медленнее С++. Для построения множества мандельброта тоже требуется лишь небольшое множество математических операций.
Впрочем, там похоже сильно оптимизирован алгоритм.
Проекцию из 4D в 2D? А какая там будет логика z-буфера? Или речь идет о проекции трехмерного сечения 4D?
Нет, именно всего 4D на 2D. Сделать проекцию трёхмерного среза 4D на 2D можно уже сейчас: нужно просто заменить строку vec.dim = 3 на vec.dim = 4. Получится такая картинка:

3dslice

Увидеть все 16 вершин не получится: они не лежат в трёхмерном пространстве.

Проецирование 4D я собираюсь делать в два шага: сначала спроецирую 4D на трёхмерный куб (аналог 2-мерного монитора) и затем этот куб спроецирую на плоский экран. Но делать это буду наоборот: буду выпускать лучи из камеры (то место откуда смотрит 3-мерный наблюдатель) лежащей в одном 3-мерном срезе с кубом, лучи будут проходить через куб и через точки пересечения луча с кубом я буду запускать лучи из второй камеры (глаз четырёхмерного наблюдателя) которые пересекаясь с тем 3-мерным кубом ровно в одной точке будут сталкиваться с предметами на сцене (с тессерактом). Это требует N3 лучей где N — ширина кубического монитора. Учитывая, что лучи преломляются и отражаются в среднем 300 раз, надо отрендерить 300•N3 лучей, 0.3 триллиона.
Понятно. Z-буфер будет на обеих проекциях? Или только на первой, а визуализация 3D будет полупрозрачными объектами?
Играясь с сочетаниями перспективных проекций 4D->3D->2D (точнее, я начинал даже с 5D), я обнаружил странный факт: результат можно описать формулами X=x/w, Y=y/w в подходящей прямоугольной системе координат, т.е. это будет сочетанием центральной и параллельной проекций! Но что там с z-буфером, я еще не разбирался. Кажется, роль «глубины» будет играть z-координата, вдоль которой идет параллельная проекция. Но надо смотреть подробнее.
Я может глупость спрошу, но разве в рей-трейсинг есть Z-буфер?
Может, и нет. Имелось в виду, как будут взаимодействовать объекты, проектирующиеся в одну точку: будет ли один из них перекрывать другой, и если да — в каком порядке (ведь в точку там проецируется 2D-плоскость!), или они будут как-то сливаться (как полупрозрачные облака)
Я наверно запутанно описал свою идею. Она же, но немного по другому.

Пусть у нас есть тессеракт T в 4-х мерном пространстве. Выберем трёхмерный куб M3 — монитор 4-х мерного наблюдателя. Возьмём камеру C не лежащую в трёхмерной плоскости с M3. Спроектируем T на M3 с помощью C и получим проекцию T' — она лежит внутри M3. Теперь возьмём наш двумерный монитор M2 и камеру C2 так, чтобы из этой камеры было видно через M2 проекцию T'. Спроектируем T' на M2 и получим T'' — это то что мы увидим на экране. Реализация этого алгоритма будет делать всё в обратном порядке: выпускать луч из C2, находить пересечение с T', выпускать луч из C через точку пересечения и находить пересечение с T.
Нет, эту идею я понял хорошо — я этот вариант проекции называю «трехмерной сетчаткой». Но дело в том, что как бы мы не реализовывали проекцию 4D на 2D, у нас каждой точке экрана будет соответствовать двумерная плоскость в 4D. Часть этой плоскости будет «невидимой», а остальные точки неизбежно будут как-то отсортированы по отношению «кто кого перекрывает». Например, в случае «трехмерной сетчатки» картина будет такой:
Видимая область для данной точки экрана — угол с вершиной в камере C. Границы угла будут определяться положением камеры C2 (в этом месте я не уверен). Если записать точку внутри этого угла в полярных координатах (r,a), то для двух точек (r1,a1) и (r2,a2) видимой будет та, для которой a1<a2 или (a1=a2 и r1<r2). То есть основным будет порядок по углу (проекция C2), а вторичным — порядок по дальности (проекция C).
Может быть, пересечение модели с углом и ближайшую точку можно будет найти быстрее, чем трассируя все лучи этого угла?
Еще немного смущает наличие «монитора M3». Если действовать так, как Вы описали, то получится изображение куба, «вырезанного» из некоторой трехмерной среды. Будут видны его грани, где в разрезе покажут «внутренние» детали изображения (нет, 4D-наблюдатель будет считать их внешними, но мы обычно можем видеть лишь «силуэты» того, что видит он). Это действительно соответствует замыслу? Или в идеале хотелось бы получить проекцию того, что наблюдатель увидел бы на бесконечном дисплее (со зрением, охватывающим 180 градусов)?
И есть у этого подхода серьезная проблема. Если таким образом попытаться получить изображение четырехмерной комнаты, то окажется, что по краям монитора M3 будут только изображения пола, стен и потолка, а все самое интересное будет спрятано внутри. Даже если съемка идет на открытом воздухе, то мы увидим, что часть объекта, находящаяся ниже уровня камеры «утонет» в земле (на фотографиях нашего имра мы видим, что часть тела человека находится на фоне земли, но флатландец, изучив эту фотографию, сказал бы, что человек утонул в земеле, а на поверхности торчит только голова, состоящая из волос и ушей.
Что со всем этим делать, я так и не придумал. Поэтому идею своего 4D-вьюера/редактора мне пришлось отложить на неопределенное время.
У вас может быть много пересечений, и вы ищете ближайшее.
Я планирую обойтись без Z-буфера. Визуализацию 3D пока не знаю как лучше сделать: можно сплошной (как на рисунках) а можно и полупрозрачной (будет дольше работать). Смотря как красивее получится.
Если нужна производительность, стоит обратить внимание на GPU. OpenCL или CUDA на приличной карточке гораздо лучше справятся с такой высокопараллельной задачей чем скриптовые языки.
Надеюсь, что дело в том, что LuaJIT сейчас в фазе стабилизации, а после фазы оптимизации ситуация улучшится.
Теперь бы еще сюда добавить результаты на С++, Java, C# и Phyton.
Питон? Зачем? Разве что PyPy потестить, конечно…
Для числодробилок как этот рендерер можно psyco подключить
Psyco уже сколько лет не развивают, да и PyPy, в общем-то, обогнал его уже давненько
ссылочка в тему: www.cnblogs.com/miloyip/archive/2010/07/07/languages_brawl_GI.html

там правда все по-китайски, но суть ясна и без знания китайского: человек тоже какой-то рендерер написал на куче языков; можно иероглифы пропускать и в пролетарскую суть диаграм с результатами замеров вникать ;-)
ИМХО дело в том, сколько внимания уделяют языку. JavaScript развивается динамичней ибо он востребован, под него затачиваются интерпретаторы, движки браузеров; в него вкидываются деньги на порядок больше, чем в Lua, вот и результат
Робко прошу вас задокументировать код.
Мысль очень правильная :) Я не сделал этого по одной причине: боялся, что кто-нибудь откроет файл raytracer.js, увидит там 2000 строчек какого то текста и подумает «ну вот… а говорил, что код рейтрейсера простой — а тут как обычно манускрипт на несколько экранов», хотя большая часть текста будет на самом деле комментариями. Я однажды читал исходник алгоритма BWT написанный автором DjVu (они в свободном доступе) — там столько текста, что… Но если выкинуть комментарии, то окажется, что кода совсем немного.

Мне не сложно прокомментировать: напишите только список файлов в которых вы хотите увидеть комментарии.
Да вроде всё понятно. Просто нужно было догадаться, что в этих языках так объекты выглядят. :)
raytracer.lua и screen.lua.

И в методе vec.vec похоже происходит что-то простое, но лень читать две страницы кода на lua когда вы это одним предложением по-русски можете сказать :)
vec.vec это векторное произведение в n-мерном пространстве. Для трёхмерного случая есть простая формула, а в общем случае это считается через определитель. Определитель можно найти методом Гаусса.
Прошу прощения за назойливость, но когда можно ожидать комментарии?
Я не заметил ваш комментарий, извиняюсь. Отправьте мне свой e-mail через ЛС и я отправлю вам эти два файла с комментариями. Обновлять zip архив не хочу, потому что я у себя что то менял в коде и сейчас bmp файлы пишутся неправильные, а разбираться в этом сейчас нет времени.
вы бы еще на перле написали и пнули тушку попугая…
Perl, увы, не знаю. Это функционально-процедурный язык как JS? Есть ли там компилятор, по типу JS V8 или LuaJIT?
НЛО прилетело и опубликовало эту надпись здесь
chrome9 (32b) — 16556
luajit-2.0.0-beta5 (64b) — 8881
luaj не смог запустить, org.luaj.vm2.LuaError: cubecyl.lua:37: attempt to index? (a nil value)
osx 10.6/core2duo 2.53
Node.js+node-canvas в среднем чуть медленнее, но не больше 5%.
GC: 9.0.597.84 beta
Node: v0.3.7
node-canvas: 0.4.3
Intel Core i5 750, 2.67GHz
Windows 7 Ultimate

chrome9 (9.0.597.84) — 22129
luajit-2.0.0-beta5 — 23946

изменения в коде луа:
— все вызовы глобальных функций переделаны на вызов локальных функций:
local bitband, bitlshift = bit.band, bit.lshift
— понижена цикличность сборки мусора
collectgarbage(«setpause», 600)

Впечатляет. Я ещё заметил, что Lua тратит много времени на заполнение массива в screen.render:

this.pixels[index] = color


Если убрать эту строчку, а также вывод процентов через io.write, то скорость возрастает более чем в три раза. Надо заметить, что для JS это не важно: там вывод на экран и сохранение пикселей не влияет на скорость. Как сказать Lua, что this.pixels это массив фиксированной длины?..
Впечатляет. Я ещё заметил, что Lua тратит много времени на заполнение массива в screen.render:

this.pixels[index] = color


трудно сказать в чем дело, но если заменить эту строчку на
this.pixels[index] = index


то RPS увеличивается до 41491

Или снова сборщик мусора, или не совсем оптимальный алгоритм хеширования в таблице.
или JIT выкидывает часть вычислений — color-то теперь никуда не утекает ;-)
все вызовы глобальных функций переделаны на вызов локальных функций


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

понижена цикличность сборки мусора


да, встроенный GC в Lua при «мусора много и мрет он молодым» ведет себя хуже GC V8.
если вы действительно все вызовы заменяли, то ради чистоты эксперимента следовало бы аналогичную операцию и с JavaScript проделать.


Запустил Lua тест с оригинальными файлами без локальных функций. Изменений особых нет +- пару процентов.

да, встроенный GC в Lua при «мусора много и мрет он молодым» ведет себя хуже GC V8.


Да, сборка мусора в хроме отменная: скрипт добирается до 200Мб, потом через несколько секунд чистит мусор до 96мб, и снова увеличивается в размере. Насколько я помню, в v8 сборщик многопоточный, видимо тут выигрыш.
С луа все гораздо хуже: если шаг сборки 600, то сборщик видимо вообще не срабатывает, кушая 500мб. Если шаг 300, то потребление памяти медленно растет до 230 мб.
Запустил Lua тест с оригинальными файлами без локальных функций. Изменений особых нет +- пару процентов.


Т.е. если функции вызывать глобально, а сборку мусора отложить, то получается быстро?

Ага! Ну я так и думал, что в GC дело. От LJ2 следует ожидать, что он сам поднимет загрузку глобалов (load hoisting). На обычных числодробилках даже Crankshaft (V8 после 3.0) к LuaJIT2 вроде не подобрался пока, я уж не говорю о классическом бэкенде (V8 до 3.0).

Насколько я помню, в v8 сборщик многопоточный


Нет, он однопоточный (точнее они, для частичных сборок в молодом поколеннии копирующий scavenger, для полных сборок — MarkSweep/MarkCompact). Ну и пауза в несколько секунд — это, м-м-м-м, не сказать что бы отменный сборщик :-)
Участие принимали Chrome 9.0 Beta


Хм. А ведь это с V8 2.5.x, т.е. без Crankshaft, т.е. без серьезной адаптивной компиляции.

Как бы не оказалось, что тут все упирается исключительно в GC.
Если быть более точным, я использовал 9.0.597.86 beta. Хром говорит, что это последняя версия. Где то есть ещё более продвинутая бета?
Нет, беты нет.

Есть Chrome 10 Dev, которая вот-вот пойдет в бету.
Неплохо.
9.0.597.84: 15150
10.0.648.18: 21590
Если вы перепишите код на С++ то я готов помочь портировать на C# для Silverlight (WriteableBitmap) и WinForms (GDI+).
Очень интересно сравнить скорость.
Договорились :)
Я бы не догадался написать «a = ffi.new('double[?]', ...)» вместо «a = {}». Это какая то фича LuaJIT — в документации Lua я такого не встречал. Вообще было бы неплохо, если бы Mike написал подобные простые сценарии кода.

Я могу дать ему инвайт, если он захочет зарегистрироваться.
Да, это фича LuaJIT 2, начиная с beta6. См. luajit.org/ext_ffi.html и соседние топики в меню слева.

Майк сожалеет, но у него сейчас недостаточно времени, чтобы отвечать на Хабре.

Он читает письма и отвечает на вопросы в официальной рассылке Луа (на английском): www.lua.org/lua-l.html

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

Hello Mike,

Today I suddenly found from agladysh that you know about my simple raytracer and you even analysed my code. You found that the code produces lots of temporary objects (that become garbage almost immediately after creation) and that the code dynamically inserts pixels to a Lua-table. These two things make the program extremely slow. Almost exactly the same code I've written in JavaScript — it also produces lots of temporary objects and inserts pixels one-by-one to an array — and this code appeared much faster under Chrome than the Lua code under LuaJIT.

You offered a simple solution: to replace the standard and simple array «pixels = {}» with a special array «pixels = ffi.new(...)». Your solution makes the program much faster — even faster than JS under Chrome. But from this point we're comparing not JS and Lua but JS and Lua+LowLevelFeatures. To make the comparsion correct, we must allow to use in JS features like WebGL and that'd make the comparsion meaningless — I didn't want to know what is faster WebGL or FFI.

It'll be more honestly to rewrite the Lua code so as it'll not create tons of objects with short life, but this thing must be done in both Lua and JS code and it's unclear who will appear faster: LuaJIT or JS V8.

ankh1989@habrahabr.ru
Рекомендую всё-таки отправить этот ответ в луашную рассылку. Иначе очень странная переписка получится :-)
спасибо за вашу статью!
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории