Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

remplacement de la RAM par du disque dur: variation du temps d'accès

24 réponses
Avatar
Tribulations Parallèles
Bonjour à tous,

J'ai codé un programme qui réalise des calculs qui demandent beaucoup de RAM
(environ 500 Mo).
Je compte améliorer le programme, mais alors j'ai besoin de 100 Go de RAM
(oui!). Ce n'est pas possible. J'envisage donc de stocker mes données sur
le disque dur; plusieurs question en découlent:

1- Comment va évoluer le temps de lecture ou écriture des données? En
cherchant, je vois que le temps d'accès à la RAM est de l'ordre de 10 nano
seconde, au disque dur de 10 milli seconde. Un facteur un million se
dessine donc: il est trop important. Pour mon application, je peux tolérer
un facteur 10000. Or, quand je fais hdparm -t /dev/hda sur mon ordi, il me
donne 22 MB/sec: cela représente une lecture bien plus rapide que 10 milli
seconde pour accéder à chaque bit; pourquoi? A quoi correspondent ces
temps? Où trouver de la doc didactique sur le fonctionnement du disque dur?
Par exemple, si j'essaie de copier un fichier de quelques centaines de Mo
sur mon disque ($ cp foo.avi bar.avi), cela prend plusieurs dizaines de
secondes; mais là il lit et écrit; comment cela évolue-t-il si je ne fais
que charger le contenu d'un gros fichier dans la RAM? Bref, je suis
dépassé, et j'ai du mal à trouver de la doc sérieuse sur internet (mais
sûrement que je cherche mal).

2- Pour stocker ces données dans des fichiers, avez-vous une expérience à
faire partager? Existe-t-il des bibliothèques spéciales sous Linux? A
priori aucun intérêt à compresser les données?

Bref je suis preneur de tout conseil.

Merci d'avance,

Julien
--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).

10 réponses

1 2 3
Avatar
lhabert
Tribulations Parallèles :

1- Comment va évoluer le temps de lecture ou écriture des données?


Ça dépend énormément de comment ton programme va y accéder. Si il reste
pendant de (relativement) longues périodes à travailler sur un sous-ensemble
des données tenant en mémoire, alors tu ne sentiras presque pas de
ralentissement : tu auras juste des accès disques de temps en temps pour
changer le sous-ensemble des données stocké en mémoire, mais si ça se
produit suffisament rarement, ça sera négligeable. À l'opposé, si il passe
son temps à sauter à droite à gauche, là tu te prends allègrement un facteur
1000 (en étant optimiste).

En cherchant, je vois que le temps d'accès à la RAM est de l'ordre de 10
nano seconde, au disque dur de 10 milli seconde. Un facteur un million se
dessine donc: il est trop important. Pour mon application, je peux tolérer
un facteur 10000. Or, quand je fais hdparm -t /dev/hda sur mon ordi, il me
donne 22 MB/sec: cela représente une lecture bien plus rapide que 10 milli
seconde pour accéder à chaque bit; pourquoi? A quoi correspondent ces
temps?


Le temps d'accès est le temps que le disque dur met à se mettre à lire à une
adresse que tu lui donnes (déplacement des têtes et cie). Mais une fois
qu'il s'est mis à lire, il peut continuer à te pondre à tombeau ouvert les
secteurs voisins. Donc si tes fichiers sont peu fragmentés et que tu les lis
séquentiellement, le temps d'accès ne se sent pas trop. Le hdparm fait
justement du transfert séquentiel bourrin, ce qui explique ses bonnes
performances.

Où trouver de la doc didactique sur le fonctionnement du disque dur?


Wikipedia par exemple.

Par exemple, si j'essaie de copier un fichier de quelques centaines de Mo
sur mon disque ($ cp foo.avi bar.avi), cela prend plusieurs dizaines de
secondes; mais là il lit et écrit; comment cela évolue-t-il si je ne fais
que charger le contenu d'un gros fichier dans la RAM?


