воскресенье, 23 ноября 2014 г.

asm.js vs plain c performance test

Много читал в разных местах про asm.js как утилиту, позволяющую портировать обычный код С/С++ в нечто, что можно вставить в веб-страницу и оно там будет работать без каких-либо дополнительных усилий со стороны браузера (не нужно ставить никаких плагинов, расширений и проч.), достаточно просто поддержки javascript, которая сегодня есть у всех популярных браузеров.
 
asm.js - это, по сути, обычный javascript, который активно используется в вебе. Подмножество javascript, если быть более точным. Больше ответов на другие вопросы на официальной странице и странице компилятора.

Очень захотелось лично попробовать это. Наваял небольшую программу:

#include "md5.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
 
int main()
{
    time_t t1;
    time(&t1);
    const unsigned int dataSize = 1024 * 1024 * 30;
    unsigned char * data;
    data = (unsigned char*) malloc (dataSize);
 
    srand((unsigned int) t1);
    for(int i = 0; i < dataSize; i++)
    {
        data[i] = rand() % 255;
    }
 
    MD5_CTX mdContext;
    for(int i = 0; i < 100; i++)
    {
        MD5Init(&mdContext);
        MD5Update(&mdContext, data, dataSize);
        MD5Final (&mdContext);
    }
 
    free(data);
 
    time_t t2;
    time(&t2);
 
    const double seconds = difftime(t2, t1);
    printf ("\n%3.2f seconds", seconds);
 
 
    return 0;
}

Что мы тут делаем. Выделяем кусок памяти в 30 мегабайт, заполняем его случайными числами, а потом 100 раз вычисляем хеш этого массива, освобождаем память. Сначала запустил как обычную консольную программу, а потом скомпилировал в html-файл, который открыл в chrome и firefox.

.pro-файл консольного приложения:
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
QMAKE_CFLAGS_RELEASE += -O3 -std=c99
SOURCES += main.c


Скрипт для компилирования html-страницы:
emcc -o2  main.c  -o md5.html -s TOTAL_MEMORY=40000000 

В скрипте параметр TOTAL_MEMORY указывает сколько памяти может потребить скрипт. С этим параметром надо обращаться осторожно и не указывать слишком больше число "про запас", без необходимости.
Файл md5.h я взял здесь.

Результаты:
console app: 14 sec, 31MB RAM
firefox: 36 sec,
chrome: 58 sec, 71 MB RAM

Обращает на себя внимание, что chrome работает заметно медленнее firefox. А последний не так радикально медленнее "чистого" си - всего в 2.5 раза. Потребление памяти тоже любопытно. Консольная программа ожидаемо заняла около 31 мегабайта памяти, страница chrome заняла 71 мегабайт. Всего в 2 раза больше, чем консольная. По-моему, очень и очень неплохо. Стоит сказать большое спасибо тем, кто создал и оптимизировал emscripten до такой степени, что javascript проигрывает C в быстродействии всего лишь в 2-4 раза и в потреблении памяти в 2 раза. Это делает возможным проивзодить некоторые достаточно тяжелые вычисления прямо на веб-странице, в браузере клиента.