IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

vitesse de recherche dans un tableau


Sujet :

C++

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut vitesse de recherche dans un tableau
    Bonjour,

    il m'arrive un truc je n'y comprends rien.
    L'idée est la suivante: je créé un tableau "c-style", ainsi qu'une fonction exists qui regarde si un élément donné k existe dans ce tableau.
    J'utilise une méthode basique, brutale, moche, je sais qu'on peut faire beaucoup mieux et surtout beaucoup plus rapide, mais là n'est pas le problème.

    Prenons donc ce bout de code:
    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #include <iostream>
    #include <chrono>
     
    using namespace std;
     
    bool exists(int ints[], int size, int k)
    {
    	bool found = false;
    	int i = 0;
    	while (!found && i<size)
    		found = (ints[i++] == k);
    	return found;
    }
     
    void main()
    {
    	const int size = 100000;
    	const int k = 90000;
    	int ints[size];
     
    	for (int i = 0; i < size; ++i)
    		ints[i] = i; 
     
    	auto start = chrono::steady_clock::now();
    	cout << exists(ints, size, k) << endl;
    	cout << chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now() - start).count() << endl << endl;
     
    	start = chrono::steady_clock::now();
    	cout << exists(ints, size, k) << endl;
    	cout << chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now() - start).count() << endl << endl;
     
    	getchar();
    }
    Ce que je fais, c'est que je fais exactement 2 fois la même chose. Mais voilà l'output que j'obtiens:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    1
    395370
     
    1
    252556
    La première recherche et plus lente que la deuxième!
    Et c'est systématique, quelques soient les options de compilation que je choisis! Même en mode Debug!
    Je suis sous Windows, je compile avec Visual Studio 2017.
    J'ai relancé le test des dizaines de fois, et j'ai toujours le même ordre de différence de vitesse d'exécution.

    Comment est-ce possible? J'imagine que le compilateur doit effectuer quelque optimisation? Mais c'est étrange puisque le résultat est le même en Debug et/ou sans optimisation.
    Une idée?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    My guess : lors du premier traitement il y a mise en cache, lors du 2eme c'est deja en cache.

    Aussi, il me semble qu'utiliser ce genre de clock pour ce genre de mesures n'est pas top. Tu peux essayer avec la high_resolution_clock, mais l'implementation peut etre la meme, sinon faut directement taper dans les fonctions systemes, QueryPerformanceCounter sous Windows.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    L'écart des temps de traitement n'est pas directement lié au code, il est dû à ce qui se passe à l'intérieur même du processeur.
    Le temps de transfert d'une donnée de la RAM vers la mémoire cache est nettement plus important que les calculs que tu effectues.
    L'autre chose "compliquée" pour le processeur dans ton code est la prédiction de branchement. Quand il y a un test, le processeur essaie de deviner ce qu'il va se passer. Quand il y arrive, le saut qui suit le test est quasi-immédiat, quand il se trompe il va perdre du temps.
    Dans ton code les actions potentiellement "longues" sont donc :
    * le test : !found (le test sera 90000 fois vrai et une fois faux.)
    * le test : i<size (le test sera toujours vrai ici.)
    * la lecture de : ints[i] (il faudra parfois attendre que la mémoire parvienne au cache.)
    * le return de la fonction (mais il n'y en a qu'un.)
    * toutes les autres se font en moins d'une ns chacune.

    Quand tu appelles ta fonction une seconde fois :
    * le processeur se souvient que la dernière fois les 2 tests étaient presque toujours vrais, il va miser sur cela et devrait moins souvent commettre d'erreur de prédiction de branchement.
    * il y aura un peu plus de ints[i] qui seront encore dans le cache, et donc il y aura un peu moins de faute de page.

    Je pense que c'est surtout la mémoire cache qui est la cause ici.

  4. #4
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    @dalfab Inutile de parlé des failles meltdown et spectre ça n'a aucun rapport, surtout que ce genre d'optimisation est faite juste pour optimiser la pipeline (qu'on optimise manuellement sur certain autre processeur comme celui du CELL sur la PS3 mais bref c'est pas le sujet ici).

    Sinon oui c'est du a la mémoire cache , si tu veux avoir un temps pareil il faudrait faire un flush en asm(pour vider la mémoire cache ).

  5. #5
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    A noter qu'il existe `std::find` et `std::find_if` qui ne souffrent pas du syndrome du SESE -> moins de tests redondants.

    Si tu veux mesurer les perfs de ce genre de code, regarde des frameworks comme google.Benchmark. Ils sont fait pour ça -> les benchs sont faits sur des traitements réalisés plusieurs fois, il y a de quoi faire sauter les optimisations de type "variable non utilisée", etc.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  6. #6
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Ok, merci pour vos réponses
    Citation Envoyé par Luc Hermitte Voir le message
    A noter qu'il existe `std::find` et `std::find_if` qui ne souffrent pas du syndrome du SESE -> moins de tests redondants.
    Dans mon cas, j'ai finalement opté pour un std::binary_search qui, dans mon contexte, semble offrir les meilleurs résultats.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par r0d Voir le message
    Ok, merci pour vos réponses
    Dans mon cas, j'ai finalement opté pour un std::binary_search qui, dans mon contexte, semble offrir les meilleurs résultats.
    Ah, ben, de fait : si un tableau est trié (une question en passant l'est il "d'origine" ou doit-il être trié de manière explicite ), la recherche dichotomique présente par nature une complexité bien moindre (en O(log(n) contre une complexité en O(n) ), si bien que, sur 100 000 éléments, tu devrais pouvoir trouver l'élément recherché en 15 mouvements contre -- dans le pire des cas -- 100 000
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Tableaux] recherche dans un TABLEAU
    Par dunbar dans le forum Langage
    Réponses: 3
    Dernier message: 15/08/2006, 00h06
  2. [VBA-E]Recherche dans un tableau
    Par Zebulon777 dans le forum Macros et VBA Excel
    Réponses: 49
    Dernier message: 05/07/2006, 10h35
  3. Recherche dans un tableau
    Par Bes74 dans le forum Access
    Réponses: 5
    Dernier message: 04/07/2006, 17h26
  4. [VBA-E] recherche dans un tableau
    Par tibss dans le forum Macros et VBA Excel
    Réponses: 33
    Dernier message: 03/05/2006, 17h52
  5. URGENt: recherche dans un tableau trié par ordre alphabetiqu
    Par JulPop dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 12/02/2005, 17h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo