"Простая итерация по связанному списку становится значительно медленнее по мере роста структуры, даже при том, что фактически ничего не происходит, кроме указателя."
При NPAD = 0 каждая строка кэша содержит 8 узлов списка, поэтому вы можете понять, почему это быстрее.
При NPAD = 7, 15, 31 необходимо загружать только одну строку кэша для каждого узла списка, и можно ожидать, что все они будут иметь одинаковую скорость - одна ошибка кэша на узел. Но современный менеджер памяти будет заниматься спекулятивным кэшированием. Если у него есть резервная емкость (что, вероятно, имеет место, потому что с современной памятью он может выполнять несколько операций чтения параллельно с основной памятью), тогда он начнет загружать память рядом с используемой памятью. Хотя это связанный список, если вы построили его любым из очевидных способов, есть хороший шанс, что вы обращаетесь к памяти последовательно. Таким образом, чем ближе друг к другу в памяти находятся узлы списков, тем успешнее будет кэш с точки зрения того, что у вас уже есть то, что вам нужно.
В худшем из возможных сценариев, когда ваша память извлекается из подкачки во время ее использования, ваша программа будет ограничена дисковым вводом / выводом. Вполне возможно, что скорость вашего прохождения по списку будет полностью зависеть от того, сколько узлов на странице, и вы можете увидеть, что затраченное время прямо пропорционально размеру узла, вплоть до 4k. Я не пробовал, однако, и операционная система будет умной со свопом так же, как MMU умна с основной памятью, так что это не обязательно так просто.