web-dev-qa-db-fra.com

Comment puis-je mesurer le temps avec la précision microseconde en Java?

J'ai vu sur Internet que je devais utiliser System.nanoTime() mais cela ne fonctionne pas pour moi - il me donne le temps avec précision millisecondes. Je dois juste les microsecondes avant et après ma fonction exécute pour que je sache combien de temps il faut. J'utilise Windows XP.

Au fond, j'ai ce code que, par exemple, fait 1 million jusqu'à 10 millions d'insertions dans un Java liste chaînée Le problème est que je ne peux pas mesurer la précision à droite;. Parfois prend moins de temps pour insérer tout dans la liste plus petite.

Voici un exemple:

class test
{
    public static void main(String args[])
    {
        for(int k=1000000; k<=10000000; k+=1000000)
        {
            System.out.println(k);
            LinkedList<Integer> aux = new LinkedList<Integer>();
            //need something here to see the start time
            for(int i=0; i<k; i++)
                aux.addFirst(10000);
            //need something here to see the end time
            //print here the difference between both times
        }
    }
}

Je l'ai fait plusieurs fois - il y avait une boucle extérieure faire 20 fois pour chaque k - mais le résultat ne sont pas bons. Parfois, il faut moins de temps pour faire 10 millions d'insertions de 1 million, parce que je ne reçois pas le temps mesuré correctement avec ce que je me sers maintenant (System.nanoTime ())

Edit 2: Oui, j'utilise la machine virtuelle Java du Soleil.

Edit 3: je l'ai fait quelque chose de mal dans le code, je vais voir si le changement il fait ce que je veux.

Edit 4: Mon erreur, il semble œuvres System.nanoTime (). Phew.

22
jao

Je suppose que depuis System.nanoTime() Utilise la "minuterie système disponible la plus précise" qui n'a apparemment que millisecond-précision sur votre système, vous ne pouvez rien obtenir de mieux.

31
Zach Scrivena

Ce n'est pas clair pour moi exactement ce que vous êtes comparatif, mais en général, tout test qui prend tel une courte durée à courir, cette précision plus faible que 50 ms est pertinente, va être très sujette à d'autres perturbations.

J'essaie généralement de faire courir des repères pendant au moins 10 secondes. Le cadre que j'écris pour le moment devinera combien d'itérations à courir afin que cela faudra 30 secondes. Cela signifie que vous n'obtiendrez pas radicalement des résultats différents simplement parce que d'autres processus ont volé la CPU pour quelques millisecondes.

Courir plus longtemps est presque toujours une meilleure approche que d'essayer de mesurer une précision finale.

25
Jon Skeet

System.nanoTime() Utilise un compteur dans la CPU et est généralement précis à environ 1 micro-seconde sous Windows XP et Linux.

Remarque: Windows XP est souvent moins précis sur des machines multi-processeurs car elle ne compense pas les différents processeurs ayant des compteurs différents. Linux fait. Note 2: Il sera dériver par rapport au système.CurrentTimemeMiS () Comme il est basé sur la précision de l'horloge pour votre CPU (qui n'a pas besoin d'être aussi précise sur une période de temps), plutôt que de l'horloge que vous avez pour obtenir le temps. (Ce qui dérive moins par jour, mais a moins de granularité)

Dans votre référence, vous testez essentiellement la vitesse à laquelle vous pouvez créer de nouveaux objets. Sans surprise vos résultats variera considérablement sur la base de vos paramètres de GC et de la manière dont une GC a récemment été effectuée.

Essayez d'exécuter vos tests avec les options suivantes et vous devriez voir des résultats très différents.

-verbosegc -XX:NewSize=128m -mx256m
4
Peter Lawrey

C'est bizarre. Système.NanOTIME () est censé fonctionner. Utilisez-vous le Sun JVM?

Pouvez-vous simplement répéter votre opération 1000 fois et diviser le temps d'ici 1000 pour savoir ce que vous devez savoir?

