Monday, March 10, 2008

Кривость alglib? - нет. кривость рук...

Часто пользуюсь библиотекой alglib.
И вот переписал я сегодня одну программу с шарпа на плюсы - работать стало медленней на порядки. В обоих вариантах использовал модуль решения ду из alglib.
Замерил скорость отработки 10^6 шагов по рунгекутту там и там:
плюсы 24.5 сек
шарп 0.5 сек
Списываю это на кривость транслятора из algoPascal в alglib. Но надо конечно разбираться...

добавлено:
Поразбирался. Нашлось множество подводных камней, и наверное еще далеко не все.
Первое что сделал - избавился от массивов alglib. Не помогло. Изначально казалось, что вся проблема должна быть в алглибе и его надстройке в виде массивов, которые нумеруются с 1, а не с нуля. Однако, переход на обычные double[] ничего не дал.
Главная причина тормозов оказалась весьма тупа. Надо было включить оптимизацию /Ox и запускать не из IDE (из-под ide работает в разы медленнее).
Потом выяснилось еще, что точность DateTime.Now оставляет желать лучшего. Заменил на Stopwatch.
Написал тестовые примеры для замера скорости:
1) на шарпе


int rep = 1000000;
double d = 0;
for (int i = 0; i < rep; i++)
{
int arrLen = 100;
double[] arr = new double[arrLen];
for (int j = 0; j < arrLen; j++)
arr[j] = j;
for (int j = 0; j < arrLen; j++)
d += arr[j];
}


2) и на плюсах:

double d = 0;
for (int i = 0; i < rep; i++)
{
double* arr = new double[size];
for (int j = 0; j < size; j++)
arr[j] = j;
for (int j = 0; j < size; j++)
d += arr[j];
delete[] arr;
}

Однако, и этого мало. По прежнему код на шарпе работал быстрее на 40%. Полез искать в инете, как можно оптимизировать код на плюсах. На rsdn нашел такой совет:
заменить

double* arr = new double[size];
for (int j = 0; j < size; j++)
d += arr[j];

на

double* arr = new double[size];
double* iter = arr;
double* endIter = arr + size - 1;
int j = 0;
iter = arr;
while (iter < endIter)
{
d += *iter;
iter++;
}

если я все правильно понял, то авторы этого совета ошиблись у себя забыв, что нумерация массива идет от нуля. поэтому endIter = arr + size - 1, а не arrIter = arr + size. хороший пример преимущества шарпа - на надо мучить мозги ерундой.
такая замена дала прирост производительности на 10%, но до сих пор обогнать шарп у меня не получилось.

добавлено:
видимо кривизна моих рук не знает границ. я пока плюнул на выяснение причин почему у меня так медленно работает код на плюсах. основная причина почему плюнул - меня забеспокоил тот факт, что код, запущенный из vs работает сильно медленнее, чем просто запущенный бинарник. мне в основном приходится постоянно что-то менять в коде и зачастую запускать расчеты из среды. ну и просто трудозатраты на написания кода на плюсах удручает. становится особенно печально, если приходится искать ошибки в чужом коде, как например утечки памяти в компоненте отрисовки графиков.
короче я сдался и решил перенести код не на плюсы, а на шарп. по крайней мере на первый взгляд трудозатраты по переходу на шарп кажутся настолько меньшими по сравнению с плюсами, что можно это сделать просто прикола ради :-)

2 comments:

invisible said...

Из своего опыта знаю, что скорость работы ++ и # зависит от компилятора. Пробуй запустит тот же код в другом компиляторе плюсов. Производительность может заметно возрасти. По умолчанию на # работать быстрее не может.

invisible said...

И кстати сказать, есть такой зверь, как GSL. Под винду есть тоже его реализация. Я его уже второй год использую - пока доволен и скоростью и количеством функций.