Bah tu n'as qu'à faire l'expérience (cat foo > /dev/null). Enfin en très
gros ça devrait varier d'un facteur 2.

2- Pour stocker ces données dans des fichiers, avez-vous une expérience à
faire partager? Existe-t-il des bibliothèques spéciales sous Linux?


Tout dépend de quelle forme de données il s'agit.

Note que sur une machine 64 bits, tu pourrais tout bêtement tout garder en
mémoire et laisser l'OS se dépatouiller avec le swap.

A priori aucun intérêt à compresser les données?


Si tu dois passer ton temps à les lire et les réécrire, ça me parait plutôt
nuisible, à moins que tu manques de place.

Avatar
Fabien LE LEZ
On Tue, 13 Jun 2006 22:33:12 +0200, Tribulations Parallèles

:

Étant donné que le domaine "freeee_._frspaM" n'existe pas, je
t'encourage vivement à rajouter ".invalid" à la fin. Merci d'avance.

1- Comment va évoluer le temps de lecture ou écriture des données? En
cherchant, je vois que le temps d'accès à la RAM est de l'ordre de 10 nano
seconde, au disque dur de 10 milli seconde. Un facteur un million se
dessine donc: il est trop important. Pour mon application, je peux tolérer
un facteur 10000. Or, quand je fais hdparm -t /dev/hda sur mon ordi, il me
donne 22 MB/sec: cela représente une lecture bien plus rapide que 10 milli
seconde pour accéder à chaque bit; pourquoi?


Tu confonds "temps d'accès" et "vitesse de lecture séquentielle".

Si tu veux lire un bloc contigu de N octets, le temps nécessaire sera
la somme du temps d'accès au premier octet (i.e. le temps de
positionnement des têtes au bon endroit) + le temps de lecture réel de
ces N octets sur le disque dur.

En d'autres termes, lire 1000 octets disséminés un peu partout sur le
disque prendra beaucoup plus de temps que lire 1000 octets contigus.


Par exemple, si j'essaie de copier un fichier de quelques centaines de Mo
sur mon disque ($ cp foo.avi bar.avi), cela prend plusieurs dizaines de
secondes;


