Quelle est la différence entre les appels vrais et improbables dans Kernel?

Quel est le entre les appels probables et improbables dans Kernel. Lors de la search dans la source du kernel, j'ai trouvé ces déclarations.

# define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) 

Est-ce que quelqu'un pourrait y jeter un peu de lumière?

Ce sont des conseils de compilation pour GCC. Ils sont utilisés dans conditionals pour dire au compilateur si une twig est susceptible d'être prise ou non. Cela peut aider le compilateur à définir le code de manière optimale pour les résultats les plus fréquents.

Ils sont utilisés comme ceci:

 if (likely(some_condition)) { // the comstackr will try and make the code layout optimal for the case // where some_condition is true, ie where this block is run most_likely_action(); } else { // this block is less frequently used corner_case(); } 

Il doit être utilisé avec beaucoup de soin (c.-à-d. Sur la base des résultats de profil de twig réels). Un mauvais indice peut dégrader la performance (évidemment).

Quelques exemples de la façon dont le code peut être optimisé sont facilement trouvés en recherchant GCC __builtin_expect . Ce blog post optimization gcc: __builtin_expect par exemple détaille un déassembly avec elle.

Le type d'optimization qui peut être fait est très spécifique au processeur. L'idée générale est que souvent, les processeurs exécutent le code plus rapidement s'il ne twig pas / saute partout. Plus il est linéaire et plus les twigs sont prévisibles, plus vite il fonctionnera. (Cela est particulièrement vrai pour les processeurs avec des pipelines profonds par exemple.)

Ainsi, le compilateur émettra le code tel que la twig la plus probable n'impliquera pas de saut si c'est ce que la CPU cible préfère, par exemple.

Décompilons pour voir ce que GCC 4.8 fait avec

Sans attendre

 #include "stdio.h" #include "time.h" int main() { /* Use time to prevent it from being optimized away. */ int i = !time(NULL); if (i) printf("%d\n", i); puts("a"); return 0; } 

Comstackr et décomstackr avec GCC 4.8.2 x86_64 Linux:

 gcc -c -O3 -std=gnu11 main.c objdump -dr main.o 

Sortie:

 0000000000000000 <main>: 0: 48 83 ec 08 sub $0x8,%rsp 4: 31 ff xor %edi,%edi 6: e8 00 00 00 00 callq b <main+0xb> 7: R_X86_64_PC32 time-0x4 b: 48 85 c0 test %rax,%rax e: 75 14 jne 24 <main+0x24> 10: ba 01 00 00 00 mov $0x1,%edx 15: be 00 00 00 00 mov $0x0,%esi 16: R_X86_64_32 .rodata.str1.1 1a: bf 01 00 00 00 mov $0x1,%edi 1f: e8 00 00 00 00 callq 24 <main+0x24> 20: R_X86_64_PC32 __printf_chk-0x4 24: bf 00 00 00 00 mov $0x0,%edi 25: R_X86_64_32 .rodata.str1.1+0x4 29: e8 00 00 00 00 callq 2e <main+0x2e> 2a: R_X86_64_PC32 puts-0x4 2e: 31 c0 xor %eax,%eax 30: 48 83 c4 08 add $0x8,%rsp 34: c3 retq 

L'ordre d'instruction dans la memory était inchangé: d'abord le printf puis puts et le return de retq .

Avec attendu

Maintenant, remplacez if (i) par:

 if (__builtin_expect(i, 0)) 

et nous obtenons:

 0000000000000000 <main>: 0: 48 83 ec 08 sub $0x8,%rsp 4: 31 ff xor %edi,%edi 6: e8 00 00 00 00 callq b <main+0xb> 7: R_X86_64_PC32 time-0x4 b: 48 85 c0 test %rax,%rax e: 74 11 je 21 <main+0x21> 10: bf 00 00 00 00 mov $0x0,%edi 11: R_X86_64_32 .rodata.str1.1+0x4 15: e8 00 00 00 00 callq 1a <main+0x1a> 16: R_X86_64_PC32 puts-0x4 1a: 31 c0 xor %eax,%eax 1c: 48 83 c4 08 add $0x8,%rsp 20: c3 retq 21: ba 01 00 00 00 mov $0x1,%edx 26: be 00 00 00 00 mov $0x0,%esi 27: R_X86_64_32 .rodata.str1.1 2b: bf 01 00 00 00 mov $0x1,%edi 30: e8 00 00 00 00 callq 35 <main+0x35> 31: R_X86_64_PC32 __printf_chk-0x4 35: eb d9 jmp 10 <main+0x10> 

Le printf (compilé en __printf_chk ) a été déplacé à la fin de la fonction, après les puts et le return pour améliorer la prédiction des twigs comme mentionné par les autres réponses.

Donc, c'est fondamentalement la même chose que:

 int i = !time(NULL); if (i) goto printf; puts: puts("a"); return 0; printf: printf("%d\n", i); goto puts; 

Cette optimization n'a pas été faite avec -O0 .

Mais bonne chance pour écrire un exemple qui fonctionne plus vite avec __builtin_expect que sans, les processeurs sont vraiment intelligents ces jours-ci . Mes tentatives naïves sont là .