2010-01-21 4 views
3

Les trois derniers appels de méthode prennent env. doubler le temps que les quatre premiers. La seule différence est que leurs arguments ne tiennent plus en nombre entier. Mais cela devrait-il être important? Le paramètre est déclaré long, il doit donc être long pour le calcul. Est-ce que l'opération modulo utilise un autre algorithme pour les nombres> maxint? J'utilise amd athlon64 3200+, winxp sp3 et vs2008.Comportement de comportement étrange pour un fonctionnement modulo 64 bits

 Stopwatch sw = new Stopwatch(); 
     TestLong(sw, int.MaxValue - 3l); 
     TestLong(sw, int.MaxValue - 2l); 
     TestLong(sw, int.MaxValue - 1l); 
     TestLong(sw, int.MaxValue); 
     TestLong(sw, int.MaxValue + 1l); 
     TestLong(sw, int.MaxValue + 2l); 
     TestLong(sw, int.MaxValue + 3l); 
     Console.ReadLine(); 

    static void TestLong(Stopwatch sw, long num) 
    { 
     long n = 0; 
     sw.Reset(); 
     sw.Start(); 
     for (long i = 3; i < 20000000; i++) 
     { 
      n += num % i; 
     } 
     sw.Stop(); 
     Console.WriteLine(sw.Elapsed);    
    } 

EDIT: je maintenant essayé la même chose avec C et la question ne pas se produit ici, toutes modulo opérations prennent en même temps, dans la version et en mode débogage avec et sans optimisations activées:

#include "stdafx.h" 
#include "time.h" 
#include "limits.h" 

static void TestLong(long long num) 
{ 
    long long n = 0; 

    clock_t t = clock(); 
    for (long long i = 3; i < 20000000LL*100; i++) 
    { 
     n += num % i; 
    } 

    printf("%d - %lld\n", clock()-t, n); 
} 

int main() 
{ 
    printf("%i %i %i %i\n\n", sizeof (int), sizeof(long), sizeof(long long), sizeof(void*)); 

    TestLong(3); 
    TestLong(10); 
    TestLong(131); 
    TestLong(INT_MAX - 1L); 
    TestLong(UINT_MAX +1LL); 
    TestLong(INT_MAX + 1LL); 
    TestLong(LLONG_MAX-1LL); 

    getchar(); 
    return 0; 
} 

EDIT2:

Merci pour les excellentes suggestions. J'ai trouvé que les deux. Net et C (en mode de débogage ainsi que dans le mode de libération) n'utilisent pas atomiquement les instructions cpu pour calculer le reste, mais ils appellent une fonction qui le fait.

Dans le programme c je pourrais obtenir le nom de celui-ci qui est "_allrem". Il a également affiché des commentaires de source complète pour ce fichier, donc j'ai trouvé l'information que cet algorithme spécial cas les diviseurs 32 bits au lieu de dividendes, ce qui était le cas dans l'application. J'ai également découvert que la performance du programme c est vraiment seulement affectée par la valeur du diviseur, mais pas le dividende. Un autre test a montré que la performance de la fonction restante dans le programme .net dépend à la fois du dividende et du diviseur. BTW: Même des ajouts simples de longues valeurs longues sont calculés par des instructions add et adc consécutives. Donc, même si mon processeur lui-même appelle 64bit, il est vraiment pas :(

EDIT3:

maintenant je courais l'application c sur un ordinateur Windows 7 édition 64 bits, compilé avec Visual Studio 2010. La chose drôle est le comportement de la performance reste le même, bien que maintenant (j'ai vérifié la source d'assemblage) vraies 64 instructions de bits sont utilisés.

+1

En ce qui concerne votre dernière observation, si vous utilisez Windows XP, vous êtes presque certain que vous utilisez votre processeur 64 bits en mode 32 bits. – caf

+0

Votre processeur est en réalité en 64 bits, c'est votre système d'exploitation et votre compilateur qui fonctionnent en mode 32 bits. –

Répondre

3

Avez-vous essayé d'effectuer les mêmes opérations dans le code natif sur votre boîte?

Je n » t être surpris si les opérations restantes natives 64 bits cas-situations spéciales wh Les deux arguments sont dans la plage de 32 bits, en déléguant cela à l'opération 32 bits. (Ou peut-être c'est le JIT qui fait cela ...) Il est logique d'optimiser ce cas, n'est-ce pas?

+0

+1 pour l'observation que cela pourrait être le JIT au travail. –

+0

Je l'ai maintenant essayé avec le code natif et le problème ne se produit pas ici. Bien sûr, il est logique qu'une telle optimisation soit faite, mais pourquoi est-ce parfois et parfois non. Mais je ne crois pas que ce soit le JIT parce que la valeur en question est passée en argument et je ne pense pas que la méthode soit triturée plusieurs fois dans le même processus. – codymanix

4

Quelle observation curieuse. Voici quelque chose que vous pouvez faire pour étudier ceci: ajoutez une "pause" au début du programme, comme une Console.ReadLine, mais APRÈS le premier appel à votre méthode. Ensuite, construisez le programme en mode "release". Puis démarrez le programme pas dans le débogueur. Ensuite, à la pause, attachez le débogueur. Déboguer à travers et jeter un coup d'oeil au code jitted pour la méthode en question. Il devrait être assez facile de trouver le corps de la boucle.

Il serait intéressant de savoir comment le corps de la boucle généré diffère de celui de votre programme C.La raison de toutes ces opérations est que la gigue modifie le code généré lors de l'insertion d'un ensemble de "débogage" ou lors de l'insertion d'un programme auquel un débogueur est déjà associé; il jette le code qui est plus facile à comprendre dans un débogueur dans ces cas. Il serait plus intéressant de voir ce que la gigue pense être le "meilleur" code généré pour ce cas, donc vous devez attacher le débogueur en retard, après que la gigue ait fonctionné.

+0

Merci pour les excellentes suggestions. J'ai découvert beaucoup de choses intéressantes, voir mes nouvelles modifications :) – codymanix