AMHA, ça dépend beaucoup de l'algorithme utilisé.
Si tu lis 100 Mo d'un coup (i.e. tu les mets en RAM), puis que tu les
écris d'un seul coup également, il y aura peu de déplacements des
têtes, donc ça ira vite.
Si tu lis 1 Ko, puis tu l'écris, puis tu lis à nouveau 1 Ko, etc., ça
prendra énormément de temps (et fera beaucoup de bruits), à cause des
200 000 déplacements des têtes (de la zone à lire à la zone
d'écriture, et vice-versa).


2- Pour stocker ces données dans des fichiers, avez-vous une expérience à
faire partager? Existe-t-il des bibliothèques spéciales sous Linux? A
priori aucun intérêt à compresser les données?


J'avais fait le test il y a peu de temps, et la compression façon gzip
prend trop de temps.
Par contre, une compression plus basique peut être efficace : si tu as
des valeurs qui vont de 1 à 1 million, stocke-les sur 20 bits et pas
sur 32.


Note : il n'est pas impossible que Linux sache gérer ce genre de chose
mieux que toi. Alloue donc une partition de swap de 100 Go, et vois ce
que ça donne.

Avatar
lhabert
Fabien LE LEZ :

Si tu lis 1 Ko, puis tu l'écris, puis tu lis à nouveau 1 Ko, etc., ça
prendra énormément de temps (et fera beaucoup de bruits), à cause des
200 000 déplacements des têtes (de la zone à lire à la zone
d'écriture, et vice-versa).


Mouais, sachant que l'os et le disque lui-même font du read-ahead et gardent
le résultat dans un cache, ça ne doit pas se sentir tant que ça, si?

Alloue donc une partition de swap de 100 Go, et vois ce que ça donne.


Il faut une machine 64 bits pour ça, à moins qu'il puisse découper son
calcul en 25 process séparés travaillant chacun sur 4Go.

Avatar
Fabien LE LEZ
On Tue, 13 Jun 2006 21:19:32 +0000 (UTC), (Luc
Habert):

Mouais, sachant que l'os et le disque lui-même font du read-ahead et gardent
le résultat dans un cache, ça ne doit pas se sentir tant que ça, si?


Sous Linux, je ne sais pas.
Sous Windows 2000, la différence (surtout dans le bruit que fait le
disque dur) est flagrante.

Alloue donc une partition de swap de 100 Go, et vois ce que ça donne.


Il faut une machine 64 bits pour ça


S'il s'agit de faire d'énormes calculs, une machine un peu récente est
de mise. Et comme le moindre petit Sempron fonctionne en 64 bits, ça
devrait être jouable.


Avatar
Tribulations Parallèles
Fabien LE LEZ wrote:

D'abord merci beaucoup pour ta réponse ainsi qu'aux autres.

Étant donné que le domaine "freeee_._frspaM" n'existe pas, je
t'encourage vivement à rajouter ".invalid" à la fin. Merci d'avance.


Pourquoi? Je veux dire, je suis tout prêt à le changer (c'est pas très
élégant, c'est vrai), mais est-ce que ça pose un problème particulier? J'ai
peur qu'en rajoutant simplement .invalid les robots puissent détecter mon
adresse: c'est pour ça que j'ai pris quelque chose de très compliqué.

Si tu veux lire un bloc contigu de N octets, le temps nécessaire sera
la somme du temps d'accès au premier octet (i.e. le temps de
positionnement des têtes au bon endroit) + le temps de lecture réel de
ces N octets sur le disque dur.

En d'autres termes, lire 1000 octets disséminés un peu partout sur le
disque prendra beaucoup plus de temps que lire 1000 octets contigus.


Question: comment peut-on écrire simplement une grosse structure C de 500Mo
(une structure avec des pointeurs de pointeurs, des choses comme ça) dans
un fichier? Existe-t-il des bibliothèques dédiées à ça? En effet, je crois
qu'il y a dans la bibliothèque standard C des fonctions comme "tmpfile" qui
ouvre un fichier en écriture binaire, mais il faut que j'écrive ma
structure (compliquée) de manière pertinente, ce qui n'est pas forcément
simple.
De plus, est-on sûr que le fichier sera contigu; d'après ce que vous me
dites, s'il est découpé en quelques morceaux, ce n'est pas trop grave, mais
s'il est découpé en 10000 morceaux, ça va être embêtant. Cela dépend du
système de partitionnement, n'est-ce pas? Et en EXT3, je crois qu'il n'y a
pas ce genre de problèmes:

http://en.wikipedia.org/wiki/Ext3

Par ailleurs, je peux effectivement me débrouiller pour lire des données de
temps en temps, par paquet de 500 Mo (sur 100 Go au total), et travailler
dessus, directement dans la RAM, avant d'écrire le résultat sur le disque.
Si je suis vos commentaires, cela ne devrait donc pas ralentir mon
programme d'un facteur énorme.

Merci,

Julien

--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).

Avatar
Tribulations Parallèles
Fabien LE LEZ wrote:

Alloue donc une partition de swap de 100 Go, et vois ce que ça donne.


Il faut une machine 64 bits pour ça


S'il s'agit de faire d'énormes calculs, une machine un peu récente est
de mise. Et comme le moindre petit Sempron fonctionne en 64 bits, ça
devrait être jouable.


Ok, je vais essayer; j'ai effectivement à disposition une machine 64 bits.
Pourquoi la taille du swap est limitée en 32 bits à 4 Go, et pas en 64
bits?

--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).



Avatar
Pascal Bourguignon
Tribulations Parallèles writes:

Bonjour à tous,

