C ++ оптимизирует преобразование массива из int в float - PullRequest
0 голосов
/ 19 мая 2018

Я пытаюсь ускорить некоторый код Matlab, портируя его на C ++, и обнаружил, что очень простые операции намного медленнее в C ++, чем в Matlab.А именно, преобразование массива целых чисел в числа с плавающей точкой.Я использую Intel Parallel Studio 2018 с MKL и TBB.

Эта строка в Matlab занимает в среднем 6 мс на моем ноутбуке (Mac OS 10.13):

spec = single(spec_int); % spec_int is 1000x4096 uint16

Наивный подход (один цикл) занимает около 9 мс (без учета выделения и инициализации памяти):

uint16_t *spec_int = (uint16_t *) MKL_malloc(4096 * 1000 * sizeof(uint16_t), 64);
float *spec = (float *) MKL_malloc(sizeof(float) * FRAME_SIZE, 64);

// Initialize spec_int

for(MKL_INT i = 0; i<FRAME_SIZE; i++)
    spec[i] = spec_int[i];

При parallel_for в TBB это занимает около 13 мс:

tbb::parallel_for( size_t(0), size_t(FRAME_SIZE), [&]( size_t i ) {
    spec[i] = spec_int[i];
} );

Я озадачен.Что я делаю неправильно?Как я могу соответствовать скорости Matlab в C ++?

1 Ответ

0 голосов
/ 19 мая 2018

Резюме: Вы, вероятно, измеряете шум:

Я довольно уверен, что вы имеете дело с простым кэшированием памяти от предыдущей (неявной) операции matlab, ускоряющей его.Я переписал вашу наивную реализацию для использования таблицы поиска (так что это простое назначение без преобразования типов).Это не ускорило его.Это стоит отметить.

Затем я запустил аналогичный (но другой - не допустить оптимизации) цикл и рассчитал его.Он работал намного быстрее:

int main()
{
  float index[65537] ;
  for (int i = 0; i < 65537; i++)
    index[i] = i;
  uint16_t *pi = new uint16_t[4096 * 1000];
  memset(pi, 0, sizeof(pi));
  float *pf = new float[4096 * 1000];
  memset(pf, 0, sizeof(pf));
  clock_t begin = clock();
  for (int i = 0; i < 4096 * 1000; ++i)
  {
    pf[i] = index[pi[i]]; //no conversion...simple copy(and not faster)
  }
  clock_t end = clock();
  clock_t begin2 = clock();
  for (int i = 0; i < 4096 * 1000; ++i)
  {
    pf[i] = index[pi[i]+1]; 
  }
  clock_t end2 = clock();
  printf("%d\n", (long)end - begin);
  printf("%d\n", (long)end2 - begin2);
}

Вывод:

9
2

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

Это все догадки, но это, вероятно, лучшее, что вы получите, если не заглянуть в эксперта по Matlab.

Вывод вышеизложенного в C#, кстати: 12, 4.

...