#windows #память #оптимизация #cpp #linux
Написан тест для измерения скорости между динамическим выделением памяти и использованием массива, а также между Windows 7 64 разрядная и Linux 64 разрядный под виртуальной машиной. struct Point { int x; int y; }; int fff0 (int n) { Point* p = new Point [n]; for ( int i = 0; i < n; ++i) { p[i].x = i; p[i].y = i; } int i = p[n-1].y; delete [] p; return i; } int fff1 (int n) { Point p[65536]; for ( int i = 0; i < n; ++i) { p[i].x = i; p[i].y = i; } int i = p[n-1].y; return i; } void test() { int nn[5][2]; // время вызовов отдельных функций int all; // общее время выполнения int n = 100000; int m[5] = {10, 100, 1000, 10000, 65536}; time_calc tc, tc_all; tc_all.begin(); for ( int j = 0; j < 5; ++j ) { tc.begin(); for ( int i = 0; i < n; ++i ) fff0(m[j]); nn[j][0] = tc.get(); tc.begin(); for ( int i = 0; i < n; ++i ) fff1(m[j]); nn[j][1] = tc.get(); } all = tc_all.get(); } time_calc реализован с помощью: Win Linux QueryPerformanceCounter ftime Результаты: - время выполнения отдельных вызовов new ( fff0 ) p[65536] ( fff1 ) win linux win linux 10 5 5 10205 5 100 27 11 10156 14 1000 232 27 10440 48 10000 2295 204 13265 395 65536 15344 1301 30323 2547 общее время выполнения: win linux 74392 3010 Собственно 2 вопроса: 1. Почему динамическое выделения быстрее использования массива, хотя используется new и delete? Почему Linux быстрее Windows 7? PS. И там и там используется релизная версия с оптимизацией по скорости.
Ответы
Ответ 1
Тестируя скорость выделения памяти в варианте p[65536]; вы на самом деле тестируете скорость цикла. Если посмотреть отладчиком, то это выделение - это просто изменения указателя стека (в разных реализациях может быть немножко по разному, но в целом - это просто изменения одного регистра). Это операция на несколько тактов процессора. Разделив время на кол-во элементов для линукс версии видно, что оно прямопропорционально для случаев больше 1000 (что и не удивительно - меряем то цикл). Для маленьких циклов упираемся в точность измерения и накладные расходы. В windows варианте видимо просто накладные расходы немного больше. В целом, все варианты тестируют скорость цикла, только win вариант с выделением на стеке выделяется. Нужно смотреть в код. Почему динамическое выделения быстрее использования массива, хотя используется new и delete? а мы не выделение памяти тестируем, а скорость прохода по циклу. Но в случае с динамическим выделением возможно компилятор выбрал более удачных алгоритм прохода (скорее всего данные были выровнены по границе кратной 16 и все работало значительно быстрее). Почему Linux быстрее Windows 7? у Вас тестирование различное. Одно тестируете на реальной машине, а другое на виртуальной. Тестируйте в одних условиях. Известно, что виртуальные машины иногда корректируют виртуальные системные таймеры, что может сильно искажать результаты тестирования. upd если компилировать fff1 с помощью gcc с параметром O3, передавая константу и не запрашивая результат, то компилятор вообще ее выбрасывает:) Компилятор далеко не такой простой.Ответ 2
@atropin, по моему Вы просто где-то с подсчетом времени в Linux на порядок ошиблись. Кстати, какой у Вас CPU (вряд ли на порядок быстрее, чем у меня)? Вы пишете, что вызываете ftime() и судя по всему приводимые Вами цифры это время в миллисекундах. Я прогнал Ваш тест у себя model name : Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz и (по моим замерам) получил такие результаты: Windows 7 (gcc, g++ 3.4.5 (mingw-vista special r3)) c:/Users/avp/src/cc/hashcode $ g++ memtime.c c:/Users/avp/src/cc/hashcode $ ./a Windows g++ (msec) N stack heap 10 37 106 100 51 119 1000 310 374 10000 2888 3002 65536 28276 18728 Total: 53892 msec c:/Users/avp/src/cc/hashcode $ gcc -std=gnu99 memtime.c c:/Users/avp/src/cc/hashcode $ ./a Windows gcc (msec) N stack heap 10 24 102 100 48 126 1000 308 371 10000 2902 2886 65536 28030 18433 Total: 53230 msec c:/Users/avp/src/cc/hashcode $ g++ memtime.c -O3 c:/Users/avp/src/cc/hashcode $ ./a Windows g++ (msec) N stack heap 10 24 1 100 32 8 1000 105 83 10000 843 819 65536 14540 5264 Total: 21719 msec c:/Users/avp/src/cc/hashcode $ gcc -std=gnu99 memtime.c -O3 c:/Users/avp/src/cc/hashcode $ ./a Windows gcc (msec) N stack heap 10 21 1 100 30 8 1000 102 83 10000 863 832 65536 14522 5265 Total: 21727 msec c:/Users/avp/src/cc/hashcode $ Linux Виртуальная машина VirtualBox 4.2.10 Linux avp-ubu1 3.2.0-39-generic #62-Ubuntu SMP Thu Feb 28 00:28:53 UTC 2013 x86_64 GNU/Linux (gcc g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3) avp@avp-ubu1:~/hashcode$ gcc -std=gnu99 memtime.c avp@avp-ubu1:~/hashcode$ ./a.out Linux gcc (msec) N stack heap 10 12 15 100 66 87 1000 358 306 10000 3016 3125 65536 20362 20595 Total: 47942 msec avp@avp-ubu1:~/hashcode$ g++ memtime.c avp@avp-ubu1:~/hashcode$ ./a.out Linux g++ (msec) N stack heap 10 14 15 100 71 90 1000 353 329 10000 3267 3191 65536 20714 21119 Total: 49163 msec avp@avp-ubu1:~/hashcode$ g++ memtime.c -O3 avp@avp-ubu1:~/hashcode$ ./a.out Linux g++ (msec) N stack heap 10 7 3 100 28 21 1000 137 92 10000 851 911 65536 5599 5990 Total: 13639 msec avp@avp-ubu1:~/hashcode$ gcc -std=gnu99 memtime.c -O3 avp@avp-ubu1:~/hashcode$ ./a.out Linux gcc (msec) N stack heap 10 7 2 100 34 16 1000 125 62 10000 878 646 65536 5644 4845 Total: 12259 msec avp@avp-ubu1:~/hashcode$ Для того, чтобы оптимизатор не выбрасывал тестируемый код, я в нескольких местах добавил volatile. Время во всех случаях брал функцией gettimeofday() и пересчитывал в long long в миллисекунды с отбрасыванием их тысячных долей. Результаты очевидно ближе к интуитивно ожидаемым. Пожалуй несколько странным (точнее, для меня необъяснимым (а смотреть ассемблерный код просто лень)) выглядит результат в винде для N = 65536 (стек значительно медленнее кучи, тогда как в других тестах время примерно равно).
Комментариев нет:
Отправить комментарий