CONNEXION
  • RetourJeux
    • Sorties
    • Hit Parade
    • Les + populaires
    • Les + attendus
    • Soluces
    • Tous les Jeux
    • Gaming
  • RetourActu Gaming
    • News
    • Astuces
    • Tests
    • Previews
    • Toute l'actu gaming
  • RetourBons plans
    • Bons plans
    • Bons plans Smartphone
    • Bons plans Hardware
    • Bons plans Image et Son
    • Bons plans Amazon
    • Bons plans Cdiscount
    • Bons plans Decathlon
    • Bons plans Fnac
    • Tous les Bons plans
  • RetourJVTech
    • Actus High-Tech
    • Intelligence Artificielle
    • Smartphones
    • Mobilité urbaine
    • Hardware
    • Image et son
    • Tutoriels
    • Tests produits High-Tech
    • Guides d'achat High-Tech
    • JVTech
  • RetourCulture
    • Actus Culture
    • Culture
  • RetourVidéos
    • A la une
    • Gaming Live
    • Vidéos Tests
    • Vidéos Previews
    • Gameplay
    • Trailers
    • Chroniques
    • Replay Web TV
    • Toutes les vidéos
  • RetourForums
    • Hardware PC
    • PS5
    • Switch 2
    • Xbox Series
    • Switch
    • Pokemon pocket
    • FC 25 Ultimate Team
    • League of Legends
    • Tous les Forums
  • PC
  • PS5
  • Xbox Series
  • Switch 2
  • PS4
  • One
  • Switch
  • iOS
  • Android
  • MMO
  • RPG
  • FPS
En ce moment Genshin Impact Valhalla Breath of the wild Animal Crossing GTA 5 Red dead 2
Liste des sujets

C++ template specialization

godrik
godrik
Niveau 30
06 janvier 2014 à 21:27:37

Bonjour a vous,

j'ai un probleme a vous soumettre et peut etre que vous aurez une idee sur comment ecrire du code propre.

J'ai une variable disons int x; Et j'ai besoin de passer cette variable comme un parametre template a une fonction. J'ai besoin que ce parametre soit template parceque je veux utiliser une version specialiser de la fonction pour cette valeure. Si je passe le parametre comme un parametre de fonction, les performances de la fonction s'ecroule (genre prend 40% de penalite dans la tete).

Du fait, je me retrouve avec un code du genre:
switch(x) {
case 1: f<1>(); break;
case 2: f<2>(); break;
case 3: f<3>(); break;
case 4: f<4>(); break;
case 5: f<5>(); break;
case 6: f<6>(); break;
case 7: f<7>(); break;
case 8: f<8>(); break;
case 16: f<16>(); break;
case 32: f<32>(); break;
case 64: f<64>(); break;
}

Comme vous pouvez le voir, c'est bien moche a souhait. Une idee quelconque pour obtenir du code plus propre?

Best,

Erik

godrik
godrik
Niveau 30
06 janvier 2014 à 21:28:24

