Я пытаюсь разобраться в результатах тестирования процессора Intel Xeon Phi 7210. Моя настройка и вопрос:
Теоретическая пиковая производительность на Intel Xeon Phi:
64 (ядра) x 2 (блоки AVX512) x 16 (32-битное с плавающей запятой) x 1,3 ГГц = 2662,4 Гфлопс / сек.
Настройка: матричное умножение 2 матриц 512x512 с использованием типов данных __mm512
Результаты:
Arrangement Time, ms GB/s GFLOP/s
OMP threads 0.620 5.075 432.616 (#pragma omp parallel for above the outer loop)
Tiling(using tasks) 3.680 0.855 72.873 (creating task for each 32x32 tile of output matrix)
GFlops: N N N [умножения] + N * N * (N-1) [сложения]
ГБ / с: sizeof (float) * 3 * (N * N ) т.е. 2 матрицы чтения и 1 запись. В моем случае N = 512
Вывод подтвержден и корректен, однако я кое-что не понимаю. Это далеко не теоретическая скорость, несмотря на использование 512-битных регистров и даже развертывание самого внутреннего l oop (вторая матрица также переносится для увеличения пространственной локальности). Я ожидал, что Tiling будет работать намного лучше, так как я спроектировал размер плитки таким образом, чтобы все частичные плитки полностью помещались в кэш данных 32 КБ, но это медленно.
Мои вопросы:
1: как я могу узнать, сколько ядер или потоков используется моей программой?
2: могу ли я выполнять контролируемое выполнение в потоках, например, выполнение 64 потоков, но на 64 ядрах (с использованием 1 аппаратного потока на ядро или, возможно, максимум 2 аппаратных потока, поскольку в каждом ядре есть два модуля AVX512)
3: как лучше всего использовать 6 портов памяти? Теоретическая пропускная способность составляет 100+ ГБ / с, и моя - лишь часть этого. Я развернул внутреннее большинство l oop дважды, т.е. есть 4 следующих
__m512 vx0 = _mm512_load_ps((P*)&in1[(i*M1Rdim)+(k+0)]); //loads up 16 floats into a __m512
__m512 vy0 = _mm512_load_ps((P*)&in2[(j*M1Cdim)+(k+0)]); //loads up 16 floats into a __m512