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

Windows Discussion :

lecture disque rapide


Sujet :

Windows

  1. #1
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut lecture disque rapide
    Bonjour,
    j'utilise pour le moment fopen fread et fgetc pour lire des fichiers tga sur mon disque dur.

    Existe-il quelque chose de plus rapide ?

    merci.

  2. #2
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut
    Bonjour,

    j'utilise pour le moment fopen fread et fgetc pour lire des fichiers tga sur mon disque dur.

    Existe-il quelque chose de plus rapide ?
    Sous Windows, les fonctions standard du C ne sont que des wrappers autour des API systèmes. Ces wrappers sont un peu plus "gros" que les fonctions de l'API, on peut donc utiliser ces dernières mais le gain de temps est vraiment minime...

    Equivalences :

    fopen = CreateFile() ou OpenFile()
    fread = ReadFile()
    fgetc = ReadFile() mais en ne lisant qu'un seul octet.

    On peut techniquement "descendre" plus bas que CreateFile() avec NtCreateFile() mais c'est peu conseillé (On gagne un gros paquet de ligne de code au prix d'aucune vérification sur les paramètres). Voir MSDN : http://msdn2.microsoft.com/en-us/library/ms805591.aspx

    Même chose avec ReadFile() et sa contrepartie non documentée, NtReadFile(). Voir : http://undocumented.ntinternals.net/...tReadFile.html

    Mais en utilisant les APIs système tu perds la portabilité du code source...

    Pour rester en C standard, tu peux lire d'un seul coup ton fichier (plutôt qu'octet par octet avec fgetc() ) en récupérant d'abord la taille de celui ci et en passant cette dernière à fread(). Voir la FAQ C :

    http://c.developpez.com/faq/c/?page=...HIERS_filesize

  3. #3
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    salut,
    merci pour ta reponse.

    Effectivement, en lisant le fichier d'un coup et en traitant les donnees selon le format plus loin, j'obtient des resultats bien meilleurs.

    Pour le moment ça m'ira merci.

  4. #4
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    Bonjour,

    J'aimerai essayer le mode FILE_FLAG_NO_BUFFERING mais

    1- J'ai du mal avec les contraintes demandees
    2- Les sources que je trouve sont tellement indigestes que ça m'ecoeure...

    bref j'aurai besoin d'un coup de pouce pour l'alignement notamment

  5. #5
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut
    Bonjour,

    J'ai du mal avec les contraintes demandees
    C'est vrai que ça n'est pas forcément évident, mais la documentation est assez explicite.

    File access must begin at byte offsets within a file that are integer multiples of the volume sector size.
    Cela indique que toute tentative d'accès (aussi bien en écriture et en lecture) soit se faire obligatoirement sur un multiple de la taille du secteur.

    Par exemple, si tu souhaites lire à partir du 524ème octet de ton fichier et que la taille de secteur du volume où est situé ton fichier est de 512 octets, tu dois commencer au 512ème.

    Tu récupère la taille du secteur du volume avec GetDiskFreeSpace(), ce qui nous intéresse dans le cas présent est le membre lpBytesPerSector.
    cf. http://msdn2.microsoft.com/en-us/library/aa364935.aspx

    Note que la version étendue "GetDiskFreeSpaceEx()" ne donne pas cette information.

    File access must be for numbers of bytes that are integer multiples of the volume sector size. For example, if the sector size is 512 bytes, an application can request reads and writes of 512, 1024, 1536, or 2048 bytes, but not of 335, 981, or 7171 bytes.
    Toute tentative de lecture et/ou écriture doit se faire sur un nombre d'octets égale ou multiple de la taille de secteur du volume où est situé le fichier. En d'autres termes, pour reprendre l'exemple précédent :

    Tu souhaites lire 2000 octets à partir du 524ème octet de ton fichier =>

    Tu commence à lire à partir du 512ème octet et tu lis 2048 octets (2048 étant un multiple de 512). C'est la taille de la lecture ou de l'écriture qui importe ici.

    Buffer addresses for read and write operations should be sector aligned, which means aligned on addresses in memory that are integer multiples of the volume sector size. Depending on the disk, this requirement may not be enforced.
    L'adresse du tampon pour la lecture ou l'écriture doit être aligné sur un multiple de la taille du secteur. Comme le dit la MSDN, VirtualAlloc() fait cela automatiquement, pas besoin de s'en préoccuper.

    Exemple :

    Supposons que tu veuilles lire un fichier depuis le 500ème octet et sur 2000 octets. Le taille de secteur est de 512.

    Le pointeur de fichier devra être aligné sur un multiple de 512. Comme 500 est inférieur à 512. On aligne le pointeur sur 0.

    Comme tu veux lire 2000 octets, mais que le pointeur de fichier est en 0, il faut allouer :

    - 500 + 2000 : 2500 octets

    Mais comme il faut aligner sur une taille de secteur on alloue au premier multiple de 512 supérieur à 2500, soit : 2560.

    Ensuite tu peux te déplacer comme tu veux sur le tampon, seul la lecture et/ou l'écriture depuis le fichier doivent être alignées !

    Voilà un exemple et qques fonction utiles sorties d'un projet (j'ai enlevé la gestion d'erreur et tout ce qui n'était pas nécessaire pour éviter un code trop lourd).

    Code c : 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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
     
    #include <windows.h>
    #include <stdio.h>
     
    DWORD GetSectorSize (char* volume);
    DWORD AlignAllocSizeOnSectorSize(DWORD NumberOfBytesRequested, DWORD SectorSize);
    DWORD SetFilePointerFromFileStart (HANDLE hFile, DWORD FirstByte, DWORD SectorSize);
    DWORD GetAllocSize(DWORD FirstByteToRead, DWORD FilePointerLoc, DWORD AllocSize, DWORD SectorSize);
     
    int main (void)
    {
     
        HANDLE hFile; /* Handle fichier */
        DWORD FilePointerLocation; /* offset pointeur de fichier */
        DWORD AllocSize = 2000;    /* Taille demande d'allocation */
        DWORD FirstByte = 500;     /* Premier octet à lire ou écrire */
        DWORD TotalAlloc;    /* Allocation totale */
        DWORD SectorSize;     /* taille secteur */
        PCHAR pBuff;    /* pointer buffer */
        DWORD NOBR;     /* nombre d'octet lu */
     
     
        /* Ouverture du fichier */
        hFile = CreateFile("E:\\TestData.bin", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
     
        /* récup taille secteur */
        SectorSize = GetSectorSize("E:\\");
        fprintf(stdout, "Sector Size : %lu\n", SectorSize);
     
        /* aligne le pointeur de fichier */
        FilePointerLocation = SetFilePointerFromFileStart(hFile, FirstByte, SectorSize);
        fprintf(stdout, "Pointeur de fichier en : %lu\n", FilePointerLocation);
     
        /* récup taille d'allocation totale nécessaire */
        TotalAlloc = GetAllocSize(FirstByte, FilePointerLocation, AllocSize, SectorSize);
        fprintf(stdout, "Taille totale allouée : %lu\n", TotalAlloc);
     
        /* allocation buffer */
        pBuff = VirtualAlloc(NULL, TotalAlloc, MEM_COMMIT, PAGE_READWRITE);
     
        /* lecture fichier */
        ReadFile(hFile, pBuff, TotalAlloc, &NOBR, NULL);
     
        /* clean up buffers & handles */
        CloseHandle(hFile);
        VirtualFree(pBuff, 0, MEM_RELEASE);
     
     
       return 0;
    }
    /*
    * GetSectorSize
    *
    * OP : Retoune la taille de secteur pour un volume donné.
    *
    * [IN] Volume : nom du volume.
    *
    * Return : Taille de secteur pour [IN]Volume.
    */
    DWORD GetSectorSize (char* Volume)
    {
        /* variables pour GetDiskFreeSpace */
        DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters;
     
         /* récupère la taille d'un secteur, seul BytesPerSector nous intéresse réellement */
        GetDiskFreeSpace(Volume, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
     
        return BytesPerSector;
    }
    /*
    * SetFilePointerFromFileStart
    *
    * OP : Aligne le pointeur de fichier sur la taille de secteur en tenant compte du premier octet à lire ou écrire.
    *
    * [IN] hFile : Handle du fichier.
    * [IN] FirsByte : Premier octet à lire ou écrire.
    * [IN] SectorSize : Taille de secteur.
    *
    * Return : La position actuelle du pointeur de fichier après alignement.
    */
    DWORD SetFilePointerFromFileStart (HANDLE hFile, DWORD FirstByte, DWORD SectorSize)
    {
        DWORD FilePointerLoc;
     
        FilePointerLoc = (FirstByte / SectorSize) * SectorSize;
     
        SetFilePointer(hFile, FilePointerLoc, NULL, FILE_BEGIN);
     
        return FilePointerLoc;
     
    }
    /*
    * GetAllocSize
    *
    * OP : Retourne la taille totale d'allocation du tampon en cas d'alignement strict nécessaire (CreateFile + FILE_FLAG_NO_BUFFERING)
    *
    * [IN] FirstByte : Offset du premier octet à lire ou écrire.
    * [IN] FilePointerLoc : Offset du pointeur de fichier [doit être aligné par la fonction SetFilePointerFromFileStart()]
    * [IN] AllocSize : Nombre d'otcet à allouer.
    * [IN] SectorSize : Taille de secteur du volume où est situé le fichier qui sera lu ou écrit.
    *
    * Return : Taille totale d'allocation.
    */
    DWORD GetAllocSize(DWORD FirstByte, DWORD FilePointerLoc, DWORD AllocSize, DWORD SectorSize)
    {
        DWORD LastByteToReach;
        DWORD TotalAlloc;
     
        LastByteToReach = FirstByte + AllocSize;
        TotalAlloc = LastByteToReach - FilePointerLoc;
     
        return AlignAllocSizeOnSectorSize(TotalAlloc, SectorSize);
    }
    /*
    * AlignAllocSizeOnSectorSize
    *
    * OP : Retourne une taille d'allocation alignée sur la taille de secteur d'un volume.
    *
    * [IN] NumberOfBytesRequested : Nombre d'octets requis pour l'allocation du tampon.
    * [IN] SectorSize : Taille de secteur d'un volume.
    *
    * Return : La taille d'allocation alignée sur la taille de secteur.
    */
    DWORD AlignAllocSizeOnSectorSize(DWORD NumberOfBytesRequested, DWORD SectorSize)
    {
        DWORD NumberOfSectorNeeded;
        DWORD Rem;
     
        NumberOfSectorNeeded = NumberOfBytesRequested / SectorSize;
        Rem = NumberOfBytesRequested % SectorSize;
     
        if (Rem != 0)
            NumberOfSectorNeeded++;
     
        return NumberOfSectorNeeded * SectorSize;
     
    }

  6. #6
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    Déjà je tiens à te remercier d'avoir passé du temps à faire une réponse si détaillée dans le soucis d'être compris. Je ne peux qu'apprécier

    Le principe, comme tu le dis, est clair mais l'implementation n'est pas triviale (au moins pour moi).

    Par example, je ne m'étais jamais servi de VirtualAlloc, car je ne comprend toujours pas la nuance avec un malloc. (malgré avoir lu la msdn) Le fait que l'allocation se fasse alignée n'est qu'un side effect j'imagine, il doit y avoir d'autres differences.

    Merci aussi pour le code qui a l'air tres clair; si j'ai des questions dessus je te dirai.

    Sinon, vois-tu des gains de performances notables avec l'utilisation d'un tel attribut ? Les tests pour assurer les contraintes de lectures ne réduisent-ils pas trop l'interret sur des fichiers de 6 - 8 mo environ ?

    Et autre question hors sujet : diviser la lecture d'un même gros fichier en plusieurs semi-lectures effectuees par autant de thread differents sur un dual core voire quatri core, a pour effet de plutot allonger le temps total de lecture ou de le reduire ?

  7. #7
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut
    Sinon, vois-tu des gains de performances notables avec l'utilisation d'un tel attribut ? Les tests pour assurer les contraintes de lectures ne réduisent-ils pas trop l'interret sur des fichiers de 6 - 8 mo environ ?
    C'est vraiment dépendant de ce que tu fais sur le(s) fichier(s)... En fait mieux vaut réaliser des tests de vitesse d'exécution pour voir quelle solution est la plus profitable dans ton cas.

    diviser la lecture d'un même gros fichier en plusieurs semi-lectures effectuees par autant de thread differents sur un dual core voire quatri core, a pour effet de plutot allonger le temps total de lecture ou de le reduire ?
    Les systèmes SMP aiment le threading Dès que tu as plusieurs Cores, il faut penser à la possibilité d'une implémentation multi-thread qui reduira fortement le temps de traitement.
    Mais ça induit des problèmes, par exemple les accès concurrents sur une même ressource.

  8. #8
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    J'ai implementé cette methode dans mon projet mais le gain de vitesse reste limite environ 0.5 fps sur des fichiers image tga 24bits non compressés de 6mo 1920*1080.

    C'est toujours ça de gagné.

    Les systèmes SMP aiment le threading Dès que tu as plusieurs Cores, il faut penser à la possibilité d'une implémentation multi-thread qui reduira fortement le temps de traitement.
    Mais ça induit des problèmes, par exemple les accès concurrents sur une même ressource.
    En fait mon appli est deja multithread, mais seulement pour des operations qui travaillent sur la memoire du style "décodage en temps reel de l'image" avant l'affichage

    Dans le cas de lecture physique sur disque, est-il vraiment bon de faire du multithreading ? Car les tetes de lectures doivent bouger sans arret non ? dans le cas de la lecture d'un même fichier par plusieurs threads, elles ne doivent pas pouvoir acceder en même temps aux donnees si ?

Discussions similaires

  1. [Disque Dur] Erreur lecture disque
    Par zoom61 dans le forum Composants
    Réponses: 13
    Dernier message: 04/01/2009, 14h17
  2. [Débutant] Err. lecture disque
    Par twiste dans le forum Composants
    Réponses: 21
    Dernier message: 22/06/2007, 17h16
  3. Erreur lecture disque
    Par flo456 dans le forum Composants
    Réponses: 3
    Dernier message: 11/05/2007, 22h18
  4. Temps de lecture disque
    Par Mucho dans le forum C++
    Réponses: 20
    Dernier message: 18/09/2006, 23h28
  5. lecture disque client
    Par gilles74 dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 30/04/2006, 11h49

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