Це, мабуть, стосується конфліктів у вашому кеш-пам'яті L2.
Пропуски кеша на matice1 не є проблемою, оскільки до них звертаються послідовно. Однак для matice2, якщо повний стовпець вписується в L2 (тобто, коли ви отримуєте доступ до matice2 [0, 0], matice2 [1, 0], matice2 [2, 0] ... і т. Д., Нічого не вилучається), ніж немає проблем з кеш пропущений і з matice2.
Тепер заглибимось у те, як працює кеш, якщо байт-адреса вашої змінної дорівнює X, ніж рядок кешу для неї буде (X >> 6) & (L - 1). Де L - загальна кількість рядків кеша у вашому кеші. L завжди потужність 2. Шість походить від того, що 2 ^ 6 == 64 байти - це стандартний розмір лінії кеша.
Тепер що це означає? Ну це означає, що якщо у мене адреса X і Y і (X >> 6) - (Y >> 6) ділиться на L (тобто деяка велика потужність 2), вони будуть зберігатися в тій же кеш-лінії.
Тепер, щоб повернутися до вашої проблеми, яка різниця між 2048 та 2049,
коли 2048 - ваш розмір:
якщо взяти & matice2 [x, k] і & matice2 [y, k], різниця (& matice2 [x, k] >> 6) - (& matice2 [y, k] >> 6) буде розділена на 2048 * 4 (розмір поплавця). Так велика потужність 2.
Таким чином, залежно від розміру вашого L2, у вас буде багато конфліктів між кешами, і ви використовуєте лише невелику частину свого L2 для зберігання стовпця, таким чином, ви фактично не зможете зберігати повний стовпець у своєму кеші, таким чином ви отримаєте погану ефективність .
Якщо розмір становить 2049, то різниця становить 2049 * 4, що не має сили 2, тож у вас буде менше конфліктів, і ваш стовпець буде безпечно вписуватися у ваш кеш.
Тепер для перевірки цієї теорії ви можете зробити кілька речей:
Виділіть свій масив matice2, як цей matice2 [razmor, 4096], і запустіть з razmor = 1024, 1025 або будь-якого розміру, і ви повинні побачити дуже погану продуктивність порівняно з тим, що раніше мали. Це тому, що ви змушуєте вирівнювати всі стовпці, щоб суперечити один одному.
Потім спробуйте matice2 [razmor, 4097] і запустіть його будь-якого розміру, і ви повинні побачити набагато кращу продуктивність.