Quantcast
Channel: Intel® C++ Compiler
Viewing all articles
Browse latest Browse all 1616

Should we align for SIMD on modern x86?

$
0
0

Hi,

I've been working on the usage of aligning arrays to SIMD width on modern x86 CPU. I finally found this piece of code that shows a difference on my computer (Core i7-4850HQ).

#include <iostream>
#include <chrono>
#include <mm_malloc.h>

int main(int argc, const char* argv[]) {
  const int n{8000};
  const int nb_loops{10000000};
  {
    char* a{new char[n]};
    char* b{new char[n]};
    char* c{new char[n]};
    for (int i = 0; i < n; ++i) {
      a[i] = 0;
      b[i] = 1;
      c[i] = 0;
    }

    auto start = std::chrono::high_resolution_clock::now();
    for (int k = 0; k < nb_loops; ++k) {
      for (int i = 0; i < n; ++i) {
        b[i] = a[i] + b[i] + c[i];
      }
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto time =
        std::chrono::duration_cast<std::chrono::nanoseconds>(end - start)
            .count();

    std::cout << "Time unaligned: "<< time << " ns"<< std::endl;

    delete[] c;
    delete[] b;
    delete[] a;
  }

  {
    char* a{static_cast<char*>(_mm_malloc(n * sizeof(char), 32))};
    char* b{static_cast<char*>(_mm_malloc(n * sizeof(char), 32))};
    char* c{static_cast<char*>(_mm_malloc(n * sizeof(char), 32))};
    for (int i = 0; i < n; ++i) {
      a[i] = 0;
      b[i] = 1;
      c[i] = 0;
    }

    auto start = std::chrono::high_resolution_clock::now();
    for (int k = 0; k < nb_loops; ++k) {
#pragma omp simd aligned(a, b, c : 32)
      for (int i = 0; i < n; ++i) {
        b[i] = a[i] + b[i] + c[i];
      }
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto time =
        std::chrono::duration_cast<std::chrono::nanoseconds>(end - start)
            .count();

    std::cout << "Time aligned: "<< time << " ns"<< std::endl;

    _mm_free(c);
    _mm_free(b);
    _mm_free(a);
  }

  return 0;
}

On my CPU, the unaligned version takes 1.57s whereas the aligned version takes 1.36s when compiled with

icpc -std=c++11 -O3 -xHost -ansi-alias -qopenmp main.cpp -o main

I would like to understand the reason for this difference. Here are the suspects:

1) SIMD aligned loads and stores are faster than unaligned ones

2) A SIMD aligned data does not cross a cacheline which makes the the memory transfer faster

3) The code for the SIMD version does not have loop peeling, and is therefore way smaller which makes the loop faster

It seems that reason 1 is not valid on modern CPU. For reason 2, it does not seem right as the aligned version loses its advantage over the first without the alignement hint. This is the reason I highly suspect the third reason. To confirm that, it would be nice to have a compiled version without loop peeling and with aligned loads. Is there a way to do that?

If 3 is the reason for the better speed, why do we still have loop peeling on x86 hardware?

The Xeon Phi is another beast as unaligned loads and stores are way slower than aligned ones. Is it expected to vanish with the future generations of Xeon Phi? 


Viewing all articles
Browse latest Browse all 1616

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>