J'ai codé un programme qui réalise des calculs qui demandent beaucoup de RAM
(environ 500 Mo).
Je compte améliorer le programme, mais alors j'ai besoin de 100 Go de RAM
(oui!). Ce n'est pas possible. J'envisage donc de stocker mes données sur
le disque dur; plusieurs question en découlent:

1- Comment va évoluer le temps de lecture ou écriture des données?


Mal.

En cherchant, je vois que le temps d'accès à la RAM est de l'ordre
de 10 nano seconde, au disque dur de 10 milli seconde. Un facteur un
million se dessine donc: il est trop important. Pour mon
application, je peux tolérer un facteur 10000. Or, quand je fais
hdparm -t /dev/hda sur mon ordi, il me donne 22 MB/sec: cela
représente une lecture bien plus rapide que 10 milli seconde pour
accéder à chaque bit; pourquoi? A quoi correspondent ces temps?


Un disque dur fonctionne de la manière suivante:

Il y a un disque qui tourne.
Il y a une tête de lecture/écriture qui se déplace sur un rayon.
Il y a une mémoire cache.
Il y a un bus entre le controleur du disque et l'ordinateur.


On trouve des disques qui tournent à 5400 tr/mn, 7200 tr/mn ou même 10000 tr/mn.

C'est des beaux chiffres, mais il est intéressant de les convertir en
tr/s, et en s/tr on obtient:

5400 tr/mn 90.0 tr/s 11.111 ms/tr
7200 tr/mn 120.0 tr/s 8.333 ms/tr
10000 tr/mn 166.6 tr/s 6.000 ms/tr


On trouve souvent dans les spécifications des disques durs seulement
le temps _moyen_ de saut de piste, comme: 12 ms, 9 ms, même 8 ms!
Mais si on va d'un bout à l'autre du disque ça peut doubler.


Le débit d'un interface IDE ATA-133, entre la RAM et le disque dur est
de 133 Mo/s maximum.


