6
votes

Le moyen le plus rapide d'analyser les annuaires NTFS récursifs en C ++

J'ai écrit un petit chenille pour numériser et recourir à des structures de répertoire.

basé sur le Dirent (qui est une petite enveloppe autour de FindnextFilea) Dans mes premiers points de repère, il est étonnamment lent: p>

environ 123473ms pour 4500 fichiers (ThinkPad T60P local Samsung 320 GB 2.5 "HD). 121481 Fichiers trouvés dans 123473 millisecondes Cette vitesse est-elle normale? P>

Ceci est mon code: P>

int testPrintDir(std::string  strDir, std::string strPattern="*", bool recurse=true){
  struct dirent *ent;
  DIR *dir;
  dir = opendir (strDir.c_str());
  int retVal = 0;
  if (dir != NULL) {
    while ((ent = readdir (dir)) != NULL) {
      if (strcmp(ent->d_name, ".") !=0 &&  strcmp(ent->d_name, "..") !=0){
        std::string strFullName = strDir +"\\"+std::string(ent->d_name);
        std::string strType = "N/A";
        bool isDir = (ent->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=0;
        strType = (isDir)?"DIR":"FILE";                 
        if ((!isDir)){
             //printf ("%s <%s>\n", strFullName.c_str(),strType.c_str());//ent->d_name);
          retVal++;
        }   
        if (isDir && recurse){
             retVal += testPrintDir(strFullName, strPattern, recurse);
        }
      }
    }
    closedir (dir);
    return retVal;
  } else {
    /* could not open directory */
    perror ("DIR NOT FOUND!");
    return -1;
  }
}


2 commentaires

Si vous avez envie de pouvoir exécuter mon outil SIZERORTER [ Color-of-Code.de/... Il ne fait pas beaucoup plus que de ramper l'arborescence de répertoires et de vérifier la taille et les horodatages et les signaler. Si la vitesse est beaucoup plus rapide, elle réside probablement à une journalisation car j'utilise du code très similaire à la vôtre.


Dupliqué possible de Comment puis-je éumérer rapidement des répertoires sur Win32?


4 Réponses :


3
votes

La toute première fois que vous effectuez un annexier récursif, vous devez probablement énumérer l'intégralité du répertoire actuel et la file d'attente de tous les annuaires que vous trouvez à visiter lorsque vous avez terminé. De cette façon, vous risquez de tirer parti de toute optimisation immédiate des optimisations de lecture en ligne NTFS pourrait faire.

sur les rampes de répertoires récursifs ultérieurs, si les métadonnées pour les répertoires correspondent à la cache du système, peu importe la façon dont vous le faites.

Edit: Clarifiez comment vous devriez visiter des annuaires. Ce n'est pas techniquement une première recherche de la largeur.


2 commentaires

Cela ne va pas faire beaucoup de différence dans la pratique. Les API FindexFile à ébullition à l'API ZWQueryDirectoryFile / NTQuyDirectoryFile ( MSDN .microsoft.com / fr-US / Bibliothèque / FF567047 (vs.85) .aspx ), qui récupère l'ensemble du répertoire à la fois. Les API Findexfile utilisent déjà un tampon interne autour de cette fonction. Le but de la FindClose API est la destruction dudit tampon.


@Billy, dans ce cas, la deuxième partie de ma réponse commence :) Bien que avec un répertoire suffisamment rempli, ce tampon nécessite-t-il à nouveau sur le disque? Auquel cas la première partie s'applique aussi :)



0
votes

Vous maintenez des poignées DIR ouvertes pendant la plongée récursive. Gardez plutôt une liste locale de répertoires que vous avez rencontrés et les traiter à l'extérieur de cette boucle, après la fermétrir () .


1 commentaires

Cela va augmenter la consommation de mémoire mais il aura peu à voir avec le temps de numérisation de fichiers, qui est limité par le disque dur.



5
votes

Il y a certaines circonstances où une telle vitesse est normale oui. Premièrement, l'utilisation de FindFirstFilea au lieu de FindFirstFileW va engager des frais généraux pour la conversion de l'UTF-16 vers ANSI. Deuxièmement, si vous traversez des répertoires qui n'ont pas encore été consultés par le système d'exploitation, vous encourrez au moins une pénalité de recherche (environ 16 ms pour la plupart des disques durs du consommateur), limitant votre énumération à bien moins de 100 chèques de répertoire par seconde. Cela va empirer si la table de fichiers principaux sur l'entraînement donné est mal fragmentée.

En ce qui concerne le nombre de fichiers, cela dépend plus du nombre de fichiers par répertoire que le nombre de fichiers eux-mêmes.


4 commentaires

Un disque dur de 7200 tr / min spins 120 fois par seconde. Une rotation complète est donc un peu plus de 8 ms. Étant donné que la tête doit également bouger, le temps de recherche est distribué entre dire (2, 10ms), avec une moyenne d'environ 6 ms, plus une partie d'une rotation est nécessaire pour lire les données. Cela convient avec des heures de lecture de 8-9ms citées sur des lecteurs modernes et traditionnels. Commande de support SCSI et SATA, en tenant compte de plusieurs demandes en vol Le lecteur peut les trier et la moyenne peut peut-être 20 chiffres de bloc par rotation au lieu de 2. Autre que de surestimer le coût de recherche légèrement, votre explication est sur place.


@Ben VOIGT: Ma valeur d'~ 16 ms provient de Tom's Hardware Hard Drive Tableaux: Tomshardware.com/charts/2009-3.5-desktop-hard-drive-charts/... . Théoriquement, les lecteurs devraient fonctionner mieux que cela, mais dans la pratique, ils ne le font pas. Mes pensées étaient basées sur des graphiques il y a quelques années, lorsque 16 ms était la norme cependant. Les lecteurs modernes sont quelque part entre mes 16 et vos 8-9 chiffres.


@Ben Voigt: Notez que les disques durs pour ordinateur portable, comme celui que l'OP est testé, sont considérablement pires: Tomshardware.com/charts/2009-2.5-mobile-hard-drive-charts/...


Oui, l'OP n'a pas donné de vitesse de rotation d'entraînement, mais vous avez raison que 7200 tr / min est une mauvaise hypothèse d'un ordinateur portable. 4500 ou 5400 est beaucoup plus commun. OTOH, tant que le contrôleur est en mode AHCI, la mise en file d'attente doit être bonne pour une amélioration de l'ordre de magnitude si les demandes sont délivrées.



2
votes

Probablement le lecteur est le goulot d'étranglement. Mais vous pouvez essayer:

  1. Les opérations de cordes peuvent être optimisées - Utilisez des tableaux de caractères d'utilisation d'instaud de std :: String.
  2. Bâtiment Strffulname Chaque appel récursif n'est pas nécessaire. Utilisez un tampon unique et fixe de caractères (c'est-à-dire une matrice statique à l'intérieur de la fonction), modifiez-le instantanément.
  3. Ne passez pas le Strpattern par la valeur!
  4. Ne crée pas strtype avant le débogage
  5. Autres ont suggéré de créer une liste de répertoires à traiter avant de devenir plus profondément dans la récursivité. Pour la construire, je suggère une matrice statique unique (de la même manière que 2.) ou d'utiliser la pile ( alloca ).
  6. Les fichiersysytem utilisent unicode pour stocker des noms de fichiers? Si tel est le cas, en utilisant des chaînes UNICODE avec FindFirstFilew et FindNextFileW peut être un peu plus rapide.

0 commentaires