3
Sarel Botha

Vous devez répéter les tests à des milliers de fois. Il y a beaucoup de choses qui se produisent qui influenceront vos mesures, telles que la collecte des ordures, les E/S, l'échange d'échange/sortie, la taille des fils de la file d'attente, etc.

3
Tiago

Si vous voulez un résultat fiable, utilisez un profileur. Je vous suggère Visualvm , facile à installer et est fourni avec le JDK à partir de la version 1.6.0_07.

C'est un outil visuel facile à utiliser qui intègre plusieurs outils de commande JDK et des capacités de profilage léger.

3
marcospereira

Oui, la précision et la précision du système.Nanotime est généralement beaucoup meilleure que System.Currenttimemillis, mais sans garantie: cela peut devenir tout aussi mauvais dans le pire des cas.

Threadmxbean.getCurrentThreadCuTime a tendance à donner des moments plus petits, mais sa résolution n'est pas claire et il a d'autres inconvénients (voulez-vous vraiment que l'heure du processeur?, La sémantique de la plate-forme dépendante, prise en charge sur votre plate-forme?).

Mesurer le temps avec les trois techniques a également un certain coût, c'est-à-dire qu'il faut du temps lui-même, ce qui peut déformer les mesures. Les coûts sont fortement dépendants de la plate-forme, mais coûtent souvent (System.Currenttimemillis) << Coût (System.NanOTIME) << Coût (Threadmxbean.getCurrentThreadCuTime).

À propos de Micro Benchmarking en général, voir

1
DaveFar

Il se peut que le système d'exploitation sous-jacent ne fournisse pas de chronométrage de la précision nanoseconde.

Il y a aussi un post plus ancien .

1
starblue

Pour notre récent profilage, j'ai trouvé que ThreadMXBean.getCurrentThreadCpuTime() et l'option -XX:+UseLinuxPosixThreadCPUClocks a fait ce dont nous avions besoin.

Voir http://bugs.java.com/view_bug.do?bug_id=6888526 pour plus de détails

0
Andrew Jessop

une solution "rapide et sale" que je suis finalement allé avec:

TimeUnit.NANOSECONDS.toMicros(System.nanoTime());

METTRE À JOUR:

Je suis allé à l'origine avec System.Nanotime, mais j'ai découvert que cela ne devrait être utilisé que pour le temps écoulé, j'ai finalement modifié mon code pour travailler avec des millisecondes ou à certains endroits d'utilisation:

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

mais cela ajoutera simplement des zéros à la fin de la valeur (micros = millis * 1000)

Laissé cette réponse ici comme un "panneau d'avertissement" au cas où quelqu'un d'autre pense à Nanotime :)

0
keisar

Une telle référence qui repose sur un intervalle de temps court vous donne des résultats peu fiables. Vous obtiendrez toujours des résultats différents, en raison de facteurs externes tels que des E/S, l'échange, les commutateurs de processus, les caches, la collecte des ordures, etc. En outre, le JVM optimise vos appels. Il est donc probable que les premières choses mesurées se produisent plus tard que la dernière appel. Le JVM commence de plus en plus pour optimiser les commandes que vous exécutez.

De plus, la méthode comme System.NanOTIME () dépend des minuteries du système sous-jacent. Ils peuvent (et très probablement) ne pas avoir la granularité à mesurer dans cette précision. Citer le [~ # ~] API [~ # ~ ~] :

Cette méthode fournit une précision nanoseconde, mais pas nécessairement une précision nanoseconde. Aucune garantie n'est faite sur la manière dont les valeurs changent fréquemment.

Pour vraiment mesurer avec une haute précision, vous devez accéder à un matériel de synchronisation externe avec une précision garantie.

Pour rendre votre référence plus stable plus stable, vous devez l'exécuter plus d'une fois et mesurer de plus gros intervalles de temps que des millisecondes.

0
Mnementh