#c #c #sse #simd
#c #c #sse #simd
Вопрос:
У меня много (x1, y1, z1), (x2, y2, z2), (x3, y3, z3) векторных триплетов одинарной точности, и я хочу изменить их порядок, поэтому (x1, y1, z1), (x2, y2, z2), (x3, y3, z3) становится (x1, x2, x3,0, y1, y2, y3,0, z1, z2, z3,0)
Цель состоит в том, чтобы подготовить набор данных для вычисления на основе SSE. Для этого у меня есть следующий код:
for (int i=0;i<count;i )
{
Vect3F p0 = get_first_point(i);
Vect3F p1 = get_second_point(i);
Vect3F p2 = get_third_point(i);
int idx = i*3;
scratch[idx] = Vec4F(p0.x, p1.x, p2.x, 0); // These 3 rows are the slowest
scratch[idx 1] = Vec4F(p0.y, p1.y, p2.y, 0);
scratch[idx 2] = Vec4F(p0.z, p1.z, p2.z, 0);
}
Последние 3 строки цикла выполняются чрезвычайно медленно, они занимают 90% времени всего моего алгоритма!
Это нормально? Могу ли я ускорить такую перетасовку? (scratch — это статическая переменная, выровненная по 16. Функция вызывается часто, поэтому я думаю, что блоки scratch не должны исчезать из кэша.)
Комментарии:
1. Похоже, здесь создается много временных объектов. Надеюсь, компилятор устраняет конструкторы, присваивания и т. Д. Рассматривали ли вы возможность реализации членов Vect3F, Vect4F как объединение с выровненным типом SSE (__m128)?
2. К сожалению, Vect3F не удалось выровнять, он должен быть длиной 12 байт, поэтому я не могу использовать SSE при переупорядочении чисел с плавающей запятой. Когда это будет сделано, я использую _mm_load_ps для загрузки данных в регистры (и это быстро). Теперь я расширил все свои конструкторы и назначения:
float* a = (float*)(cache i*3); a[0] = p0.x; a[1] = p1.x; a[2] = p2.x; a[4] = p0.y; a[5] = p1.y; a[6] = p2.y; a[8] = p0.z; a[9] = p1.z; a[10] = p2.z;
немного помогло, но все равно очень медленно.3. Этот фрагмент даже компилируется? Вы объявляете Vect3F p0 три раза!
4. По сути, это транспонирование матрицы. Транспонируйте Google sse, и вы получите несколько более быстрых версий.
5. Даже если компилятор оптимизирует доступ к временным объектам p0, p1, p2, было бы лучше использовать: const Vect3F amp; p0 = points[i];
Ответ №1:
Прежде всего, вы не должны создавать 3 временных векторных объекта. Вместо:
tri = triangles[i];
Vect3F p0 = points[indices[tri]];
Vect3F p1 = points[indices[tri 1]];
Vect3F p2 = points[indices[tri 2]];
Вы должны просто скопировать данные с помощью memcpy(); Создайте цикл, который распространяется на всю вашу коллекцию и копирует необработанные данные. Это самый быстрый способ, который я могу придумать.
Использование 3 переменных запускает множество конструкторов, которые работают мучительно медленно. Второй способ (из комментария) не намного лучше по той же причине.
Комментарии:
1. Заставляет меня задуматься, какие компиляторы вы используете и какие флаги. Я думаю, что код должен быть в некоторой степени отображен одинаково с включенной надлежащей оптимизацией.