Donc, pour obtenir le premier secteur, puis le dernier secteur du
disque dur, il faudra envoyer deux commandes (petites, à 133 Mo/s, le
disque dur sera au parfum en 0.120 µs et commencera son travail.

Si on n'a pas de chance, les données ne se trouvent pas dans la
mémoire cache du disque dur (seulement 2 Mo, parfois 8 Mo ou 16 Mo sur
les gros disques durs de haut de gamme), alors il va falloir déplacer
la tête de lecture sur le premier secteur; temps de saut de piste
moyen: 9 ms.

Ok, 9 ms plus tard, on arrive sur la piste zéro, il nous faut le
secteur zéro, alors on lit se qui passe sous la tête de lecteur, et
pas de chance, on est aux antipode. Il va donc falloir attendre en
moyenne un demi tour: 4.2 ms.

4.2 ms plus tard, on lit le secteur. De nos jours, la densité change
selon le secteur: comme il y a plus de surface sur le bord qu'à
l'intérieur, on y met plus de secteurs. Disons qu'on a 64 secteurs au
bord, il va falloir pour en lire un 1/64 tour, soit: 0.130 ms.

Enfin, transmission du secteur sur le bus IDE, 512 octets à 133 Mo/s
soit: 3.849 µs.

Total pour lire le secteur zéro: 9000
4200
130
+ 4
-----
13334 µs

Mais attention, là les choses se gâtent. Si on voulait lire le secteur
1 après le zéro, on pourrait le faire dans la foulée. Lire une piste
ne prend qu'un tour, soit: 9 ms pour le saut de piste, plus 8.333 ms
pour la piste, et 0.246 ms pour le transfer: 17.579 ms pour 32 Ko,
total 1.8 Mo/s. Mais comme on veut lire le dernier secteur, on a gros
saut de piste: il faudra 26.333 ms, plus les 13.334 du secteur zéro,
total: 39.667 ms pour 1 Ko, soit 25 Ko/s.

C'est pas fameux, mais heureusement, comme tu vois en lecture
séquentielle, c'est un peu mieux, et avec le cache dans le disque dur,
et le cache implémenté par le système, on améliore la situation,
puisqu'on évite de faire des saut de piste pour chaque secteur: on
cumule les requêtes et on optimise les déplacements de la tête de
lecture.



Donc, pour ton problème, qui consiste à utiliser le disque dur comme
mémoire virtuelle, tu as intérêt à adapter ton algorithme pour éviter
d'accéder la mémoire dans tout les sens. Utilise plutôt de l'accès
séquentiel.


Où trouver de la doc didactique sur le fonctionnement du disque dur?


google? Je ne sais pas, c'est du B.A.BA d'informatique, ça doit
s'apprendre à la maternelle non? :-)

Mais vois aussi les thèmes de mémoire virtuelle et fichiers swap.
http://en.wikipedia.org/wiki/Virtual_memory


Par exemple, si j'essaie de copier un fichier de quelques centaines
de Mo sur mon disque ($ cp foo.avi bar.avi), cela prend plusieurs
dizaines de secondes; mais là il lit et écrit; comment cela
évolue-t-il si je ne fais que charger le contenu d'un gros fichier
dans la RAM?


Si tu le charge après l'avoir copié, alors il est en cache dans la
RAM, et plus besoin de relire le disque dur:

% free
total used free shared buffers cached
Mem: 1033972 1017696 16276 0 16168 393576
-/+ buffers/cache: 607952 426020 ^^^^^^
Swap: 1004020 25972 978048

Par exemple, là, j'ai 390 Mo de données en cache.


Bref, je suis dépassé, et j'ai du mal à trouver de la
doc sérieuse sur internet (mais sûrement que je cherche mal).


http://www.google.com/search?q=hard+disk+introduction

http://scholar.google.com/scholar?q=virtual+memory+performance+swap
http://scholar.google.com/scholar?hl=en&lr=&q=performance+swap+thrashing


2- Pour stocker ces données dans des fichiers, avez-vous une expérience à
faire partager? Existe-t-il des bibliothèques spéciales sous Linux? A
priori aucun intérêt à compresser les données?

Bref je suis preneur de tout conseil.


Bon, 100 Go, c'est plus que la mémoire virtuelle sur un processeur
32-bit (seulement 4Go, sur unix en général entre 1 Go et 3 Go
utilisable par les programmes). À moins que tu ne travaille sur un
processeur 64-bit? Auquel cas, tu pourrais compter sur le système
pour faire le travail: créer un fichier swap de 100 Go ou un peu plus,
et lancer le programme.

Sinon, ça dépend de l'algorithme. Mais en général, c'est vraiment
embêtant de programmer les lectures/écriture de tampons (ou simplement
les mmap/munmap) au millieu de l'algorithme, alors il vaut mieux le
faire automatiquement, en utilisant une indirection: ne pas utiliser
de pointeurs machine, mais des pointeurs virtuels (idem pour les
autres structures de données, tableaux, etc), et tout accès passe par
une routine qui implémente la mémoire virtuelle avec swap.

Peut-être qu'une solution simple serait de compiler un user-mode-linux
64-bit même sur un processeur 32-bit?


Dans tout les cas, il faut adapter son algorithme aux conditions. Il
y a pas mal d'expérience accumulée sur les anciens gros systèmes, où
il y avait des gros jobs tournant sur des "petites" machines avec
"seulement" 1 Mo de RAM...

Par exemple, il peut être plus efficace d'écrire séquentiellement des
résultats partiels que d'essayer d'aller mettre à jour une donnée
antérieure, si ça évite de faire des sauts de pistes. Mieux vaut
écrire 200 Go séquentiellement que sur 50 Go... Aussi, mieux vaut
avoir deux disques de 50 Go, qu'un disque de 100 Go, et de s'arranger
pour lire séquentiellement sur un quand on écrit séquentiellement sur
l'autre, plutôt que de tout mettre sur un disque de 100 Go et de faire
des sauts de pistes dans tous les sens pour lire et écrire des
bouts. À une époque, ça faisait marcher les disques dans les salles
informatique... http://www.disktrend.com/disk3.htm

4 ou 8 disques durs seraient encore meilleurs qu'un seul, si
l'algorithme le permet! Peut être en les configurant en RAID-0, peut
être en les gérant manuellement, selon le programme...



Mais surement, le meilleur conseil serait de gonfler l'UC:
http://www.digitimes.com/news/a20050729PR208.html
Pas plus de $55786 pour une carte mère dual opteron avec 64 Go.
Ou 128 Go: http://www.amdboard.com/opteron_04260501.html
http://www.notesbench.org/r6report.nsf/4dad05c18c1cb5338525687f006c4a60/02aa835ca79b2dcd85256f2c0067ac75?OpenDocument


Si l'algorithme est parallelisable, on peut aussi considérer un
cluster, par exemple, 64 CPU avec 2 Go RAM chacune, pas besoin de
disque dur alors.


--
__Pascal Bourguignon__ http://www.informatimago.com/
Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay

Avatar
Tribulations Parallèles
Tribulations Parallèles wrote:

Fabien LE LEZ wrote:

Alloue donc une partition de swap de 100 Go, et vois ce que ça donne.


Il faut une machine 64 bits pour ça



Ok, je vais essayer; j'ai effectivement à disposition une machine 64 bits.
Pourquoi la taille du swap est limitée en 32 bits à 4 Go, et pas en 64
bits?


Finalement, non, je ne pense pas que ce soit une bonne idée d'essayer: Linux
risque de Swaper quand je ne le veux pas, alors qu'avec la connaissance de
mon algorithme, je peux traiter mes données par paquet dans la RAM, et
éviter toute lecture sur le disque pendant ce traitement (cf autre post de
ce thread).

Julien

--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).




