Comments 43
Если я правильно понял, у вас немного перепутано количество знаков в конечной статистике. Сейчас выглядит как будто на порядок время лучше, на самом деле (если я правильно понял), всего на 3 секунды лучше (сравнивать надо первую и последнюю — они для 10^7 знаков, результат в 1.8с — для 10^6).
0
Результат мягко говоря впечатляет
+1
Чё-то как-то технология asm.js выглядит сыроватой.
+4
Не могу не согласиться) По-моему в этот язык инвестировала мозилла с целью использования своей платформы, как игровой. Поэтому есть emcc, чтобы компилить обычный сишный код в asmjs. Поэтому и WebGL + asm.js. А где игры, там и юзеры)
0
Да, asm.js конечно это костыль костылем, но надеюсь, что в него смогут компилироваться другие языки и не надо будет его дополнительно изучать.
0
У меня ощущение, что asm.js разработал skynet, чтобы люди не смогли понять когда их начнут захватывать.
А по делу, интересно конечно узнать из первых рук, что это такое, хоть и не понятно как программистское сообщество до такого докатилось.
За статью спасибо.
А по делу, интересно конечно узнать из первых рук, что это такое, хоть и не понятно как программистское сообщество до такого докатилось.
За статью спасибо.
+3
Насколько я знаю, asm.js сделан для трансляторов с других языков и не предназначен к тому, чтобы на нём руками писали.
+5
В этой статье мы видели пример того, как пришлось напрямую писать на asm.js. Кроме того есть куча библиотек, которые захотят улучшить производительность в критических местах. Им же не переходить ради этого на другие языки. Поэтому в результате получится, что очень многим программистам придется напрямую копаться в таком коде.
0
Ну да. Я, вот, программирую на Си время от времени. А когда хочется улучшить производительность, я лезу в Ассеблер и не ною на синтаксис.
0
Я бы сказал, что синтаксис простого ассемблера более читабелен. И здесь не было никаких проблем сделать синтаксис основанный, например, на неком наборе функций, который был бы понятен и людям.
А ещё один вариант — аннотации.
В общем, тут есть свобода для более красивой реализации.
А ещё один вариант — аннотации.
В общем, тут есть свобода для более красивой реализации.
0
asm.js сделан так, чтобы код мог интерпретироваться браузером без поддержки asm.js, просто с меньшей скоростью. Это исключает поддержку функций.
0
Не то чтобы совсем исключает. Просто нужну было бы подключать библиотеку с функциями заглушками и это бы особо не тормозило браузеры без поддержки asm.js.
А вариант с аннотациями точно был бы немного быстрее (опять же без поддержки asm), т.к. не приходилось бы интерпритировать/оптимизировать кучу странных конструкций. Плюс к этому не нужно было бы вспоминать, что (1|0) — это int, т.к. можно было бы написать
/*int*/ var i = 1 или
var i = /*int*/ 1
Если добавить сюда вывод типов (не знаю, реализованно ли это сейчас), то избыточность была бы минимальной.
А вариант с аннотациями точно был бы немного быстрее (опять же без поддержки asm), т.к. не приходилось бы интерпритировать/оптимизировать кучу странных конструкций. Плюс к этому не нужно было бы вспоминать, что (1|0) — это int, т.к. можно было бы написать
/*int*/ var i = 1 или
var i = /*int*/ 1
Если добавить сюда вывод типов (не знаю, реализованно ли это сейчас), то избыточность была бы минимальной.
0
Сам долго думал что же мешало сделать в таком виде. И нет ответа.
К тому же эти перепрыгивания типов fixnum->int->intish->signed вообще выглядят магически.
К тому же эти перепрыгивания типов fixnum->int->intish->signed вообще выглядят магически.
0
Во-первых, комментарии не для этого. Не дело их трогать.
Во-вторых, это чересчур многословно. Просто кошмар.
В-третьих, переходы между типами сделаны, чтобы всё работало эквивалентно движкам без asm.js, только быстрее.
И, кстати, не нужно вспоминать, что variable|0 — это int, это просто надо знать. В обычном JS variable|0 тоже даёт int, это же известный приём, попробуйте.
Во-вторых, это чересчур многословно. Просто кошмар.
В-третьих, переходы между типами сделаны, чтобы всё работало эквивалентно движкам без asm.js, только быстрее.
И, кстати, не нужно вспоминать, что variable|0 — это int, это просто надо знать. В обычном JS variable|0 тоже даёт int, это же известный приём, попробуйте.
-1
Ещё скажите, что +'123' даст мне 123)
1) ну команда |0 тоже не для того была придумана, чтобы создавать эквивалент int i, а скорее изначально это… = (int) i; т.е. приведение типов.
2) ну вообще говорить о многословности, когда есть популярное объявление вида public static int, например… В общем на 4 символа больше, зато очевиднее.
3) тут вы не правы) Переходы между типами в обычном js есть и так. Т.е. если мы убираем все эти трансформации в фикснум, инт, сигн и назад получаем… Рабочую версию. Они зачем-то нужны компилятору, но зачем вопрос остался)
Комментарии имеют только одно тонкое место, которое я вижу: минификаторы) Они их просто вырежут и вот снова фигскомпилишь язык на выходе)
1) ну команда |0 тоже не для того была придумана, чтобы создавать эквивалент int i, а скорее изначально это… = (int) i; т.е. приведение типов.
2) ну вообще говорить о многословности, когда есть популярное объявление вида public static int, например… В общем на 4 символа больше, зато очевиднее.
3) тут вы не правы) Переходы между типами в обычном js есть и так. Т.е. если мы убираем все эти трансформации в фикснум, инт, сигн и назад получаем… Рабочую версию. Они зачем-то нужны компилятору, но зачем вопрос остался)
Комментарии имеют только одно тонкое место, которое я вижу: минификаторы) Они их просто вырежут и вот снова фигскомпилишь язык на выходе)
+1
На счет комментариев и минификаторов только добавлю, что выход есть и тут. Либо все аннотации начинать со спец. символа (как например в java @), чтобы минификаторы понимали, что их не нужно вырезать. Либо же аннотации были бы все описаны в стандарте и минификаторы опять же могли смотреть, что вырезать, а что нет.
0
На счет многословности могу сказать только одно. Она предотвращает огромное количество ошибок. И как я сказал уже, если добавить выведение типов по Хиндли-Милнеру, то останется только самое необходимое. Но даже без него оверхед по сравнению с текущим синтаксисом процентов на 50%, что прямо скажем не кошмар.
0
Спасибо! У меня есть несколько вопросов:
1. Как сделать то же самое с помощью Emscripten?
2. Можно ли вызывать Asm.js функции из обычных JS функций?
3. Как определить, понимает ли браузер Asm.js (не в режиме совместимости)?
1. Как сделать то же самое с помощью Emscripten?
2. Можно ли вызывать Asm.js функции из обычных JS функций?
3. Как определить, понимает ли браузер Asm.js (не в режиме совместимости)?
0
1, Как компилировать код в asm.js вроде написано, поэтому берём pi.c и emcc pi.c -o pi.js. Но как с этим работать не разбирался пока что.
2. Да, вы можете вернуть из модуля объект с функциями. Тут, например можно в конце модуля написать
return {
series: series,
expm: expm
}
и потом в функциях js обращаться как к прочим методам (например в данном случае было бы series.series(...) or series.expm(...))
3.Озадаченный этим вопросом я так и не нашёл ответа, кроме разве что по-дурацки проверить время работы функции. В консоль в FF выводится «Error: successfully compiled asm.js code». Но никакие ухищрения не помогли мне вытащить эти заветные слова.
2. Да, вы можете вернуть из модуля объект с функциями. Тут, например можно в конце модуля написать
return {
series: series,
expm: expm
}
и потом в функциях js обращаться как к прочим методам (например в данном случае было бы series.series(...) or series.expm(...))
3.Озадаченный этим вопросом я так и не нашёл ответа, кроме разве что по-дурацки проверить время работы функции. В консоль в FF выводится «Error: successfully compiled asm.js code». Но никакие ухищрения не помогли мне вытащить эти заветные слова.
+1
3. testASM.js и testASM.min.js см апдейт.
+1
Т.е. там время выполнения проверяется?
0
Да. Увы иначе только если грубо браузерное имя и версию) Но в сумме эта проверка и 70мс не займёт, так что если нужно, (а бывает ну очень нужно) подождать) А вот как поступать потом дело ваше)
0
Ваш код на FF Nightly не проходит asm.js-верификацию c сообщениями типа
(надо писать
А теперь внимание, сюрприз, производительность при этом у него не страдает. Как следствие, если взять и аккуратно переписать этот код на простой человеческий JavaScript получим ту же самую производительность и читаемый код
Как из всего этого следует вывод? Без надобности тут вам asm.js.
Это, впрочем, и из кода видно — нет там ничего такого, что вменяемый JIT не осилил бы оптимизировать самостоятельно, без назойливых ручных
[12:43:56.056] TypeError: asm.js type error: non-expression-statement call must be coerced @ pi.js:91
(надо писать
+floor
, +pow
везде) А теперь внимание, сюрприз, производительность при этом у него не страдает. Как следствие, если взять и аккуратно переписать этот код на простой человеческий JavaScript получим ту же самую производительность и читаемый код
[13:02:08.076] Error: successfully compiled asm.js code (total compilation time 0ms) @ pi.js [13:02:08.084] "pi (asm.js) start" [13:02:30.776] "{"hex":"7AF5863EFF","fraction":1.4803089050105553}" [13:02:30.776] "pi (asm.js) took 22692 ms." [13:02:30.786] "pi (pure JS) start" [13:02:51.523] "{"hex":"7AF5863EFF","fraction":1.4803089050105553}" [13:02:51.523] "pi (pure JS) took 20736 ms."
Как из всего этого следует вывод? Без надобности тут вам asm.js.
Это, впрочем, и из кода видно — нет там ничего такого, что вменяемый JIT не осилил бы оптимизировать самостоятельно, без назойливых ручных
|0
и +foo
+1
Да, на счёт +floor читал, но у меня не ночная, так что увидев, что работает, решил, что атавизм)
Какое число переданно в пи? Хэша 7AF5863EFF нет ни на 100 000 ни на 10 000
Сейчас перепроверил, вот взял ваш код и ничегошеньки не менял, 71,5 сек от 1'000'000.
и мой итог 1,9 сек от 1'000'000
Какое число переданно в пи? Хэша 7AF5863EFF нет ни на 100 000 ни на 10 000
Сейчас перепроверил, вот взял ваш код и ничегошеньки не менял, 71,5 сек от 1'000'000.
console
— [01:34:18.041] console.time('njs');
console.dir(pi(1000000));
console.timeEnd('njs');
[01:34:18.045] undefined
[01:34:18.046] njs: таймер запущен
— [01:35:29.505] [object Object]
[01:35:29.506] njs: 71459.41мс
console.dir(pi(1000000));
console.timeEnd('njs');
[01:34:18.045] undefined
[01:34:18.046] njs: таймер запущен
— [01:35:29.505] [object Object]
[01:35:29.506] njs: 71459.41мс
и мой итог 1,9 сек от 1'000'000
console
— [01:38:17.177] console.time('asmjs');
console.dir(pi(1000000));
console.timeEnd('asmjs');
[01:38:17.180] undefined
[01:38:17.181] asmjs: таймер запущен
[01:38:19.050] [object Object]
[01:38:19.050] asmjs: 1868.46мс
console.dir(pi(1000000));
console.timeEnd('asmjs');
[01:38:17.180] undefined
[01:38:17.181] asmjs: таймер запущен
[01:38:19.050] [object Object]
[01:38:19.050] asmjs: 1868.46мс
0
Число переданное в функцию: 10000000
Кстати походу FF замедляет нормальные функции (гонит их только на интерпретаторе?) если их выполнять прямо из консоли.
Я выполнял из контекста страницы (добавил в конец JS файла)
Кстати походу FF замедляет нормальные функции (гонит их только на интерпретаторе?) если их выполнять прямо из консоли.
Я выполнял из контекста страницы (добавил в конец JS файла)
function measure(name, f) {
console.log(name + " start")
var start = Date.now();
var result = f(10000000);
var end = Date.now();
console.log(JSON.stringify(result));
console.log(name + " took " + (end - start) + " ms.");
}
measure("pi (pure JS)", pi);
0
Судя по всему 10 000 000, но что-то тут не так, ваш код на 10^7 я просто даже боюсь запускать. Даже на шестом порядке больше минуты. Ваше pure точно pure?
0
Точно pure. Замеряно на FF Nightly и Chrome Dev Channel на Mac Book. Но замер запущен не из консоли, а из самого JS скрипта.
0
Перепроверил, правда ваша, разница не столь разительна, всего 75% асм от чистого. Интересно, конечно, почему так, ну что же, коварная консоль)
Два урока сразу: и по asm.js, и методы проверки надо проверять)
Два урока сразу: и по asm.js, и методы проверки надо проверять)
0
у меня вообще разницы нет (asm.js на самом деле чуть медленнее) в FF Nightly, какая у вас версия FF?
Про консоль я выясню у Мозиловцев.
Интересно, конечно, почему так, ну что же, коварная консоль)
Про консоль я выясню у Мозиловцев.
0
FF 23 из репы федоры.
Больше всего меня удивило, что скомпилированная программа паботает дольше asm.js-а.
Больше всего меня удивило, что скомпилированная программа паботает дольше asm.js-а.
0
А как вы эту программу собирали? Допустим если я собираю как
то особой разницы не вижу
$ gcc -o pi -O3 -m32 -msse4 -mfpmath=sse pi.c
то особой разницы не вижу
$ time ./pi position = 10000000 fraction = 1.480308905010555 hex digits = 7AF5863EFF ./pi 10000000 20.38s user 0.01s system 99% cpu 20.391 total
0
Интересно, а в чём смысл этих магических сдвигов индекса в массиве на 3 бита? Это что, способ декларации типа такой? Типа, если 3 — то индекс целочисленный?
0
смысл очень простой: asm.js вырос из emscripten, который фактически компилирует LLVM биткод в JS. Биткод работает с указателями и сырой памятью, но в JS указателей нет, поэтому память эмулируется типизированными массивами, которые все указывают на один и тот же
Теперь если представить что
Отсюда и требование на сдвиг — это деление на размер элемента в преположении что остальное это «адрес», потому что emscripten всегда такой код рожает. В рукописном коде выглядит, конечно же, сюрреалистично
ArrayBuffer
, а указатели эмулируют целочисленной переменной. При этом поддерживается только правильно выравненные указатели, т.е. int16
должен быть выравнен на 2 байта, а int32
— на 4 байта и так далее. Теперь если представить что
i
— это правильно выравненный указатель на double
, то как прочитать double
по «адресу» i
? Надо взять Float64Array
представление кучи и прочитать из него элемент с индексом (i / 8)
(double
занимаем 8 байт). Отсюда и требование на сдвиг — это деление на размер элемента в преположении что остальное это «адрес», потому что emscripten всегда такой код рожает. В рукописном коде выглядит, конечно же, сюрреалистично
+2
А реально ли прямо в браузере интерпретировать классический код на С++ (начиная с #include ...)? И если да, реально ли в нём обращаться к функциям из javascript-библиотек?
0
Sign up to leave a comment.
Asm.js практика