Content

Vorbereitung: Verwendung von Hardware-optimierten Micro-Kernel

Um die für SIMD (Single instruction multiple data) Operationen optimierten Assembler Micro-Kernel benutzen zu können, müssen noch ein paar Vorbereitungen getroffen werden:

SFINAE Substitution failure is not an error

Die Blockgrößen sind durch den hpc::ulmblas::BlockSize Trait bereits zur Compile-Zeit bekannt. Wir werden zeigen, wie man auch schon zur Compile-Zeit festlegen kann, ob beim Micro-Kernel die Referenz-Implementierung oder eine optimierte Variante verwendet wird.

Wir brechen das eigentliche Problem zunächst auf ein Reihe einfacher Beispiele herunter:

Aufgabe

Obige Foo-Beispiele ausprobieren.

Allokation mit speziellem Alignment

In C11 wurde die Funktion

void *aligned_alloc(size_t alignment, size_t size);

eingeführt, die size Bytes allokiert, wobei der allokierte Speicherbereich bei einer durch alignment teilbaren Adresse beginnt. Leider ist diese Funktion voraussichtlich erst ab C++17 für C++ verfügbar. Für eine Allokation mit speziellem Alignment greifen wir deshalb zunächst auf die in xmmintrin.h dekalrierte und den (meisten) Intel Platformen verfügbaren Funktion _mm_malloc zurück:

void *_mm_malloc(size_t size, size_t align);

Um den Speicher freizugeben, muss dann

void _mm_free(void *mem);

verwendet werden. In hpc/ulmblas/malloc.h implementieren wir einen Wrapper, um dynamischen Speicher zu allokieren. Falls ein Macro MEM_ALIGN definiert wurde soll die Funktion hpc::ulmblas::malloc einen Block mit entsprechendem Alignment allokieren, der mit hpc::ulmblas::free wieder freigegeben werden muss:

#ifndef HPC_ULMBLAS_MALLOC_H
#define HPC_ULMBLAS_MALLOC_H 1

#include <cstddef>
#ifdef MEM_ALIGN
#   include <xmmintrin.h>
#endif

namespace hpc { namespace ulmblas {

template <typename T>
T *
malloc(std::size_t n)
{
#ifdef MEM_ALIGN
    return reinterpret_cast<T *>(_mm_malloc(n*sizeof(T), MEM_ALIGN));
#   else
    return new T[n];
#   endif
}

template <typename T>
void
free(T *block)
{
#ifdef MEM_ALIGN
    _mm_free(reinterpret_cast<void *>(block));
#   else
    delete [] block;
#   endif
}

} } // namespace ulmblas, hpc

#endif // HPC_ULMBLAS_MALLOC_H

Aufgaben