Question

Moi-même et un autre développeur sur mon temps a récemment déménagé à partir d'un Core 2 Duo de la machine au travail à un nouveau Core 2 Quad 9505;Windows XP SP3 32 bits avec JDK 1.6.0_18.

Ainsi, un couple de nos tests unitaires automatisés pour certains timing/statistiques/métriques de code d'agrégation est rapidement mis en échec, en raison de ce qui semble être ridicule valeurs de retour à partir du Système.nanoTime().

Le code de Test qui affiche ce comportement, de manière fiable, sur ma machine:

import static org.junit.Assert.assertThat;

import org.hamcrest.Matchers;
import org.junit.Test;

public class NanoTest {

  @Test
  public void testNanoTime() throws InterruptedException {
    final long sleepMillis = 5000;

    long nanosBefore = System.nanoTime();
    long millisBefore = System.currentTimeMillis();

    Thread.sleep(sleepMillis);

    long nanosTaken = System.nanoTime() - nanosBefore;
    long millisTaken = System.currentTimeMillis() - millisBefore;

    System.out.println("nanosTaken="+nanosTaken);
    System.out.println("millisTaken="+millisTaken);

    // Check it slept within 10% of requested time
    assertThat((double)millisTaken, Matchers.closeTo(sleepMillis, sleepMillis * 0.1));
    assertThat((double)nanosTaken, Matchers.closeTo(sleepMillis * 1000000, sleepMillis * 1000000 * 0.1));
  }

}

De sortie standard:

millisTaken=5001
nanosTaken=2243785148

L'exécutant 100x rendements nano résultats entre 33% et 60% du temps de sommeil;habituellement autour de 40%, bien que.

Je comprends les faiblesses de la précision des temporisations dans Windows, et avoir lu liées fils comme Est Système.nanoTime() cohérente à travers les threads?, cependant ma compréhension est que le Système.nanoTime() est prévu pour la fin, nous utilisons :- la mesure du temps écoulé;avec plus de précision que currentTimeMillis().

Personne ne sait pourquoi il est de retour tels fou résultats?Est-ce susceptible d'être une architecture matérielle problème (le seul grand chose qui a changé, c'est le CPU/carte Mère sur cette machine)?Un problème avec le Windows HAL avec mon matériel actuel?Un JDK problème?Dois-je abandonner nanoTime()?Dois-je connecter un bug quelque part, ou des suggestions sur comment je pourrais poursuivre l'enquête?

MISE À JOUR 19/07 03:15 UTC:Après avoir essayé finnw du cas de test ci-dessous j'ai fait un peu plus de Googler, à venir à travers les entrées telles que bugid:6440250.Il m'a aussi rappelé de quelque autre comportement étrange que j'ai remarqué vendredi en fin d'où pings étaient de retour négatif.J'ai donc ajouté /usepmtimer pour ma botte.ini et maintenant, tous les tests se comportent comme prévu., et mon ping est normal aussi.

Je suis un peu confus au sujet de pourquoi c'était toujours une question de bien;de ma lecture j'ai pensé TSC vs PMT questions ont été en grande partie résolu dans Windows XP SP3.Serait-ce parce que ma machine était à l'origine SP2, et a été patché pour SP3 plutôt que de installé à l'origine dans le SP3?Maintenant, je me demande aussi si je dois être l'installation de patchs comme celle de MS KB896256.Je devrais peut-être prendre cela avec le bureau d'entreprise créer une équipe?

Était-ce utile?

La solution

Le problème a été résolu (avec des soupçons ouverts sur l'adéquation de Nanotime () sur des systèmes multicœurs!) En ajoutant / USEPMTIMER à la fin de mon C: \ Boot.ini chaîne;Forcer les fenêtres à utiliser le minuteur de gestion de l'alimentation plutôt que le TSC.C'est une question ouverte sur la raison pour laquelle j'avais besoin de le faire, je suis sur XP SP3, car j'ai compris que c'était la valeur par défaut, mais peut-être que c'était dû à la manière dont ma machine a été patchée à SP3.

Autres conseils

sur mon système (Windows 7 64 bits, Core I7 980X):

nanosTaken=4999902563
millisTaken=5001

System.NanOTIMOTIME () Utilise des appels spécifiques au système d'exploitation, alors je m'attends à ce que vous voyiez un bogue dans votre combinaison Windows / processeur.

Vous voulez probablement lire les réponses à cette autre question de dépassement de la pile:

Il est difficile de dire si c'est un bug ou juste normal de la minuterie de la variation entre les cœurs.

Une expérience que vous pourriez faire est d'essayer d'utiliser les appels natifs de forcer l'exécution du thread sur une base spécifique.

Aussi, pour écarter la gestion de l'alimentation effets, essayez de tourner en boucle comme une alternative à sleep():

import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.W32API;

public class AffinityTest {

    private static void testNanoTime(boolean sameCore, boolean spin)
    throws InterruptedException {
        W32API.HANDLE hThread = kernel.GetCurrentThread();
        final long sleepMillis = 5000;

        kernel.SetThreadAffinityMask(hThread, new NativeLong(1L));
        Thread.yield();
        long nanosBefore = System.nanoTime();
        long millisBefore = System.currentTimeMillis();

        kernel.SetThreadAffinityMask(hThread, new NativeLong(sameCore? 1L: 2L));
        if (spin) {
            Thread.yield();
            while (System.currentTimeMillis() - millisBefore < sleepMillis)
                ;
        } else {
            Thread.sleep(sleepMillis);
        }

        long nanosTaken = System.nanoTime() - nanosBefore;
        long millisTaken = System.currentTimeMillis() - millisBefore;

        System.out.println("nanosTaken="+nanosTaken);
        System.out.println("millisTaken="+millisTaken);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Sleeping, different cores");
        testNanoTime(false, false);
        System.out.println("\nSleeping, same core");
        testNanoTime(true, false);
        System.out.println("\nSpinning, different cores");
        testNanoTime(false, true);
        System.out.println("\nSpinning, same core");
        testNanoTime(true, true);
    }

    private static final Kernel32Ex kernel =
        (Kernel32Ex) Native.loadLibrary(Kernel32Ex.class);

}

interface Kernel32Ex extends Kernel32 {
    NativeLong SetThreadAffinityMask(HANDLE hThread, NativeLong dwAffinityMask);
}

Si vous obtenez des résultats très différents en fonction sur le noyau de sélection (p. ex.5000ms sur la même base, mais 2200ms sur les différents cœurs) qui donnerait à penser que le problème est tout à fait naturel de la minuterie de la variation entre les cœurs.

Si vous obtenez des résultats très différents de dormir vsla filature, il est plus probable en raison de la gestion de l'alimentation ralentissement des horloges.

Si aucun des quatre résultats sont près de 5000 ms, alors il peut être un bug.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top