Avatar
Fabien LE LEZ
On Tue, 13 Jun 2006 23:55:53 +0200, Tribulations Parallèles
:

Ok, je vais essayer; j'ai effectivement à disposition une machine 64 bits.
Pourquoi la taille du swap est limitée en 32 bits à 4 Go, et pas en 64
bits?


C'est pas la taille du swap, c'est la quantité de mémoire adressable
par ton programme. Si un pointeur ne fait que 32 bits, tu ne peux pas
adresser plus de 2^32 octets.

Avatar
Rémi Moyen

Salut,

J'ai codé un programme qui réalise des calculs qui demandent beaucoup de RAM
(environ 500 Mo).
Je compte améliorer le programme, mais alors j'ai besoin de 100 Go de RAM
(oui!). Ce n'est pas possible. J'envisage donc de stocker mes données sur
le disque dur;


Pour un problème relativement similaire, j'ai vu passer un code qui
utilisait plusieurs threads : l'un était chargé de la lecture/écriture
sur le disque, et les autres faisaient les calculs eux-mêmes.

Dans ce cas particulier, ça marchait très bien parce que l'algo de
calcul était fait de telle sorte qu'entre le moment où il savait qu'il
aurait besoin de données stockées sur le disque et le moment où il en
avait réellement besoin, il s'écoulait pas mal de temps (en gros, une
grosse matrice à calculer puis à inverser) donc le thread de lecture
avait le temps de lire la partie de données nécessaires pendant ce
temps, sans ralentir les calculs.

Expérimentalement et dans ce cas-là, un seul thread de lecture/écriture
suffisait pour alimenter 5 ou 6 threads de calcul (sur une machine où
chaque thread tournait sur son processeur) avant de devenir le facteur
limitant de l'algo.

Mais évidemment, ça dépend totalement de l'algo de calcul, je ne sais
pas si tu peux utiliser une solution de ce genre...
--
Rémi Moyen

1 2 3