J'ai a piece of code où il apparaît, dans chaque test que j'ai exécuté, que les appels de fonction ont une quantité importante de temps système. Le code est une boucle serrée, effectuant une fonction très simple sur chaque élément d'un tableau (contenant 4-8 millions int
s).Réduction de l'en-tête des appels de fonction Java
L'exécution du code, qui se compose principalement de
for (int y = 1; y < h; ++y) {
for (int x = 1; x < w; ++x) {
final int p = y * s + x;
n[p] = f.apply(d, s, x, y);
}
}
exécuter quelque chose comme
(final int[] d, final int s, final int x, final int y) -> {
final int p = s * y + x;
final int a = d[p] * 2
+ d[p - 1]
+ d[p + 1]
+ d[p - s]
+ d[p + s];
return (1000 * (a + 500))/6000;
};
sur différentes machines (mon ordinateur portable de travail, un W530 avec Core i7 3840QM, un serveur VM avec un noyau de un Xeon E5-1620, et un nœud Digital Ocean avec un noyau d'un CPU inconnu), je reçois à plusieurs reprises un coup de performance statistiquement significatif lors de l'appel d'une méthode vs inlining. Tous les tests ont été effectués sur Java 1.8.0_11 (Java Server HotSpot (TM) 64 bits).
machine de travail:
Benchmark Mode Samples Score Score error Units
c.s.q.ShaderBench.testProcessInline thrpt 200 40.860 0.184 ops/s
c.s.q.ShaderBench.testProcessLambda thrpt 200 22.603 0.159 ops/s
c.s.q.ShaderBench.testProcessProc thrpt 200 22.792 0.117 ops/s
serveur dédié, VM:
Benchmark Mode Samples Score Score error Units
c.s.q.ShaderBench.testProcessInline thrpt 200 40.685 0.224 ops/s
c.s.q.ShaderBench.testProcessLambda thrpt 200 16.077 0.113 ops/s
c.s.q.ShaderBench.testProcessProc thrpt 200 23.827 0.088 ops/s
DO VPS:
Benchmark Mode Samples Score Score error Units
c.s.q.ShaderBench.testProcessInline thrpt 200 24.425 0.506 ops/s
c.s.q.ShaderBench.testProcessLambda thrpt 200 9.643 0.140 ops/s
c.s.q.ShaderBench.testProcessProc thrpt 200 13.733 0.134 ops/s
Tous acceptable la performance, mais je suis intéressé à comprendre pourquoi l'appel a des frais généraux si importants et ce qui peut être fait pour optimiser cela. Actuellement en expérimentation avec différents ensembles de paramètres.
Il serait difficile, mais théoriquement possible, d'incruster toutes les opérations potentielles. Pour près d'une augmentation de performance de 2x, potentiellement la peine, mais la maintenance serait un cauchemar.
Je ne sais pas s'il existe un moyen raisonnable de regrouper un ensemble de répétitions; la plupart des opérations prennent plusieurs entrées (inconnues de l'appelant) et produisent une seule sortie.
Quelles autres options ai-je pour minimiser les frais généraux et les performances en soirée?
Pour votre information à des gens qui veulent répondre, la fonction 'f' est en fait une méthode d'interface normale, pas un' @ functionalInterface' – dkatzel
@dkatzel C'est une erreur de ma part (cela fait partie d'un projet de jouer avec Java 8), bien que cela puisse être conservé si cela aide d'une certaine façon. Il est assez important que 'f' soit remplissable par une classe ou lambda. – ssube