8
votes

Pourquoi inlinfing math.max donne-t-il plus de code plus lent 200x?

J'ai récemment commencé à analyser un code Java afin d'obtenir les meilleurs résultats de performance de mon programme et remarquez une chose étrange. À savoir, j'ai comparé les méthodes suivantes: xxx

et obtenu ces résultats: xxx

après la recherche de plus (c'est-à-dire est math.max (A, B) ou (A> B)? : B Plus vite en Java? ) C'était certain pour moi que test1 ne devrait pas être tellement plus lent.

Ces méthodes ont été testées au hasard sur 8 threads dans 30 secondes et chaque référence que je cours semble similaire. J'utilise jdk1.8.0_45 .

donc, pourquoi est test1 plus de 200 fois plus lentement que test0


2 commentaires

Essayez d'ajouter des effets secondaires pour vous assurer que l'exécution n'est pas simplement effacée par le compilateur déterminant le code ne fait rien du tout: somme + = math.max (i, m); ... System.out.println (somme);


Utilisez JMH pour vous assurer que vous mesurez réellement la performance de votre code plutôt qu'un non-OP.


4 Réponses :


2
votes

math.max (A, b) peut être très agressif / évidemment optimisé dans une instruction native pour le processeur.

Pour le ternaire, la transformation simple en instruction de processeur serait un comparateur + saut, en particulier le saut est coûteux.

Pour optimiser le ternaire dans le JIT (le compilateur juste dans le temps) doit reconnaître que le code exprime un maximum et que l'instruction native est la meilleure.

Le JIT pourrait éventuellement reconnaître cela, mais jusqu'à ce que cela soit plus lent.


2 commentaires

Je ne jette pas une fois par classe bytecode? Ce serait un changement de temps constant, pas pour chaque invocation.


Dépend de JIT. Mais Hotspot (l'oracle JVM) compile d'abord avec une compilation rapide, et s'il reconnaît les points chauds (d'où le nom) recompilera avec des optimisations plus agressives.



4
votes

Etant donné que math.max est une fonction statique, le compilateur peut comprendre que le code ne fait rien du tout et optimise simplement l'exécution en ne l'exécutant pas!

variable m être local sur la fonction, attribuant qu'il ne vous aide pas car il n'est jamais lu.

Vous devez vous assurer que l'exécution modifie quelque chose de sorte qu'il n'est pas optimisé agressivement par le compilateur.

Par exemple, vous pouvez simplement imprimer la valeur de M à la fin du test ou faire m une variable de classe qui peut être accessible ultérieurement ou même la somme la résultat que j'ai initialement suggéré dans le commentaire.


0 commentaires

0
votes

Lorsqu'une méthode fonctionne pour la première fois, la JVM n'a pas eu l'occasion de ré-compiler la méthode à l'aide de son compilateur juste à temps. C'est le problème avec tant d'efforts de micro de référence. En supposant que les appels principaux () Test1 (), rendez-vous Main () Call Test1 () plusieurs fois et mesurez le temps de chaque appel de Test1 (). Vous verrez que les appels ultérieurs de Test1 () vont fonctionner beaucoup em> plus rapide!

public class Test
{
    public static void main(String[] args)
    {
        System.out.println("test0");
        for (int i = 0; i < 10; i++)
        {
            long t = System.currentTimeMillis();
            for (int j = 0; j < 100000; j++)
            {
                test0();
            }
            t = System.currentTimeMillis() - t;
            System.out.println(t);
        }
        System.out.println("test1");
        for (int i = 0; i < 10; i++)
        {
            long t = System.currentTimeMillis();
            for (int j = 0; j < 100000; j++)
            {
                test1();
            }
            t = System.currentTimeMillis() - t;
            System.out.println(t);
        }
    }

    private static final int n = 10000;
    private static int z = 10000;

    private static void test0()
    {
        int m = 0;

        for(int i = 0; i < n; ++i)
        {
            m = Math.max(i, m);
        }

        z += m;
    }

    private static void test1()
    {
        int m = 0;

        for(int i = 0; i < n; ++i)
        {
            m = ((i >= m) ? i : m);
        }

        z += m;
    }
}


2 commentaires

J'ai indiqué dans la question que chaque méthode était exécutée 16000000+ fois dans un ordre aléatoire


J'ai mis à jour ma réponse. J'ai ajouté du code et j'ai fait de la sorte que le JVM ne finisse pas d'optimiser / contourner la boucle ou l'appel. Test1 () semble fonctionner environ 27% plus rapidement que Test0 () donner ou prendre.



1
votes

Juste pour confirmer (dans une certaine mesure) Que Jean LoGeart a dit dans sa réponse: lors de l'ajout d'un trivial Main code> qui appelle à la fois des méthodes, comme dans

Decoding compiled method 0x0000000002926290:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x000000001bd103a8} &apos;runTests&apos; &apos;()V&apos; in &apos;MaxOpt&apos;
  #           [sp+0x30]  (sp of caller)
  0x00000000029263c0: mov    %eax,-0x6000(%rsp)
  0x00000000029263c7: push   %rbp
  0x00000000029263c8: sub    $0x20,%rsp         ;*synchronization entry
                        ; - MaxOpt::runTests@-1 (line 13)

  0x00000000029263cc: xor    %r8d,%r8d
  0x00000000029263cf: mov    $0x1,%r11d
  0x00000000029263d5: data32 data32 nopw 0x0(%rax,%rax,1)
                        ;*iload_1
                        ; - MaxOpt::test1@11 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029263e0: cmp    %r8d,%r11d
  0x00000000029263e3: jl     0x000000000292650c  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029263e9: mov    %r11d,%r8d
  0x00000000029263ec: inc    %r8d               ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029263ef: cmp    %r11d,%r8d
  0x00000000029263f2: jl     0x000000000292652d  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029263f8: mov    %r11d,%r9d
  0x00000000029263fb: add    $0x2,%r9d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029263ff: cmp    %r8d,%r9d
  0x0000000002926402: jl     0x000000000292650f  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926408: mov    %r11d,%r8d
  0x000000000292640b: add    $0x3,%r8d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292640f: cmp    %r9d,%r8d
  0x0000000002926412: jl     0x0000000002926518  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926418: mov    %r11d,%r9d
  0x000000000292641b: add    $0x4,%r9d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292641f: cmp    %r8d,%r9d
  0x0000000002926422: jl     0x000000000292650f  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926428: mov    %r11d,%r8d
  0x000000000292642b: add    $0x5,%r8d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292642f: cmp    %r9d,%r8d
  0x0000000002926432: jl     0x0000000002926518  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926438: mov    %r11d,%r9d
  0x000000000292643b: add    $0x6,%r9d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292643f: cmp    %r8d,%r9d
  0x0000000002926442: jl     0x000000000292650f  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926448: mov    %r11d,%r8d
  0x000000000292644b: add    $0x7,%r8d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292644f: cmp    %r9d,%r8d
  0x0000000002926452: jl     0x0000000002926518  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926458: mov    %r11d,%r9d
  0x000000000292645b: add    $0x8,%r9d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292645f: cmp    %r8d,%r9d
  0x0000000002926462: jl     0x000000000292650f  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926468: mov    %r11d,%r8d
  0x000000000292646b: add    $0x9,%r8d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292646f: cmp    %r9d,%r8d
  0x0000000002926472: jl     0x0000000002926518  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926478: mov    %r11d,%r9d
  0x000000000292647b: add    $0xa,%r9d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292647f: cmp    %r8d,%r9d
  0x0000000002926482: jl     0x000000000292650f  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926488: mov    %r11d,%r8d
  0x000000000292648b: add    $0xb,%r8d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292648f: cmp    %r9d,%r8d
  0x0000000002926492: jl     0x0000000002926518  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x0000000002926498: mov    %r11d,%r9d
  0x000000000292649b: add    $0xc,%r9d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292649f: cmp    %r8d,%r9d
  0x00000000029264a2: jl     0x000000000292650f  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264a4: mov    %r11d,%r8d
  0x00000000029264a7: add    $0xd,%r8d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264ab: cmp    %r9d,%r8d
  0x00000000029264ae: jl     0x0000000002926518  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264b0: mov    %r11d,%r9d
  0x00000000029264b3: add    $0xe,%r9d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264b7: cmp    %r8d,%r9d
  0x00000000029264ba: jl     0x000000000292650f  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264bc: mov    %r11d,%r8d
  0x00000000029264bf: add    $0xf,%r8d          ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264c3: cmp    %r9d,%r8d
  0x00000000029264c6: jl     0x0000000002926518  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264c8: add    $0x10,%r11d        ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264cc: cmp    $0x2701,%r11d
  0x00000000029264d3: jl     0x00000000029263e0  ;*if_icmpge
                        ; - MaxOpt::test1@8 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264d9: cmp    $0x2710,%r11d
  0x00000000029264e0: jge    0x0000000002926500
  0x00000000029264e2: xchg   %ax,%ax            ;*iload_1
                        ; - MaxOpt::test1@11 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264e4: cmp    %r8d,%r11d
  0x00000000029264e7: jl     0x0000000002926532  ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264e9: mov    %r11d,%r10d
  0x00000000029264ec: inc    %r10d              ;*iinc
                        ; - MaxOpt::test1@22 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264ef: cmp    $0x2710,%r10d
  0x00000000029264f6: jge    0x0000000002926500  ;*if_icmpge
                        ; - MaxOpt::test1@8 (line 30)
                        ; - MaxOpt::runTests@3 (line 14)

  0x00000000029264f8: mov    %r11d,%r8d
  0x00000000029264fb: mov    %r10d,%r11d
  0x00000000029264fe: jmp    0x00000000029264e4
  0x0000000002926500: add    $0x20,%rsp
  0x0000000002926504: pop    %rbp
  0x0000000002926505: test   %eax,-0x26f650b(%rip)        # 0x0000000000230000
                        ;   {poll_return}
  0x000000000292650b: retq   
  0x000000000292650c: mov    %r11d,%r9d
  0x000000000292650f: mov    %r9d,%r11d
  0x0000000002926512: mov    %r8d,%r9d
  0x0000000002926515: mov    %r11d,%r8d
  0x0000000002926518: mov    $0xffffff65,%edx
  0x000000000292651d: mov    %r8d,0x4(%rsp)
  0x0000000002926522: mov    %r9d,0x8(%rsp)
  0x0000000002926527: callq  0x00000000028557a0  ; OopMap{off=364}
                        ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)
                        ;   {runtime_call}
  0x000000000292652c: int3                      ;*if_icmplt
                        ; - MaxOpt::test1@13 (line 31)
                        ; - MaxOpt::runTests@3 (line 14)

  0x000000000292652d: mov    %r11d,%r9d
  0x0000000002926530: jmp    0x0000000002926518
  0x0000000002926532: mov    %r8d,%r9d
  0x0000000002926535: mov    %r11d,%r8d
  0x0000000002926538: jmp    0x0000000002926518
  0x000000000292653a: hlt    
  0x000000000292653b: hlt    
  0x000000000292653c: hlt    
  0x000000000292653d: hlt    
  0x000000000292653e: hlt    
  0x000000000292653f: hlt    
[Exception Handler]
 ...


0 commentaires