Если это важно, то нужно для архитектуры core 2 duo не ниже. Есть функция, которая из гигантского массива (больше гига) считывает значение. Код (Text): unsigned char poluchaem(int& j0,int& j1,int& j2,int& j3) { return massiv[j0][j1][j2][j3]; } Индексы рассчитываются по сложному алгоритму и абсолютно не упорядочены. Функция вызывается очень часто, и дело усугубляется тем, что вынужден использовать тип char чтобы вписаться в размер оперативки. Есть такая же функция для записи. Для эксперементов написал такую прогу. Код (Text): const int razmer=100; unsigned char massiv_0[razmer][razmer][razmer][razmer]; unsigned char massiv_1[razmer][razmer][razmer][razmer]; unsigned char massiv_2[razmer][razmer][razmer][razmer]; //набиваем все массивы случайными числами; QueryPerformanceCounter(&begin_time); for(int i=0;i<1024*1024;i++) { int j0=rand()%razmer; int j1=rand()%razmer; int j2=rand()%razmer; int j3=rand()%razmer; //бог с ним с переполнением, просто для примера massiv_0[j0][j1][j2][j3]= massiv_1[j1][j2][j3][j0]+ massiv_2[j2][j3][j0][j1]; } QueryPerformanceCounter(&end_time); Без учета задержек все должно выполняться с одинаковой скоростью не зависимо от razmer. По факту: при росте общего размера массивов от размера L1 кеша до ГБ скорость падает больше чем в 100 раз. Возвращаясь к первоначальной функции. Можно с момента получения индексов и высчитывания указателя написать много кода, а потом уже обратиться к значению. Нашел такую функцию, но что-то не помогает. void _mm_prefetch(char * p , int hint ); // hint = _MM_HINT_T0, _MM_HINT_T1, _MM_HINT_T2, _MM_HINT_NTA Типа получится Код (Text): unsigned char* ptr=index(j0,j1,j2,j3); _mm_prefetch(ptr,_MM_HINT_T0); … //много кода … unsigned char a=*ptr; В ассемблере только начальные знания, но, т.к. очень нужно, разберусь. Спасибо.
Дружок, какие промахи в кэш, когда ты прыгаешь по всему массиву? Дай бог, что бы страничных прерываний не было.
Обязательно использовать четырёхмерный массив? Посмотри какой из индексов чаще меняется в твоей программе - он должен быть последним. То есть структура массива должна быть такой, чтобы часто запрашиваемые данные распологались ближе друг к другу в памяти. Тогда в большинстве случаев они будут браться из кеша.
Алгоритм поменяю, если смогу. Хочется тут разобраться _mm_prefetch(ptr,_MM_HINT_T0); Просто про эту функцию подскажите, как ее правильно использовать на core 2 duo. Какой лучше 2 параметр и нужно ли выравнивать ptr или процессор сам это делает. Пока придумал такого плана Код (Text): const int razmer=100; const int chislo_progonov=1024*1024; const int razmer_bufera_predviborki=4;//поиграться с этим коэф. unsigned char* ptr_0[razmer_bufera_predviborki]; unsigned char* ptr_1[razmer_bufera_predviborki]; unsigned char* ptr_2[razmer_bufera_predviborki]; //тут случайно, на самом деле алгоритм //но заранее не предсказуемо void generator(int& j0,int& j1,int& j2,int& j3) { j0=rand()%razmer; j1=rand()%razmer; j2=rand()%razmer; j3=rand()%razmer; }; //предвыборка void predviborka(int& i) { int& j0,j1,j2,j3; generator(j0,j1,j2,j3); ptr_0[i]=&massiv_0[j0][j1][j2][j3]; _mm_prefetch(ptr_0[i],_MM_HINT_T0); ptr_1[i]=&massiv_1[j1][j2][j3][j0]; _mm_prefetch(ptr_1[i],_MM_HINT_T0); ptr_2[i]=&massiv_2[j2][j3][j0][j1]; _mm_prefetch(ptr_2[i],_MM_HINT_T0); }; //начало в холостую for(int i=0;i<razmer_bufera_predviborki;i++) { predviborka(i); }; //должно быть быстрее for(int i=0;i<chislo_progonov-razmer_bufera_predviborki;i++) { //бог с ним с переполнением, просто для примера *ptr_0[i%razmer_bufera_predviborki]= *ptr_1[i%razmer_bufera_predviborki]+ *ptr_2[i%razmer_bufera_predviborki]; predviborka(i+razmer_bufera_predviborki); } //досчитать for(int i=chislo_progonov-razmer_bufera_predviborki;i<chislo_progonov;i++) { //бог с ним с переполнением, просто для примера *ptr_0[i%razmer_bufera_predviborki]= *ptr_1[i%razmer_bufera_predviborki]+ *ptr_2[i%razmer_bufera_predviborki]; }
sashaz Как говориться, должно, да не обязано Префетч рулит только на достаточно большой дистанции. Говоря твоими словами, нужно "много кода" между префетчами, причем этот код должен обращаться только к уже загруженным в кэш данным (или вообще не обращаться). В этом случае префетч позволяет заблоговременно выдавать процессору запрос на подгрузку данных из ОЗУ и выполнять ее полностью или частично во время исполнения кода. В твоем же примере весь код состоит из нескольких элементарных действий, выполняемых за единицы тактов, в то время как на загрузку каждого из 3-х операндов со случайными адресами требуется не менее сотни-другой тактов. Т.е. время исполнения кода пренебрежимо мало по сравнению с временем ожидания загрузки и префетч здесь практически ничего не даст. PS: При чисто случайном доступе к объему данных, намного превышающему размер L2, ловить нечего. Нужно уточнить задачу и попытаться как-то упорядочить данные