Страницы

Поиск по вопросам

суббота, 28 декабря 2019 г.

Что быстрее: динамическое выделение памяти vs массив, Windows 7 vs Linux

#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 (стек значительно медленнее кучи, тогда как в других тестах время примерно равно).

Комментариев нет:

Отправить комментарий