Още по-забавни резултати

t1.c:
GeSHi (C):
#include <unistd.h>
void main()
{
int a[2][2];
int b;
b = a[1][1];
}
t2.c:
GeSHi (C):
void main()
{
int *a;
int b;
b = *(a+4);
}
Асемблерен код на main() функцията, компилираме го без оптимизации:
t1:
0x08048384 <main+0>: lea 0x4(%esp),%ecx
0x08048388 <main+4>: and $0xfffffff0,%esp
0x0804838b <main+7>: pushl 0xfffffffc(%ecx)
0x0804838e <main+10>: push %ebp
0x0804838f <main+11>: mov %esp,%ebp
0x08048391 <main+13>: push %ecx
0x08048392 <main+14>: sub $0x20,%esp
0x08048395 <main+17>: mov 0xfffffff4(%ebp),%eax
0x08048398 <main+20>: mov %eax,0xfffffff8(%ebp)
0x0804839b <main+23>: add $0x20,%esp
0x0804839e <main+26>: pop %ecx
0x0804839f <main+27>: pop %ebp
0x080483a0 <main+28>: lea 0xfffffffc(%ecx),%esp
0x080483a3 <main+31>: ret
t2:
0x08048384 <main+0>: lea 0x4(%esp),%ecx
0x08048388 <main+4>: and $0xfffffff0,%esp
0x0804838b <main+7>: pushl 0xfffffffc(%ecx)
0x0804838e <main+10>: push %ebp
0x0804838f <main+11>: mov %esp,%ebp
0x08048391 <main+13>: push %ecx
0x08048392 <main+14>: sub $0x10,%esp
0x08048395 <main+17>: mov 0xfffffff4(%ebp),%eax
0x08048398 <main+20>: add $0x10,%eax
0x0804839b <main+23>: mov (%eax),%eax
0x0804839d <main+25>: mov %eax,0xfffffff8(%ebp)
0x080483a0 <main+28>: add $0x10,%esp
0x080483a3 <main+31>: pop %ecx
0x080483a4 <main+32>: pop %ebp
0x080483a5 <main+33>: lea 0xfffffffc(%ecx),%esp
0x080483a8 <main+36>: ret
Или демек 5 инструкции повече. Обаче компилираме ли го с флаг за оптимизация (O1 и нагоре), и двете генерират абсолютно идентичен код:
0x08048384 <main+0>: lea 0x4(%esp),%ecx
0x08048388 <main+4>: and $0xfffffff0,%esp
0x0804838b <main+7>: pushl 0xfffffffc(%ecx)
0x0804838e <main+10>: push %ebp
0x0804838f <main+11>: mov %esp,%ebp
0x08048391 <main+13>: push %ecx
0x08048392 <main+14>: pop %ecx
0x08048393 <main+15>: pop %ebp
0x08048394 <main+16>: lea 0xfffffffc(%ecx),%esp
0x08048397 <main+19>: ret
Има една разлика между масивите и указателите обаче - масивите могат да бъдат в стека или data секцията (в зависимост от това дали са локални/глобални променливи), указателите се очаква да сочат към памет в хийпа. Обаче последното не е задължително - примерно ако се ползва alloca() няма да е така.
Обаче и при това положение, не виждам разлика. Паметта би трябвало да се dereference-ва еднакво бързо без значение къде е. Performance драми може да има с TLB misses при големи матрици, но това трябва да е валидно и за двата варианта. Другото което си мисля е дали линукс ядрото не предпочита при нужда да pageout-ва страници памет от хийпа пред страници памет от стека, ама много ме съмнява да (може да) го прави, а и не виждам с какво това би било по-умно от LRU стратегията.
Та все още не мога да се сетя защо едното трябва да е по-бързо от другото.
В хийпа трябва да е по-бавно заради malloc() ама ако е малка матрицата може да го заделим в стека и тва е доста бърза операция (измества се само стек пойнтера). После, не е казано че трябва да ползваме malloc() въобще, може и сaмо с mmap(), което ще е малко по-бързо.
Ако изключим времето за заделяне и освобождаваме, двете трябва да са еднакво бързи.