janvier
2010
Suite à un post sur le forum, je me suis posé la question s’il fallait utiliser des short comme indice de boucle for pour les boucle avec peu d’itérations (moins de 32768).
Au premier abord, cela peut être tentant étant donné qu’on gagne 2 octets (c’est toujours ça). Alors pourquoi utiliser un int alors qu’un short suffirait ?
Mais quand on y réfléchit, on voit bien que le int est le plus adapté. Il est en effet plus performant.
Pourquoi ?
En Java, toutes les opérations mathématiques sur des nombres entier (++ par exemple) se font en int. De ce fait, si on utilise un short comme indice de boucle, il faudra à chaque itération, effectuer un type casting implicite vers short, ce qui est plus couteux qu’une affectation directe vers int.
Pour appuyer mes propos, j’ai développé un petit test :
public static void main(String[] args){
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++){
for (int j = 0; j < 32760; j++){}
}
System.out.println("Temp pour int : " + (System.nanoTime() - startTime) / 1000000 + " ms");
startTime = System.nanoTime();
for (int k = 0; k < 100000; k++){
for (short f = 0; f < 32760; f++){}
}
System.out.println("Temp pour short : " + (System.nanoTime() - startTime) / 1000000 + " ms");
}
}
Qui me donne comme résultat :
Temp pour int : 1441 ms
Temp pour short : 3015 ms
La version avec short est donc deux fois plus lente !
Je parle ici des boucles for, mais le cas est le même lorsque vous utilisez une boucle while qui garde un indice et qui l’incrémente à chaque tour.
On peut relativiser en disant qu’ici on fait 100’000 fois 32’760 itérations et on ne perd qu’une seconde et demie. Néanmoins, dans des endroits critiques, on peut chercher à gagner le moindre nombre de millisecondes (voire nanosecondes).
Le short sera toutefois à privilégier dans le cas d’un stockage de données de petite taille.
A noter également que le int est à priviligier aux long, double et float pour les indices de boucle pour les mêmes raisons que le short. La version long est environ 3 fois plus lente et les versions double/float sont 2.5 fois plus lente.
En conclusion, utilisez toujours des int comme indices de boucle.
17 Commentaires + Ajouter un commentaire
Archives
- novembre 2011
- avril 2010
- mars 2010
- février 2010
- janvier 2010
- décembre 2009
- novembre 2009
- octobre 2009
- septembre 2009
- juillet 2009
- juin 2009
- avril 2009
- mars 2009
- février 2009
- octobre 2008
- septembre 2008
- mars 2008
- février 2008
- janvier 2008
- décembre 2007
- novembre 2007
- octobre 2007
- septembre 2007
- août 2007
- juillet 2007
- juin 2007
- mai 2007
- avril 2007
Catégories
- AMD
- Apple
- Cartes graphiques
- Chrome
- Conception
- Divers
- Eclipse
- English
- Hardware
- Informatique générale
- Intégration continue
- IntelliJ Idea
- Java
- JTheque
- Linux
- Logiciels
- Mes articles
- Mes critiques de livres
- Mes projets
- Microsoft
- Mon serveur perso
- Office 2007
- Open Source
- Outils
- Perso
- PHP
- Processeurs
- Programmation
- Sécurité
- Spring
- Windows Vista
- Windows XP
Salut,
j’ai fais le test avec Windows 64 bits, un processeur 64 bits et la JVM en 64 bits également mais avec short, int et long.
Donc dans mon cas, il y a une optimisation sur les long qui est lié clairement au full 64 bits.
J’obtiens 0 ms en long, en int, un peu plus et en short, encore plus. Ce n’est pas du à une suppression de boucle inutile comme certains l’ont déclarés car j’ai effectué également un autre test en faisant un calcul dans les boucles.
Merci pour les informations
Donc apparemment, les JVM font des optimisation sur le type phare (int 32 et long 64).
Oui, c’est intéressant à savoir tout ça. Du coup, vu que je développe une application 64 bits, je pense que j’utiliserais plus souvent des long.
Pour infos voici les scores que j’ai obtenu :
Temp pour int : 2 ms
Temp pour short : 1676 ms
Temp pour long : 0 ms
Ma config : (Core i7 3770K 16 Go de RAM, Win 7 64 bits, avec la JVM 64 bits).
La boucle avec short est 1676 fois plus lente qu’avec long Oo
Les dernières versions de la jvm 1.6 intègrent les optimisations sur les boucles « inutiles ». Pour ceux qui obtiennent 5ms c’est qu’en fait il n’y a aucune itération de faite.
J’ai un collègue qui a une jvm 32 bits sous linux et qui fait également les optimisations.
Je viens de faire les tests avec une machine virtuelle 64 bits, j’ai effectivement l’optimisation qui est faite pour les ints mais pas pour les short, ce qui m’étonne aussi.
Pour le code :
public class Test2 { <br />
public static void main(String[] args){ <br />
int n=0; <br />
long startTime = System.nanoTime(); <br />
<br />
for (int i = 0; i < 100000; i++){ <br />
for (int j = 0; j < 32760; j++){n++;} <br />
} <br />
<br />
System.out.println("Temp pour int : " + (System.nanoTime() - startTime) / 1000000 + " ms"); <br />
<br />
startTime = System.nanoTime(); <br />
<br />
for (int k = 0; k < 100000; k++){ <br />
for (short f = 0; f < 32760; f++){n++;} <br />
} <br />
<br />
System.out.println("Temp pour short : " + (System.nanoTime() - startTime) / 1000000 + " ms"); <br />
System.out.println("n="+n); <br />
} <br />
} <br />
J’obtiens :
Donc pareil. Par contre, si je lance le programe :
public class Test3 { <br />
public static void main(String[] args){ <br />
int n=0; <br />
long startTime = System.nanoTime(); <br />
<br />
for (int i = 0; i < 100000; i++){ <br />
for (int j = 0; j < 32760; j++){n=(n+1)%10;} <br />
} <br />
<br />
System.out.println("Temp pour int : " + (System.nanoTime() - startTime) / 1000000 + " ms"); <br />
<br />
startTime = System.nanoTime(); <br />
<br />
for (int k = 0; k < 100000; k++){ <br />
for (short f = 0; f < 32760; f++){n=(n+1)%10;} <br />
} <br />
<br />
System.out.println("Temp pour short : " + (System.nanoTime() - startTime) / 1000000 + " ms"); <br />
System.out.println("n="+n); <br />
} <br />
} <br />
J’obtiens :
Donc dans ma version de Java, il optimise beaucoup les boucles sur des entiers int, mais ne le fait pas sur des short. Par contre, je trouve etrange que Java 32 bits ne fait pas cette optimisation.
@ylarvor : ca depends de ce qu’on fait, pour une appli de gestion, on va pas forcément creuser ce genre d’opti, mais pour du distribué bien velu, ca peut être un problème (sur une appli que je connais bien, à environ 15000 message/secondes, le pouillème, ca compte )
@Petrus : tu as bien fait de préciser car la première chose que j’ai faite a été de rigoler ! lol
Pour les long : 2 fois plus long pour moi : ~ 6000 ms
Un collègue sous XP (long : ~10000, int : ~2000, short : ~3000)
mais lui à 1 simple coeur à 3.2 alors que moi, j’ai un 4 coeurs à 2.13
Dans l’exemple, par rapport à mes résultats, on voit que la fréquence est plus importante que le nombre de coeur (ce qui semble logique puisque l’exemple ne doit utiliser qu’un coeur).
Moi, aussi, sous RAD 7.0 :
Temp pour int : 35269 ms
Temp pour short : 48400 ms
Et on ne rigole pas ;-), ce sont les machines du client ;-P
C:Program FilesIBMSDP70runtimesbase_v61javabin>java -version
java version « 1.5.0 »
Java(TM) 2 Runtime Environment, Standard Edition (build pwi32devifx-20070608 (SR
5+IY99712))
IBM J9 VM (build 2.3, J2RE 1.5.0 IBM J9 2.3 Windows XP x86-32 j9vmwi3223-2007042
6 (JIT enabled)
Pour ma part, j’obtiens (Intel Xeon E5506, Window 7 / 32 bits, Java 6):
Temp pour int : 3092 ms
Temp pour short : 3604 ms
Et en utilisant currentTimeMillis() à la place de nanoTime() :
Temp pour int : 0 ms
Temp pour short : 1263218 ms
Je reste très dubitatif.
Puis je conclure que nanoTime est plus précis que currentTimeMillis pour ce genre de mesure, probablement.
Puis je conclure que nanoTime (Returns the current value of the most precise available system timer) dépend pour beaucoup du système ?
felicitation pour cet article trés amusant, c’est trés trés technique mais bien écrit. Vous noterez qu’il est rare d’avoir à optimiser une boucle de 32000 iteration en temps de réponse ou de se poser la question d’un int ou d’un short sur une machine de centaine de gigaoctet, je considère cette information un peu comme les test du monde, quel etait l’expression de l’année ? quel est le personnage de l’année ?… c’est du pur fun! mais c’est divertissant!
C’est bizarre…
Ma machine est aussi en 64 bits sur Windows Seven par contre, j’ai pas une machine virtuelle 64 bits. Il faudrait que je teste avec une machine virtuelle 64 bits. Je vais le faire ce soir pour voir si les résultats sont cohérents avec les tiens.
Ce qui m’impressionne le plus c’est que tu aies 5 ms et moi 1441, ca fait presque 300 fois plus rapide.
Il faudrait voir si ta JVM Server ne fait pas une optimisation sur la boucle qui est inutile en la supprimmant ?
Bonjour,
Je viens de lancer ton exemple, et j’obtiens des résultats bizards :
>java Test
Temp pour int : 5 ms
Temp pour short : 2470 ms
J’ai lancer plusieurs fois le test, et j’ai toujours les valeurs du même ordre.
Pour info, je suis sous windows vista 64bits, avec un icore7, et la version de java est :
>java -version
java version « 1.6.0_16″
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) 64-Bit Server VM (build 14.2-b01, mixed mode)
On dirait qu’en 64 bits, c’est très très penalisant les conversions vers les short.
Intéressant
Par contre, c’est bizarre que l’impact soit aussi grand avec des long en .Net.
bon à savoir
pour le fun, j’ai fait le même test en .Net, à priori, l’impact est le même, avec la différence que long est encore plus lent(6 fois plus que int)