2017-10-18 54 views
0

Je demande principalement Java, donc c'est ce que les exemples sont ici, mais je m'attendrais à ce que cela s'applique à d'autres langages comme C ou C++.Les compilateurs vont-ils reconnaître et optimiser les fonctions communes?


Le premier cas concerne les fonctions communes. Va-t-il reconnaître que le code fait une certaine chose et la remplacer par quelque chose de plus optimal?

exemples simples:

int max(int a,int b){ 
    return a>b?a:b; 
} 

int rotateLeft(int a,int b){ 
    return (a<<b)|(a>>>-b); 
} 

boolean testBitLittleEndian(int v,int i){ 
    return (v>>i&1)!=0; 
} 

Pivoter est pas évident, mais d'expliquer, le >>> est non signé changement/logique, et les montants décalage sont interprétés modulo la largeur. Puisque int s sont 32 bits, seuls les 5 bits les moins significatifs de la quantité de décalage sont utilisés.

Je pense que c'est au JIT de le remplacer par l'instruction native de rotation.

moins évidentes:

void intToByteLittleEndian(int v,byte[] b,int i){ 
    b[i+3]=(byte)(v>>24); 
    b[i+2]=(byte)(v>>16); 
    b[i+1]=(byte)(v>> 8); 
    b[i ]=(byte) v; 
} 

float median(float a,float b,float c){ 
    float d;//Swap 
    if(a>b){d=a;a=b;b=d;} 
    if(b>c){b=c;} 
    return a>b?a:b; 
} 

Même pas proche de l'optimum, mais il est simple et facile à lire. En raison de nombreuses variantes de ces fonctions, il peut être difficile pour le compilateur de les détecter et de les optimiser correctement.

Encore une fois, c'est peut-être au JIT de faire le remplacement car les instructions nécessaires pour la version optimisée ne sont pas disponibles depuis Java. Spécifiquement pour l'écriture int en tant que petite fonction d'endian, pour empêcher le compilateur de penser peut-être que nous pouvons écrire une partie du int et ensuite obtenir une exception hors limites, nous écrirons le dernier octet en premier. L'autre cas est celui des fonctions de bibliothèque standard, dont le compilateur peut être certain qu'il est supposé faire quelque chose de spécifique. Il n'y a pas besoin de reconnaître et de remplacer le code, donc même les grandes fonctions comme les maths dans BigInteger peuvent être optimisées si nécessaire.

La classe Math est l'une des classes spéciales spécifiquement remplacées par des instructions natives rapides lorsque cela est possible.

Il y a aussi certains d'entre eux qui sont trivial dans un langage de bas niveau, comme Double.doubleToLongBits():

int64_t doubleToLongBits(double v){ 
    return *(int64_t*)&v; 
} 

Un travail supplémentaire si le boutisme est erroné.

There are others with a pure Java implementation which will be optimized anyways.

Il est également possible que seules les fonctions de bibliothèque standard soient optimisées de cette manière, car il est difficile pour le compilateur de savoir exactement ce que fait votre code, ou pour d'autres raisons.


La principale raison pour laquelle je l'ai entendu pour les statisticiens de ne pas pouvoir faire une telle optimisation est qu'ils ne peuvent pas savoir exactement ce que vous voulez, ou dans ce cas, ce que votre code fait. Au-delà d'une certaine complexité (qui n'est pas très élevée) le compilateur arrête de pouvoir analyser votre code de manière à pouvoir le laisser faire ces optimisations.

+0

Vous pouvez toujours vérifier le code machine/octet produit. Bien sûr, vous ne verrez pas ce que fait le JIT. – Henry

+0

La question est beaucoup trop large. Le compilateur Java n'optimise généralement pas. Ce que fait la JVM dépend entièrement de la JVM en question. Il n'y a pas de réponse unique à votre question. * Marque *, * Plate-forme *, * Edition *, * Version *. Chaque combinaison peut avoir une réponse différente. – Andreas

+3

@Henry Vous pouvez voir le code machine généré par JIT: [Comment voir le code JIT compilé dans JVM?] (Https://stackoverflow.com/q/1503479/5221149) – Andreas

Répondre

0

Ceci est en fait un tas de questions. Mais ...

javac optimise rien, ce n'est pas son travail.

La JVM ... il n'y a pas de JVM unique. Il existe de nombreuses implémentations et elles optimisent généralement beaucoup à l'exécution. Parlons de hotspot sur amd64.

Il reconnaît certains modèles et certaines méthodes, google pour "intrinsèques JVM".

Par exemple, Math.max est optimisé en utilisant un mouvement conditionnel, si le profileur le dit (une branche conditionnelle rarement prise est plus rapide en moyenne).

Des méthodes comme Integer.rotateLeft, Long.rotateRight et bien d'autres sont optimisées pour une seule instruction. Votre propre code ne l'est pas.

Les opérations sur les bits sont implémentées efficacement.

Le reste de votre question ressemble plus à une réponse ...

A partir de ce blog vous pouvez en apprendre beaucoup sur les optimisations Hotspot.