Question

Par rapport à

  • Accès simple à la mémoire
  • Accès au disque
  • Accès à la mémoire sur un autre ordinateur (sur le même réseau)
  • Accès au disque sur un autre ordinateur (sur le même réseau)

en C ++ sous Windows.

Était-ce utile?

La solution

timings relatifs (ne devrait pas être décalé de plus d'un facteur de 100; -)

  • accès mémoire dans le cache = 1
  • appel / retour de fonction dans le cache = 2
  • accès mémoire hors cache = 10 .. 300
  • accès au disque = 1000 .. 1e8 (amorti en fonction du nombre d'octets transférés)
    • dépendant principalement du temps de recherche
    • le transfert lui-même peut être assez rapide
    • implique au moins quelques milliers d'opérations, car le seuil utilisateur / système doit être franchi au moins deux fois; une demande d'E / S doit être planifiée, le résultat doit être réécrit; éventuellement des tampons sont alloués ...
  • appels réseau = 1000 .. 1e9 (amorti en fonction du nombre d'octets transférés)
    • même argument que pour les entrées / sorties sur disque
    • la vitesse de transfert brute peut être assez élevée, mais certains processus sur l’autre ordinateur doivent faire le travail réel

Autres conseils

Un appel de fonction consiste simplement à déplacer le pointeur d’image en mémoire sur la pile et à ajouter une nouvelle image par-dessus. Les paramètres de la fonction sont décalés dans les registres locaux pour être utilisés et le pointeur de la pile est avancé vers le nouveau sommet de la pile pour l'exécution de la fonction.

En comparaison avec le temps

Appel de fonction ~ accès mémoire simple
Appel de fonction & Lt; Accès au disque
Appel de fonction & Lt; accès mémoire sur un autre ordinateur
Appel de fonction & Lt; accès au disque sur un autre ordinateur

Par rapport à un simple accès mémoire - un peu plus, vraiment négligeable.

Par rapport à tout ce qui est répertorié - ordres de grandeur moins.

Cela devrait être vrai pour à peu près n'importe quelle langue sur n'importe quel système d'exploitation.

En général, un appel de fonction sera légèrement plus lent qu'un accès en mémoire car il doit en réalité effectuer plusieurs accès en mémoire pour effectuer l'appel. Par exemple, plusieurs push et pops de la pile sont requis pour la plupart des appels de fonction utilisant __stdcall sur x86. Mais si votre accès à la mémoire se trouve sur une page qui ne se trouve même pas dans le cache L2, l’appel de la fonction peut être beaucoup plus rapide si la destination et la pile se trouvent toutes dans les caches de mémoire de la CPU.

Pour tout le reste, un appel de fonction est beaucoup plus rapide.

Difficile de répondre car de nombreux facteurs entrent en jeu.

Tout d'abord, & "Accès simple à la mémoire &"; n'est pas simple. Depuis les vitesses modernes, un processeur peut ajouter deux chiffres plus rapidement qu’il n’obtient un numéro d’un côté à l’autre de la puce (La vitesse de la lumière - Ce n’est pas simplement une bonne idée, c’est la loi.)

La fonction est-elle appelée dans le cache de la mémoire de la CPU? Est-ce que l'accès mémoire que vous comparez aussi?

L’appel de fonction effacera ensuite le pipeline d’instructions de la CPU, ce qui affectera la vitesse de manière non déterministe.

En supposant que vous vouliez parler de la surcharge de l’appel lui-même, plutôt que de ce que l’appelé pourrait faire, c’est nettement, beaucoup plus rapide que tout, sauf le & "simple &"; accès mémoire.

C’est probablement plus lent que l’accès à la mémoire, mais sachez que puisque le compilateur peut effectuer une mise en ligne, la surcharge des appels de fonction est parfois nulle. Même si ce n'est pas le cas, il est au moins possible sur certaines architectures que certains appels au code déjà dans le cache d'instructions soient plus rapides que l'accès à la mémoire principale (non mise en cache). Cela dépend du nombre de registres à empiler avant de faire l'appel, et ce genre de chose. Consultez votre compilateur et la documentation de la convention d'appel, bien qu'il soit peu probable que vous puissiez le comprendre plus rapidement que de désassembler le code émis.

Notez également que " simple " L’accès à la mémoire n’est parfois pas le cas. Si le système d’exploitation doit importer la page à partir d’un disque, vous aurez une longue attente. Il en irait de même si vous sautiez dans le code actuellement affiché sur le disque.

Si la question sous-jacente est & "; quand devrais-je optimiser mon code pour minimiser le nombre total d'appels de fonction effectués? &" ;, alors la réponse est & "; très proche de jamais ";

Ce lien apparaît souvent dans Google. Pour référence future, j’ai exécuté un court programme en C # sur le coût d’un appel de fonction. La réponse est: & "; Environ six fois le coût du transfert en ligne &"; Vous trouverez ci-dessous des détails, voir // Sortie en bas. UPDATE: pour mieux comparer des pommes avec des pommes, j'ai modifié Class1.Method pour renvoyer 'void', comme suit: public void Method1 () {// return 0; }
Pourtant, en ligne est plus rapide de 2x: inline (avg): 610 ms; appel de fonction (avg): 1380 ms. La réponse, mise à jour, est donc & Environ deux fois & «;

using System; using System.Collections.Generic; using System.Linq; using System.Text; utiliser System.Diagnostics;

espace de noms FunctionCallCost {     programme de classe     {         static void Main (string [] args)         {             Debug.WriteLine (& Quot; stop1 & Quot;));             int iMax = 100000000; // 100M             DateTime funcCall1 = DateTime.Now;             Chronomètre sw = Chronomètre.StartNouveau ();

        for (int i = 0; i < iMax; i++)
        {
            //gives about 5.94 seconds to do a billion loops, 
          // or 0.594 for 100M, about 6 times faster than
            //the method call.
        }

        sw.Stop(); 

        long iE = sw.ElapsedMilliseconds;

        Debug.WriteLine("elapsed time of main function (ms) is: " + iE.ToString());

        Debug.WriteLine("stop2");

        Class1 myClass1 = new Class1();
        Stopwatch sw2 = Stopwatch.StartNew();
        int dummyI;
        for (int ie = 0; ie < iMax; ie++)
        {
          dummyI =  myClass1.Method1();
        }
        sw2.Stop(); 

        long iE2 = sw2.ElapsedMilliseconds;

        Debug.WriteLine("elapsed time of helper class function (ms) is: " + iE2.ToString());

        Debug.WriteLine("Hi3");


    }
}

// Classe 1 ici en utilisant le système; using System.Collections.Generic; using System.Linq; using System.Text;

espace de noms FunctionCallCost {     classe Class1     {

    public Class1()
    {
    }

    public int Method1 ()
    {
        return 0;
    }
}

}

// Sortie: stop1 temps écoulé de la fonction principale (ms) est de: 595 stop2 Le temps écoulé de la fonction de classe auxiliaire (ms) est: 3780

stop1 temps écoulé de la fonction principale (ms) est de: 592 stop2 Le temps écoulé de la fonction de classe auxiliaire (ms) est: 4042

stop1 temps écoulé de la fonction principale (ms) est de: 626 stop2 Le temps écoulé de la fonction de classe auxiliaire (ms) est: 3755

Le coût de l’appel de la fonction, sans l’exécuter complètement? ou le coût d'exécution de la fonction? La simple mise en place d’un appel de fonction n’est pas une opération coûteuse (mise à jour du PC?). mais évidemment, le coût d’une fonction s’exécutant entièrement dépend de ce qu’elle fait.

N'oublions pas que le C ++ a des appels virtuels (beaucoup plus coûteux, environ x 10) et que sur Windows, vous pouvez vous attendre de VS à des appels en ligne (0 coût par définition, car il n'y a plus d'appel dans le binaire)

Cela dépend de ce que fait cette fonction. Elle serait la deuxième de votre liste si elle faisait la logique avec des objets en mémoire. Plus bas dans la liste s'il inclut l'accès au disque / au réseau.

Un appel de fonction implique généralement quelques copies en mémoire (souvent dans des registres, ils ne doivent donc pas prendre beaucoup de temps), puis une opération de saut. Cela sera plus lent qu'un accès mémoire, mais plus rapide que toutes les autres opérations mentionnées ci-dessus, car elles nécessitent une communication avec un autre matériel. La même chose devrait normalement s'appliquer à toute combinaison système d'exploitation / langue.

Si la fonction est insérée au moment de la compilation, son coût devient équivalent à 0.

0 bien sûr, ce que vous auriez pu obtenir en n’ayant pas d’appel de fonction, c’est-à-dire: en ligne vous-même.

Cela semble évidemment excessivement évident quand je l’écris comme ça.

Le coût d'un appel de fonction dépend de l'architecture. x86 est considérablement plus lent (quelques horloges plus une horloge ou environ par argument), alors que 64 bits est beaucoup moins, car la plupart des arguments de fonction sont passés dans des registres plutôt que sur la pile.

L’appel de fonction est en fait une copie des paramètres de la pile (accès mémoire multiple), la sauvegarde des registres, l’exécution du code et enfin la copie du résultat et la restauration des registres (la sauvegarde / restauration des registres dépend du système).

Donc .. parlant relativement:

  • Appel de fonction > Accès simple à la mémoire.
  • Appel de fonction < < Accès au disque - comparé à la mémoire, il peut coûter des centaines de fois plus cher.
  • Appel de fonction < < Accès à la mémoire sur un autre ordinateur: la bande passante du réseau et le protocole sont les plus meurtriers ici.
  • Appel de fonction < < < Accès au disque sur un autre ordinateur - tout ce qui précède et plus encore:)

Seul l'accès à la mémoire est plus rapide qu'un appel de fonction.

Mais l'appel peut être évité si le compilateur utilise l'optimisation en ligne (pour le (s) compilateur (s) de GCC et non seulement il est activé lors de l'utilisation du niveau 3 d'optimisation (-O3)).

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