Прежде всего, ваш тест сильно смещен: чтобы увидеть смещение, измените порядок двух блоков, которые вы тестируете, и все начнет меняться. Для такого теста нужно:
- написать две разные программы, по одной на каждый случай;
- запускайте каждую программу несколько раз и берите среднее время;
Вы также можете заменить второй шаг циклом в зависимости от того, что вас интересует.
Теперь, возвращаясь к вашему беспокойству, я сначала упомяну, что вопрос слишком широк, как упомянул Франческал. Короче говоря; Память компьютера организована в иерархию:
- ОЗУ;
- Кэш (уровней может быть много, для простоты считаем один уровень);
- Регистры
У любого уровня есть свои преимущества и недостатки:
- Оперативная память может быть большой (гигабайты), но очень медленной (около десятков наносекунд, от 50 до 70).
- Кэш не очень большой (от нескольких килограммов до нескольких мегабайт), быстрее, чем оперативная память (несколько наносекунд от 0,5 до 2,5)
- регистр не большой (всего десятки байт), очень быстрый.
См., например, эту ссылку для получения дополнительной информации. . Я проигнорировал диски, которые являются другим уровнем памяти, а также сетью.
Данные обычно переходят только с одного уровня памяти на другой: то есть из ОЗУ в кэш и из кеша в ОЗУ, из кеша в регистр и из регистра в кеш. ЦП работает только с регистрами, доступ к которым быстрее. Таким образом, для каждой операции данные заносятся из ОЗУ в регистр, а после вычисления возвращаются обратно в ОЗУ. О нет, не так быстро. Давайте не будем усложнять и скажем, что ЦП работает с байтами (если вы пойдете глубже, вы узнаете понятие слов, представляющих собой группу смежных байтов, и понятие страниц, представляющее собой группу смежных слов).
Когда вы обращаетесь к байту, которого еще нет в кеше, возникает ошибка кеша, этот байт сначала идет из ОЗУ в кеш, а затем переходит в регистр для вашей операции. Когда система берет этот байт из ОЗУ в кеш, она берет вместе группу смежных байтов. Так что если следующая операция будет на самом соседе, то не надо будет лезть в ОЗУ.
Теперь в вашей программе происходит то, что fortran хранит массив по столбцам, что означает, что в памяти элементы хранятся в следующем порядке:
a(1,1) a(2,1) a(3,1) ... a(M,1) a(1,2) a(2,2) a(3,2) ... a(M,2) ...
Итак, петля
do j=1,255,1
do i=1,255,1
arr1(i,j)=1
end do
end do
обращается к элементам в том порядке, в котором они хранятся в памяти. Количество переходов между оперативной памятью и кешем сведено к минимуму.
Для другой петли
do i=1,255,1
do j=1,255,1
arr1(i,j)=1
end do
end do
Вы просто не обращаетесь к элементам в правильном порядке. Например, если ваш кеш может содержать меньше столбца вашей матрицы, это означает, что для любой итерации внутреннего цикла система должна пополнить кеш. И это не так просто, чтобы пополнить кеш, система сначала скопирует обратно в оперативную память данные, которые находятся в кеше, если они были изменены, как здесь. Чтобы увидеть это, увеличьте матрицу до максимального размера, который может выдержать ваша оперативная память, и вы увидите, что значит не следовать логике хранения, разрыв будет увеличиваться. Вы можете переходить постепенно, 1000x1000, затем 10000x10000 и т. д. Когда вы кэшируете только один столбец или меньше, вы получите коэффициент, близкий к коэффициенту между временем доступа к ОЗУ и кэшу. Помните, больше 10.
Тема памяти является предметом многих курсов информатики. Я хотел дать тебе только то, что могу дать быстро.
person
innoSPG
schedule
09.08.2015