(oups, je voulais poster sur le forum programmation. Bon c'est pas grave, il doit y avoir des gens famillier avec ca ici aussi.

Lapintade
Lapintade
Niveau 30
06 janvier 2014 à 22:35:06

Ouch c'est tricky.
Je ne peux pas aider, je n'utilise jamais les templates.

Paulop
Paulop
Niveau 12
06 janvier 2014 à 22:46:44

Pourquoi pas appeler chacune des fonctions et mettre le résultat dans un tableau, puis après utiliser le tableau pour récupérer la bonne valeur ?

godrik
godrik
Niveau 30
06 janvier 2014 à 22:51:26

Paulop, j'ai pas compris. Je ne veux appeler qu'une seule de ces fonctions, je n'ai pas une boucle sur x en amont. En gros x c'est une taille de bloc sur laquel je fais mes calculs. En fonction de mon jeu de donnee et des capacite de la machines, je fais des blocs de taille differentes.

Mais par contre, ca m'a donnee lidee de faire un tableau de pointeurs de fonction. Bon je ne sais pas si c'est beaucoup mieux...

godrik
godrik
Niveau 30
06 janvier 2014 à 22:52:21

ah, je viens de comprendre ton message. En fait, il y a des parametre a la fonction f(). Je les ai juste retires pour faire court.

Paulop
Paulop
Niveau 12
06 janvier 2014 à 23:08:57

Ok, je me disais aussi :D

Par contre je comprend pas pourquoi tu prends un 40% de penalité :/

godrik
godrik
Niveau 30
07 janvier 2014 à 00:38:02

Je ne suis pas completement sur non plus. Ce nombre est utilise pour calculer des offsets. Si tu connais le nombre a la compilation il y a peut etre des operations qui peuvent etre precalculee. Aussi peut etre que rajouter une variable consomme un registre de plus et que la pression registre devient trop forte. Et c'est du code CUDA donc j'ai aucune idee de ce que le compilateur fait dans mon dos.

Pseudo supprimé
Pseudo supprimé 07 janvier 2014 à 04:40:33

A mon avis tu traque un bug au mauvais endroit...

godrik
godrik
Niveau 30
07 janvier 2014 à 05:21:38

Qui a parle de bug? Le code fonctionne correctement et ne rapporte pas d'erreur dans valgrind. Le code est moche, mais a priori pas bugge.

papy386
papy386
Niveau 10
07 janvier 2014 à 12:05:12

Bonjour

Je pense que ce code est mal conçus, normalement un template c'est pour un type, une classe, mais pas pour une valeur.

Cette valeur devrais être passer comme paramètre a ta fonction, genre f(64), surtout si c'est juste un offset.

LGV
LGV
Niveau 28
07 janvier 2014 à 14:41:02

Ce n'est pas mal concu, on utilise souvent des specialisations de templates pour optimiser des parties critiques de code en "applatissant" toute une structure de classe au compile-time.

Je pense notamment a des systemes de particuliers, generation de shaders dynamiques, etc. On perd un peu de memoire (code plus gros) mais on evite toutes les tables virtuelles. La seule contrainte etant de connaitre toute la structure des classes a la compilation.

Pour rendre le code un peu plus "beau", sans en changer la logique, tu peux eventuellement passer pas un tableau de pointeur sur fonctions (selon la signature, et si tu as d'autres parametres ou pas), ou utiliser le preprocesseur a coup d'operateur de concatenation (##) (histoire de faire une macro qui rende le switch moins monstrueux)

LGV
LGV
Niveau 28
07 janvier 2014 à 14:41:23

typo : systemes de particules*

godrik
godrik
Niveau 30
07 janvier 2014 à 18:49:17

LGV, c'est pas bete d'utiliser le preprocesseur pour faire dnas le moins moche. Surtout qu'en fait j'ai une dizaine de parametre a cette fonction. Donc si je peux ecrire les parametres qu'une seule fois, ca fera deja du bien.

papy, LGV, en l'occurence, ce n'est pas un applatissement de structure de donne. C'est une histoire d'un parametre qui est constant et qui permet de simplifier le code assembleur dans une partie critique. J'avais parler il y a un bout de temps d'utiliser des templates pour parametre statiquement la taille de structures de donnes [1]. Et ici je pense que c'est essentiellement le meme comportement que je vois.

Mon parametre template est le nombre de colonnes d'un jeu matrices qui sont passees en parametre. Je passe du temps a faire des calculs d'indice i*X+j. Je ne sais pas bien d'ou vient la difference de performance qui est si significative ici. Mais comme c'est du code CUDA et que je ne connais pas l'assembleur du truc (je ne suis meme pas sur qu'il soit public?) c'est difficile a dire. J'imagine que la difference vient de l'economie d'un registre par thread (une centaine de million) et que ca evite le register spilling. Aussi, il est possible que ca evite une multiplication parceque j est constant par thread. du coup tu peux faire offtab = tab+sizeof(int)*j en amont. et il te reste a faire offtab+i*X*sizeof(int). Et si X est connu a la compilation tu peux precalculer X*sizeof(int) et economiser une multiplication (et un registre). Enfin bon, experimentalement, ca va plus vite :)

[1] http://erik.deblan.org/blog/index.php?article6/quand-les-conteneurs-standards-deviennent-trop-lents

papy386
papy386
Niveau 10
07 janvier 2014 à 20:02:56

A ok, c'est vraiment spécifique car je n'est jamais vu ça avant. La spécialisation de templates étant toujours présenté avec des types et pas des valeurs.

M'enfin on apprend tous les jours.

La performance c'écroule peut être car au niveau du GPU quand tu a une structure compiler dans le code elle est peut être directement dans le GPU, alors que si tu le fait en cour d'exécution (par paramètre donc) ta structure est peut être compiler a ce moment par le CPU, puis streamer dans le GPU, donc perte probable de 40%.

Mais ce n'est qu'un hypothèse.

godrik
godrik
Niveau 30
07 janvier 2014 à 20:29:16

nan, la compilation du code PTX en code assembleur pour GPU est fate par le CPu dans les deux cas. Et elle n'est faites qu'une fois et cache au niveau du driver (de memoire)

godrik
godrik
Niveau 30
07 janvier 2014 à 23:38:00

Bon, bah ca ressemble a ca finalement:

switch (NB_BFS)
{

  1. define CASE(X) case X: init_virtual_multi<X><<<grid2,threads2>>>(d_source

s,
d_d, d_sigma, n_count); break;
CASE(1);CASE(2);CASE(3);CASE(4);CASE(5);CASE(6);CA
SE(7);CASE(8);

CASE(16);CASE(32);CASE(64);CASE(128);
default: assert(0);

  1. undef CASE

}

C'est moche, mais pas tant.

[yamashi]
[yamashi]
Niveau 7
08 janvier 2014 à 14:03:29

Pourquoi pas un tableau ? ca bouffera 64 x 4 octets mais en perf ca enverra le maximum...

Sinon pour rendre ton expension plus jolie :

  1. define SEQ (1)(2)(3)(4)(5)(6)(7)(8)(16)(32)(64)(128)
  2. define MACRO(r, data, elem) CASE(elem);

switch (NB_BFS)
{
BOOST_PP_SEQ_FOR_EACH(MACRO, x, SEQ)
default: assert(0);
}

godrik
godrik
Niveau 30
08 janvier 2014 à 16:28:07

J'ai pense au tableau, mais concretement ca pousse juste le probleme un peu plus loin. L'initialisation du tableau va etre moche, l'appel un peu mieux, mais je peux toujours encapsuler le switch dans une fonction classique pour rendre 'vode client' plus propre.

Je ne connaissais pas cette macro de boost, il va falloir que je la regarde, je ne vois pas bien coment elle fonctionne. Merci!

Sous forums
  • Aide à l'achat Mac
  • Création de sites web
  • Création de Jeux
  • Linux
  • Programmation
  • Internet
  • Steam Deck
  • Macintosh
  • Hardware