.text
.globl asm_f1
.globl asm_f2
.globl asm_f3
.globl asm_f4
.globl asm_f5
asm_f1:
mov x0, #1
movk x0, #1, lsl #16
movk x0, #1, lsl #32
ret
asm_f2:
nop
nop
nop
ret
asm_f3:
mov x0, #1
movk x0, #1, lsl #16
nop
ret
asm_f4:
mov x0, #1
nop
movk x0, #1, lsl #16
ret
asm_f5:
mov x0, #1
nop
nop
ret
int main(int argc, char **argv) {
clock_t start;
clock_t end;
start = clock();
for (int i = 0; i < COUNT; i++) {
asm_f1();
}
end = clock();
printf("asm_f1 took %ld cycles on avg\n", (end - start) );
start = clock();
for (int i = 0; i < COUNT; i++) {
asm_f2();
}
end = clock();
printf("asm_f2 took %ld cycles on avg\n", (end - start) );
start = clock();
for (int i = 0; i < COUNT; i++) {
asm_f3();
}
end = clock();
printf("asm_f3 took %ld cycles on avg\n", (end - start) );
start = clock();
for (int i = 0; i < COUNT; i++) {
asm_f4();
}
end = clock();
printf("asm_f4 took %ld cycles on avg\n", (end - start) );
start = clock();
for (int i = 0; i < COUNT; i++) {
asm_f5();
}
end = clock();
printf("asm_f5 took %ld cycles on avg\n", (end - start) );
}
asm_f1 took 345961 cycles on avg
asm_f2 took 325725 cycles on avg
asm_f3 took 327267 cycles on avg
asm_f4 took 324958 cycles on avg
asm_f5 took 349501 cycles on avg
Compared with f1 and f2, it seems that 'nop' will save time than 'mov'. As f3 and f4 just use one 'nop', they are a little bit slower than f2 which is expected. f5 uses 2 'nop' but it's slower than f3 and f4, how to explain this case?
$> lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 18.04.2 LTS
Release: 18.04
Codename: bionic
$> uname -p
aarch64
Some docs from AArch64 instruction book
NOP
No Operation does nothing, other than advance the value of the program counter by 4. This instruction can be used for instruction alignment purposes.
The timing effects of including a NOP instruction in a program are not guaranteed. It can increase execution time, leave it unchanged, or even reduce it. Therefore, NOP instructions are not suitable for timing loops.
Update:
According to @Siguza's comment, I changed the loop a little, the performance gap now is more obvious.
void loop(void *f, char *fname) {
clock_t start;
clock_t end;
start = clock();
for (int i = 0; i < COUNT; i++) {
((void(*)())f)();
}
end = clock();
printf("%s took %ld cycles on avg\n", fname, (end - start) );
}
int main(int argc, char **argv) {
loop(asm_f1, "asm_f1");
loop(asm_f2, "asm_f2");
loop(asm_f3, "asm_f3");
loop(asm_f4, "asm_f4");
loop(asm_f5, "asm_f5");
return 0;
}
asm_f1 took 344089 cycles on avg
asm_f2 took 259436 cycles on avg
asm_f3 took 246766 cycles on avg
asm_f4 took 245166 cycles on avg
asm_f5 took 354827 cycles on avg