lundi 10 juillet 2023

Architecture CPU et optimisation du compilo

Et on continue de jouer avec Godbolt, en particulier la capacité de gcc d'optimiser du code numérique. Prenons par exemple une version simplifiée de la résolution d'une équation quadratique :

#include <cmath>

double calc(double a, double b, double c)
{
    double delta = b * b - 4 * a * c;
    return (-b + sqrt(delta)) / (2 * a);
}

Je vous laisserai aller voir sur Godbolt, mais en gros, ça nous fait une 30aine d'instructions assembleur.

La première grosse optimisation, c'est la combinaison de -O3 et de -ffast-math. On passe à 18 lignes (dont 12 seulement font quelque chose d'intéressant), et le compilo utilise l'instruction assembleur sqrtsd plutôt que d'appeler le sqrt de la libc. Mais l'on peut faire encore mieux ! Avec un -march=skylake, on perd 2 instructions, et la machine passe alors sur des instructions vectorisées. Plus rapide ? Moins rapide ? Je suppose que ça va dépendre ! On retrouve un code équivalent en passant chez AMD et -march=znver3.

Maintenant, le souci, c'est que je si, comme dans mon cas, je dois compiler du code qui tournera à la fois sur des machines récentes de chez Intel et AMD, eh bien je suis obligé de garder une architecture générique et de perdre l'avantage de toutes ces instructions magiques... Quand bien même elles sont peut-être en commun ?

Frustrant, donc. Mais probablement pas catastrophique, car le code que j'optimise n'est de toutes façons pas très numérique, et se vectorise probablement mal. Tant pis !

Aucun commentaire: