С++ Array vs Vector описание теста производительности

Чтобы количественно оценить разницу в производительности C-подобного массива и векторов в С++, я написал эту небольшую программу. https://github.com/rajatkhanduja/Benchmarks/blob/master/C%2B%2B/vectorVsArray.cpp

Чтобы сравнить их по общим основаниям, я решил проверить как случайный, так и последовательный доступ. Я добавил итераторы, чтобы просто сравнить их (но это не тот вопрос, на который стоит обратить внимание).

Результаты для 64-разрядной машины Linux с 7,7 ГБ оперативной памяти с размером массива/вектором 1 млн. являются следующими: -

  • Время записи в массив.: 12.0378 мс
  • Время, затраченное на чтение из массива последовательно.: 2.48413 мс
  • Время, затраченное на чтение из массива случайным образом.: 37.3931 мс
  • Время, затраченное на запись в динамический массив.: 11.7458 мс
  • Время, затраченное на чтение из динамического массива последовательно.: 2.85107 мс
  • Время, затраченное на чтение из динамического массива случайным образом.: 36.0579 мс
  • Время, затраченное на запись в вектор с использованием индексов.: 11.3909 мс
  • Время, затраченное на чтение из вектора с использованием индексов, последовательно.: 4.09106 мс
  • Время, затраченное на чтение из вектора с использованием индексов, случайным образом.: 39 мс
  • Время, затраченное на запись в вектор, используя итераторы.: 24.9949 мс
  • Время считывания с вектора с использованием итераторов.: 18.8049 мс

Размер вектора устанавливается во время инициализации и не изменяется, поэтому нет изменения размера вектора (утверждение в программе помогает проверить это). Времена не включают времена инициализации любого из статически выделенного массива, динамически распределенного массива или вектора.

Согласно статистике, время записи в вектор меньше, чем у массива, но время для чтения из вектора в два раза больше, чем у массива.

Разница довольно маленькая, но есть ли объяснение, почему существует разница в производительности? Что-то не так с тестом? Я ожидал, что оба выйдут с такой же скоростью. Повторение этого теста показывает ту же тенденцию.

Код:

#include <vector>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <sys/time.h>
#include <cassert>

#define ARR_SIZE 1000000

using std::string;

void printtime (struct timeval& start, struct timeval& end, string str);   

int main (void)
{
  int arr[ARR_SIZE];
  int tmp;
  struct timeval start, stop;

  srand (time (NULL));

  /* Writing data to array */
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    arr[i] = rand();
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to write to array."));

  /* Reading data from array */
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    tmp = arr[i];
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to read from array sequentially."));

  /* Reading data from array randomly*/
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    tmp = arr[rand() % ARR_SIZE];
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to read from array randomly."));


  int *darr = (int *) calloc (sizeof (int), ARR_SIZE);  

  /* Writing data to array */
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    darr[i] = rand();
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to write to dynamic array."));

  /* Reading data from array */
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    tmp = darr[i];
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to read from dynamic array sequentially."));

  /* Reading data from dynamic array randomly*/
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    tmp = darr[rand() % ARR_SIZE];
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to read from dynamic array randomly."));

  std::vector<int> v(ARR_SIZE);
  assert (v.capacity() == ARR_SIZE);

  /* Writing to vector using indices*/
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    v[i] = rand();
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to write to vector using indices."));
  assert (v.capacity() == ARR_SIZE);

  /* Reading from vector using indices*/
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    tmp = v[i];
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to read from vector using indices, sequentially."));

  /* Reading data from dynamic array randomly*/
  gettimeofday (&start, NULL);
  for (int i = 0; i < ARR_SIZE; i++)
  {
    tmp = v[rand() % ARR_SIZE];
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to read from vector using indices, randomly."));

  std::vector<int> v2(ARR_SIZE);

  /* Writing to vector using iterators*/
  gettimeofday (&start, NULL);
  std::vector<int>::iterator itr, itr_end;
  for (itr = v2.begin(), itr_end = v2.end(); itr != itr_end; itr++)
  {
    *itr = rand();
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to write to vector using iterators."));


  /* Reading from vector using iterators*/
  gettimeofday (&start, NULL);
  for (itr = v2.begin(), itr_end = v2.end(); itr != itr_end; itr++)
  {
    tmp = *itr;
  }
  gettimeofday (&stop, NULL);
  printtime (start, stop, string ("Time taken to read from vector using iterators."));

  return 0;
}

void printtime (struct timeval& start, struct timeval& end, string str)
{
  double start_time, end_time, diff;

  start_time = ((start.tv_sec) * 1000 + start.tv_usec/1000.0);
  end_time   = ((end.tv_sec) * 1000 + end.tv_usec/1000.0);
  diff = end_time - start_time;

  std::cout << str << " : " << diff << " ms" << std::endl;
}

EDIT

Как указано в комментариях, вот дополнительная информация: -

  • Компилятор: - g++ - 4.5.2
  • Флаги: - нет (т.е. значения по умолчанию)
  • Оптимизация: - Нет (я хотел проверить поведение в обычной настройке. Оптимизация может варьировать поведение программы, например, поскольку переменная tmp никогда не используется, шаг чтения вектора/массива может вообще пропустить или сводится только к последнему назначению. По крайней мере, это то, что я понимаю).

Ответ 1

Конечно, не окончательный ответ, но вы пишете в цикле переменную, что означает, что компилятор может легко догадаться, каков конечный результат для последовательного чтения, тем самым оптимизируя цикл. Поскольку это, очевидно, не делает этого, я предполагаю, что нет оптимизации, которая определенно не способствует итератору. Другие цифры слишком близки, чтобы делать выводы.