Limité par le calcul ou par la mémoire
Un travail est limité par le calcul quand le processeur ne suit pas. Il est limité par la mémoire quand les données arrivent trop lentement. Savoir lequel des deux freine un programme dit où chercher un gain.
Un GPU fait un très grand nombre de sommes par seconde, mais il doit d’abord recevoir ses données. Le labo n’a pas de GPU : le script transfer.py calcule des temps à partir d’un débit et d’une vitesse inventés, sans rien mesurer.
À la fin de cette leçon
Remarque
Je peux dire si un travail est limité par le calcul ou par la mémoire.
Mots clés
| Mot | Ce que ça veut dire |
|---|---|
| Débit mémoire | le nombre d’octets déplacés par seconde |
| Vitesse de calcul | le nombre d’opérations faites par seconde |
| Goulot d’étranglement | la limite qui freine tout le reste |
| Intensité | le nombre d’opérations faites par octet déplacé |
| Accès groupés | des fils voisins qui lisent des cases voisines |
| Ligne mémoire | un bloc d’octets lu d’un seul coup |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un appareil a deux limites
Un appareil déplace des octets à un certain débit, et fait des opérations à une certaine vitesse. Le script suppose 500 gigaoctets par seconde et 10 millions de millions d’opérations par seconde.
Pour chaque travail, il calcule deux temps : celui de déplacer les octets, et celui de faire les opérations. Le plus long est le goulot.
Comparer déplacer et calculer
docker exec jupyter python3 steps/transfer.pyAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Exemple : deux travaux, deux limites
| Travail | Octets | Opérations | Temps mémoire | Temps calcul | Limité par |
|---|---|---|---|---|---|
| Addition de 10 millions d’éléments | 120 000 000 | 10 000 000 | 240 µs | 1 µs | La mémoire |
| Produit de matrices 1000 par 1000 | 12 000 000 | 2 000 000 000 | 24 µs | 200 µs | Le calcul |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
L’intensité dit où est le goulot
L’intensité d’un travail est son nombre d’opérations divisé par ses octets. Elle vaut 0,08 pour l’addition et environ 166,7 pour le produit de matrices.
L’appareil a lui aussi un seuil : sa vitesse divisée par son débit, soit 20 opérations par octet. Sous le seuil, la mémoire freine. Au-dessus, c’est le calcul.
Comparer l’intensité au seuil
# Calcul ou mémoire ? On compare l'intensité du travail à celle de l'appareil.
debit = 500 * 10 ** 9 # octets par seconde
vitesse = 10 * 10 ** 12 # opérations par seconde
seuil = vitesse / debit
print("seuil de l'appareil :", seuil, "opérations par octet")
travaux = [["addition", 10000000, 120000000], ["produit", 2000000000, 12000000]]
for travail in travaux:
intensite = travail[1] / travail[2]
if intensite < seuil:
verdict = "la mémoire"
else:
verdict = "le calcul"
print(travail[0], ":", round(intensite, 2), "opérations par octet, limité par", verdict)
# Changez le débit en 1000 * 10 ** 9 : le seuil baisse de moitié.
Des fils voisins doivent lire des cases voisines
La mémoire est lue par lignes de 32 octets. Si huit fils lisent huit nombres de 4 octets côte à côte, une seule ligne suffit.
Si chacun lit un nombre sur huit, il faut huit lignes, pour les mêmes huit nombres. On appelle cela l’accès groupé, ou coalescence, et il compte autant que le calcul.
Compter les lignes mémoire lues
docker exec jupyter python3 steps/coalesce.pyAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Exemple : deux façons de lire huit nombres
| Lecture | Adresses touchées | Lignes de 32 octets |
|---|---|---|
| Chaque fil lit la case suivante | 0, 4, 8, 12, 16, 20, 24, 28 | 1 |
| Chaque fil lit une case sur huit | 0, 32, 64, 96, 128, 160, 192, 224 | 8 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une erreur fréquente
Attention
On croit souvent que plus d’unités de calcul accélèrent n’importe quel programme. Si la mémoire limite le programme, ajouter du calcul ne change presque rien. Il faut déplacer moins d’octets, ou les lire de façon groupée.
Envoyer les données au GPU a un coût
Un GPU a sa propre mémoire. Les données viennent de celle du processeur par un lien plus lent que sa mémoire locale. Ce transfert s’ajoute au calcul.
Il vaut la peine si le temps gagné sur le calcul dépasse le temps de transfert. Pour une addition, ce n’est presque jamais le cas.