Crunchez vos adresses URL
|
Rejoignez notre discord
|
Hébergez vos photos
Page 280 sur 334 PremièrePremière ... 180230270272273274275276277278279280281282283284285286287288290330 ... DernièreDernière
Affichage des résultats 8 371 à 8 400 sur 10008
  1. #8371
    Citation Envoyé par Møgluglu Voir le message
    La loi de Murphy étant ce qu'elle est, tu serais obligé de re-valider tout si tu mets le FPGA A à la place.
    I see what you mean. J'ai eu que l'experience "light" en FPGA de bosser sous LabVIEW et du coup d'avoir un "compilateur"/"interpréteur" (je ne sais pas le nom exacte) qui traduit ton code "abstrait" et VHDL spécifique à la puce que tu utilise (du coup, le code est portable... dans la limite de leur produits qui embarquent tous différentes gammes de puces Xilinx).

  2. #8372
    Je suis confusion

    Je vois dans le précis de ce cher Agner Fog que presque toutes les instructions arithmétiques élémentaires prennent au moins 3 cycles. Mais sont-ce les meilleurs?
    Je suis confusion parce que je vois qu'il faut déjà 4 cycles d'horloge pour que le pileline puisse exécuter pleinement une instruction.

    1) Fetch (de la pile d'instructions?)
    2) Decode (passage du x86 au RISC interne)
    3) Execute (le truc qui nous intéresse à la base)
    4) Write back

    Du fait que le pipeline est une chaine de montage, il execute 1+2+3+4 à chaque cycle d'horloge, mais pour 4 instructions consécutives différentes. Donc, 1 seul "execute" par cycle a priori.

    Ces 3 cycles, c'est quoi donc dans l'histoire?
    Le nombre d'instructions RISC minimum qui code une instruction x86?
    Et dans ce cas, pour exécuter une instruction x86, il faudrait 3 instructions RISC, soit 3 fetch, 3 decode, 3 execute et 3 WB?
    Dernière modification par vectra ; 02/02/2016 à 15h33.

  3. #8373
    Oui, pour le pipeline c'est ça en gros, mais et comptant plutôt 25 étages que 4...

    Donc tu pourrais avoir par exemple un pipeline pipo du genre : F1 F2 F3 F4 D1 D2 D3 D4 E1 E2 E3 WB avec tes 3 étages d'exécution au milieu.

    En vrai, c'est du out-of-order, donc tu n'as pas un beau pipeline bien régulier mais un gros bordel entre l'étage d'issue et celui du retire. Mais l'idée est là.

    Après, tu dois avoir une colonne latence et une colonne 1/débit dans les tables d'Agner. La latence est la profondeur du pipeline d'exécution, le débit est fonction du nombre d'unités capable d'exécuter l'instruction et du nombre de µops de l'instruction le cas échéant.

  4. #8374
    C'est un peu ambigüe ta réponse. Si j'ai bien compris si j'exécute 50 additions d'affilé de théoriquement 3 cycles chacune, le tout prend environ 150 cycles ? (et non 52 ?)
    Rust fanboy

  5. #8375
    Le out-of-order, c'est le genre de tâches que le Frontend gère, au même titre que la prédiction de branchement?

    Ah, et j'avais oublié que les processeurs étaient maintenant superscalaires: c'est pour cela que le pipeline à l'instant t est chargé de F1-4, D1-4, E1-4, WB?

  6. #8376
    @vectra : Non, le out-of-order c'est le backend.

    Le frontend gère Fetch (lire le cache d'instruction), Decode (x86 to microops) et Rename (pour casser les fausses dépendances sur les registres, ce dont l'out-of-order a besoin pour marcher bien). Il y a aussi l'allocation de ressources quelque part (mettre chaque instruction dans le ROB, Load Queue/Store Queue, et le Scheduler) qui est faite dans l'ordre donc on admettra que c'est encore dans le Frontend.
    Après, l'exécution se fait dataflow-style dans le backend depuis le Scheduler (dès qu'une instruction a ses opérandes prêts, elle est exécutée, quel que soit son âge).

    Sinon j'ai pas compris ta deuxième question. Si c'est superscalaire, chaque étage va te faire deux instructions par cycle (ou plus), au lieu d'une. Après chaque étage n'a pas forcément la même largeur...

    @Tomaka : Non, 50 exécutions d'affilé c'est 52 cycles, vu que l'addition est pipelinée et normalement c'est un seul cycle. Même si elles sont dépendantes tu peux chopper le résultat de la précédente sur le réseau de bypass.

    Vous avez vu comme j'ai répondu out-of-order?
    Citation Envoyé par François
    L'ordinateur cantique, c'est l'avenir.

  7. #8377
    C'est un métier

    Pour le superscalaire, je ne savais pas que les étages n'avaient pas tous la même taille. Ce qui explique l'état de pipeline qu'a posté Mogluglu et que je ne comprenais pas à première lecture.


    Par contre, la prédiction de branchement, c'est bien le Frontend?
    J'ai l'impression de tout redécouvrir de zéro, alors que j'ai pourtant eu des cours d'archi MIPS bordayl

  8. #8378
    Moi je comprend le pipeline de Mogluglu comme étant scalaire. Le Fetch prend 4 cycles, le Decode 3, etc...Pour autant ça ne dit rien sur combien d'instructions sortent du Fetch (sortent de F4) à chaque cycle. Ou alors lapin compris :3

    Et oui, la prédiction de branchement c'est en parallèle du Fetch, en gros.

    Un exemple de pipeline x86 pas trop vieux.
    Dernière modification par Thamior ; 02/02/2016 à 17h01.
    Citation Envoyé par François
    L'ordinateur cantique, c'est l'avenir.

  9. #8379
    Oui, les numéros dans mon pipeline c'était juste pour pas avoir à donner un nom à chaque étage, mais ils sont tous les uns à la suite les uns des autres. J'aurais pu prendre les lettres de A à Z suivi de l'alphabet grec pour le Pentium 4. Et chaque étage peut être plus ou moins large.

    Pour l'exemple de Tomaka, j'ai supposé qu'on parle d'une addition flottante avec une latence de 3 cycles. Dans ce cas si chaque addition est dépendante de la précédente, ça fait 150 cycles. Mais si on parle d'une addition entière avec 1 opérande en mémoire, c'est de la triche, c'est plusieurs µops...

  10. #8380
    Citation Envoyé par Naity Voir le message
    2*0 = ?
    Perfs, pas résultats pertinents.

  11. #8381
    Citation Envoyé par Robix66 Voir le message
    Perfs, pas résultats pertinents.
    Pour avoir teste bing qqs fois, j'ai pas le souvenir que ses recherches soient lentes. Ceci dit, il est beaucoup plus facile de fixer les problemes que l'on a pas.

  12. #8382
    J'ai une question sur l'optimisation de code au niveau assembleur.
    D'après l'ami Agner, le compilateur se livre à une analyse syntaxique du code C pour optimiser le code C au possible (élimination de branches, évaluation partielle des expressions arithmétiques, etc), puis ensuite traduire ce code C optimisé en x86 mot à mot. Enfin je suppose.

    Mais y'a pas une phase où il optimise séparément le code x86 tout seul?

    Mon problème, c'est que j'ai pas optimisé d'assembleur depuis le MIPS, donc je ne suis pas très au fait.

  13. #8383
    Dans un compilo, il y a 3 morceaux : le début, le milieu, et la fin le front-end, le middle-end et le back-end.
    Le front-end fait l'analyse syntaxique sur le C ou n'importe quel autre langage et le traduit en une représentation intermédiaire interne au compilo. Il n'optimise pas, en principe. Tu as un front-end par langage d'entrée.

    La représentation intermédiaire, c'est du bytecode et des graphes. Dans LLVM c'est la LLVM IR, dans gcc c'est Gimple et tout un bordel. Ça ne dépend (en théorie) ni du langage d'entrée ni de l'architecture de sortie.

    Le middle-end fait la plupart des optimisations, celles qui sont indépendantes de l'architecture cible. Tu as un seul middle-end, mais il contient plein d'analyses et de transformations possibles qu'on va appliquer au pif dans un ordre précis savamment étudié.

    Le back-end traduit le langage intermédiaire en assembleur, en faisant des optimisations dépendantes de l'archi cible au passage, genre choix des instructions et scheduling. Tu as un back-end par architecture cible.

    Protip : dans gcc, les options qui commencent par -f causent au front-end/middle-end, celles en -m causent au back-end.

  14. #8384
    Citation Envoyé par Møgluglu Voir le message
    Protip : dans gcc, les options qui commencent par -f causent au front-end/middle-end, celles en -m causent au back-end.
    J'avais jamais percuté !
    Rust fanboy

  15. #8385
    Citation Envoyé par Møgluglu Voir le message
    Par "au moment de l'élaboration", je parle de la première étape de synthèse qui correspond à la compilation pour le software. J'essayais de faire de la méta-programmation pour que le code qui lit le fichier soit exécuté par l'outil de synthé au moment de l'élaboration. Le fichier d'initialisation est dans le répertoire des sources de l'hôte.
    Code:
    architecture structural of My_Memory is
    	constant rambits : natural := 8;
    	type ram is array(0 to 2**rambits - 1) of instruction_word;
    
    	impure function Read_File(fname : string) return ram is
    		file fh       : text open read_mode is fname;
    		variable ln   : line;
    		variable addr : natural := 0;
    		variable word : instruction_word;
    		variable output : ram;
    	begin
    		report "Opened file " & fname;
    		while addr < 2**rambits loop
    			if endfile(fh) then
    				report "Unexpected EOF!";
    				exit;
    			end if;
    			readline(fh, ln);
    			report "line(" & integer'image(addr) & ")= " & ln.all;
    			hread(ln, word);
    			output(addr) := word;
    			addr := addr + 1;
    		end loop;
    		return output;
    	end function;
    
    	-- Qu'une fonction impure abreuve mes signaux !
    	signal imem : ram := Read_File("my_mem.hex");
    	signal address : natural range 0 to 2**rambits - 1 := 0;
    begin
    	process(clock)
    	begin
    		if rising_edge(clock) then
    			address <= to_integer(input_address);
    		end if;
    	end process;
    	data <= imem(address);
    end architecture;
    Transposé dans un langage pour software genre C++, ça reviendrait à initialiser un tableau statique constexpr avec une fonction constexpr qui lit un fichier. On est d'accord que ça n'a aucune chance de marcher, le compilo m'enverrait chier à juste titre. Surtout qu'en VHDL la fonction est explicitement marquée "impure" vu qu'elle a des effets de bord sur le système de fichier hôte.

    Ce qui me tue, ce n'est pas que ça ne marche pas (encore que les outils Xilinx vont lire le fichier sans broncher), c'est que je n'ai même pas un putain de warning dans la console pour me dire que peut-être que remplacer les données lues par des zéros ça pourrait changer légèrement le comportement de mon circuit...
    Ha ok, je vois, mais j'imagine que pour lui, par défaut ce n'est qu'une simple chaîne de caractère sans aucun sens, vu qu'il n'a pas de notion de fichier lors de la compil. Néanmoins il devrais certainement te préciser qu'il est en train de transformer par défaut une chaîne de caractère en 0 "parce que". Ya pas moyens d'activer plus de Warning via une option ? Un peu à la manière d'un GCC ?

    - - - Mise à jour - - -

    Citation Envoyé par vectra Voir le message
    Y'a des cours de FPGA à mon IUT, mais j'ai jamais eu l'occasion d'y toucher.
    Quelques doctorants amenés à en faire, visiblement atteints de syndrome post-traumatique, et pas franchement à l'aise avec, et pas tellement de recul dessus on dirait.

    D'après ce que j'en ai compris, c'est bien pour faire de l'embarqué sur un petit circuit portable qui consomme modérément, mais niveau performances c'est vraiment si bon que ça sur des applis scientifiques (FFT, accès à grosses mémoires, tout ça)? Visiblement, chez nous, c'est pas orienté perfs du tout, mais plutôt embarquement dans de petits appareillages.
    Gnééé ? C’est hardware donc ce que tu pond sur des portes en FPGA s’exécute virtuellement "infiniment vite" (par rapport à un programme software). C'est plutôt QUE orienté perfs en général.
    En embarqué ça évite de créer une carte dédié pour des applis qui changerais sur un robot généraliste (donc gain de couts) et effectivement on peut s'en foutre des performance du truc qui sont alors similaires à la première solution. Mais ça reste toujours bien meilleurs qu'une solution software.

    En embarqué ça permet également de réduire la conso sur des trucs qui serait lourd en software et qui consommerais donc beaucoup. Enfin ça permet de faire de l'ultra fiabilité pour des trucs genre satellite (on fait ça dans mon labo) vu qu'il y a possibilité de détecter en live des portes défectueuses (rayon cosmique qui passerais par là, par exemple) et de trouver d'autres chemin pour que la carte hardware reste fonctionnelle. Tout benef ^^.

    Donc quand il s'agit de remplacer une solution Hardware par un FPGA c'est évidemment équivalent en terme de perf (ou même un peu plus lent car pas forcement opti par rapport à une carte dédiée ou à une solution de traitement analogique) et souvent c'est pour une des raisons sus-cités. Mais quand il s'agit d'adapter un programme software en FPGA c'est absolument pour les perfs, qui sont bien bien supérieure (genre nous on le fait pour des traitements de vision/traitement d'image en live bah c'est à mille lieux de ce que peut faire un processeur moderne, et un poil supérieur à une solution implémentée sous carte graphique dans bien des cas).

  16. #8386
    J'avais compris, sur leur projet, que ce qui comptait pour eux était de faire rentrer le dispositif dans des objets plus petits qu'un rapsberry. Ensuite, il font du traitement du signal 1D avec des petits tampons si j'ai bien suivi.

    Moi, dans l'absolu, ça m'intéresse de savoir (*) si ma job sur GPU avec de gros volumes de mémoire *single-float* serait portable sur FPGA, et dans ce cas, dans quelle mesure on peut espérer accélérer le traitement. Alors je ne sais pas si on peut implémenter directement de la mémoire avec des portes logiques en FPGA, et si ça peut monter à 4Go, mais il semblerait que pas. Mon appli reste très fortement limitée par la bande-passante mémoire, donc s'il faut implanter de la mémoire externe sur un circuit, ça ne servirait à rien a priori.

    Ma seconde application du FPGA, ça serait des FFT 2D *single-float* et quelques traitements sur des images 1024*1024 se terminant par le découpage d'une zone utile bien plus petite. Pour l'instant c'est fait sur GPU, mais si on pouvait déporter ça sur un FPGA, voire FPGA intégré à une caméra d'acquisition (y'en a), on gagnerait un bon facteur de vitesse en amont des calculs, et ce juste parce qu'on pourrait fortement réduire le besoin en bande passante entre caméra et CPU->GPU.


    Je sais que mes questions peuvent paraître idiotes, mais j'ai plutôt une formation informatique de base et le FPGA sort clairement de mes compétences.


    (* surtout pour argumenter, dans ma thèse)

  17. #8387
    Citation Envoyé par Møgluglu Voir le message
    Pour l'exemple de Tomaka, j'ai supposé qu'on parle d'une addition flottante avec une latence de 3 cycles. Dans ce cas si chaque addition est dépendante de la précédente, ça fait 150 cycles. Mais si on parle d'une addition entière avec 1 opérande en mémoire, c'est de la triche, c'est plusieurs µops...
    Agner Fog détaille dans un exemple ce que vous avez essayé de m'expliquer il y a quelques mois, je crois, et qui me fait penser à ce que tu dis.

    En gros, quand on calcule une somme des éléments d'un tableau, parcourir plusieurs cases à chaque itération, avec des sommes réalisées sur accumulateurs différents, permet alors de briser les dépendances?
    Ce qui autorise alors l'exécution superscalaire de plusieurs sommes par cycles au lieu d'une (*), ce qui j'imagine optimise le taux d'occupation. Si jamais j'ai bon sur ça, faudrait encore que je voie en quoi l'exécution dans le désordre intervient.

    Oui, là aussi, c'est encore confus.

    (*) Je vois qu'il y a une ALU pour 3 ports différents du scheduler, mais ça ne marche que pour les entiers. Pour SSE/AVX, il y a un MUL sur un port, et un ADD sur l'autre.

  18. #8388
    Citation Envoyé par vectra Voir le message
    Agner Fog détaille dans un exemple ce que vous avez essayé de m'expliquer il y a quelques mois, je crois, et qui me fait penser à ce que tu dis.

    En gros, quand on calcule une somme des éléments d'un tableau, parcourir plusieurs cases à chaque itération, avec des sommes réalisées sur accumulateurs différents, permet alors de briser les dépendances?
    Ce qui autorise alors l'exécution superscalaire de deux sommes par cycles au lieu d'une, ce qui j'imagine optimise le taux d'occupation. Si jamais j'ai bon sur ça, faudrait encore que je voie en quoi l'exécution dans le désordre intervient.
    Bah, en gros, si tu traites deux cases par itération, tu as deux chaînes de dépendances (el0 + el2 + el4 + ...) et (el1 + el3 + el5 + ...), donc tu peux faire ça plus vite, en effet. Bon après techniquement ta réduction tu peux la vectoriser et utiliser SSE/AVX mais ça je crois que tu connais

    Dans cet exemple particulier, l'exécution dans le désordre te permettra par exemple de calculer les adresses des loads suivants (i+=2 et j+=2 si tu accèdes à array[i] et array[j]) pendant que les loads précédents accèdent à la hiérarchie mémoire, ainsi que lancer les loads suivants alors que les précédents n'ont pas nécessairement terminé leur accès. Sans l'OoO, il faudrait attendre que les loads reviennent et que l'accumulation soit faite avant de calculer le prochain indice*. Voilà, j'espère que je n'ai pas raconté trop n'importe quoi

    * Je considère que tu fais en gros:
    Code:
    i = 0, j = 1;
    for(whatever; i+=2, j+=2) {
     somme_partielle1 += array[i];
     somme_partielle2 += array[j];
    } 
    
    somme = somme_partielle1 + somme_partielle2;
    Dernière modification par Thamior ; 04/02/2016 à 17h11.
    Citation Envoyé par François
    L'ordinateur cantique, c'est l'avenir.

  19. #8389
    Oui c'est ça, c'est exactement l'exemple d'Agner

    J'allais dire que, pour une somme d'entiers, il fallait mettre autant de sommes partielles qu'il y a d'ALUs sur les ports du scheduler (ici: 0,1,5) pour maximiser le parallélisme. Mais en fait, j'avais oublié les calculs de boucle.

    Donc, si on part sur la somme d'un tableaux de flottants vectorisés (déjà plus proche de mon applicatif), ça n'aurait pas de sens de créer deux sommes partielles, puisque seul le port 1 dispose d'un SSE_ADD?
    Et cette version sans sommes partielles verrait par contre les calculs d'indice dispatchés sur les port 0 et 5.


    , mais SSE ADD sur un seul port (le 1), ne serait

  20. #8390
    Alors déjà, ton tableau il est en mémoire, donc ce qui sera limitant n'est pas forcément le nombre de ports INT/FP mais aussi le nombre de ports loads. Par exemple, si on fait une réduction d'un tableau d'entier, tu as quatre ports ALU sur Haswell, mais deux ports load. Donc en gros, tu ne pourra pas lire plus de deux éléments par cycle, donc ça ne sert à rien de faire plus que deux sommes partielles. Note que ça c'est la version naïve pas vectorisée (suivant l’implémentation, charger 256-bit avec un seul load AVX peut te permettre d'aller encore plus vite).

    Si tu fais du flottant vectorisé (et je n'ai pas la liste des ports sous les yeux), il n'y a pas l'air utile d'avoir plus qu'une addition à faire par cycle. Cela dit, ton addition fait 4 éléments par cycle, donc d'un autre côté t'es déjà gagnant par rapport à la version scalaire.
    Citation Envoyé par François
    L'ordinateur cantique, c'est l'avenir.

  21. #8391
    Même si tu n'as qu'un port SSE_ADD, l'additionneur flottant est un pipeline à 3 étages. Si tu n'as qu'un seul (vecteur d')accumulateur, tu devras attendre deux cycles le temps que la nouvelle valeur de l'accumulateur sorte du pipeline avant de pouvoir la réinjecter dans l'addition suivante.

    Il te faut donc au minimum 3 accumulateurs pour pouvoir lancer une addition par cycle.

    Pour t'embrouiller encore plus, si tu es sur Haswell, tu peux aussi utiliser le pipeline FMA sur l'autre port pour faire des additions, en ajoutant des multiplications par 1. Le pipeline FMA fait 5 étages, donc il te faut 5 accumulateurs de plus :
    Code:
    __mm256 * array;
    i = 0;
    for(whatever; i+=8) {
     somme_partielle1 = _mm256_add_ps(somme_partielle1, array[i]);
     somme_partielle2 = _mm256_add_ps(somme_partielle2, array[i+1]);
     somme_partielle3 = _mm256_add_ps(somme_partielle3, array[i+2]);
     somme_partielle4 = _mm256_fmadd_ps(array[i+3], one, somme_partielle4);
     somme_partielle5 = _mm256_fmadd_ps(array[i+4], one, somme_partielle5);
     somme_partielle6 = _mm256_fmadd_ps(array[i+5], one, somme_partielle6);
     somme_partielle7 = _mm256_fmadd_ps(array[i+6], one, somme_partielle7);
     somme_partielle8 = _mm256_fmadd_ps(array[i+7], one, somme_partielle8);
    } 
    
    // Arbre de réduction inter-vecteurs
    somme_partielle1 = _mm256_add_ps(somme_partielle1, somme_partielle2);
    somme_partielle3 = _mm256_add_ps(somme_partielle3, somme_partielle4);
    somme_partielle5 = _mm256_add_ps(somme_partielle6, somme_partielle5);
    somme_partielle7 = _mm256_add_ps(somme_partielle8, somme_partielle7);
    
    somme_partielle1 = _mm256_add_ps(somme_partielle1, somme_partielle3);
    somme_partielle5 = _mm256_add_ps(somme_partielle7, somme_partielle5);
    
    somme_partielle1 = _mm256_add_ps(somme_partielle1, somme_partielle5);
    
    // Arbre de réduction intra-vecteur
    somme_partielle_1 = _mm256_hadd_ps(somme_partielle_1, somme_partielle_1);
    somme_partielle_1 = _mm256_hadd_ps(somme_partielle_1, somme_partielle_1);
    somme_partielle_1 = _mm256_hadd_ps(somme_partielle_1, somme_partielle_1);
    // Résultat dans les 32 bits de poids faible de somme_partielle_1
    Là en principe ça déboite, et le code fait 2 additions vectorielles de 8 éléments chacune par cycle. Bon, en réalité comme dit Thamior ta hiérarchie mémoire n'arrivera jamais à te fournir les 2x256 bits par cycle nécéssaires pour nourrir tes unités de calcul...

    Sinon, pour évaluer l'utilisation des ports d'exécution AVX sur une petite boucle, y'a qu'à utiliser l'outil d'Intel du même nom.

  22. #8392
    >Thamior:


    Ah oui, je vois qu'il n'y a que les ports 2 et 3 (sur Ivy Bridge) qui ont des load disponibles.

    Oula, donc en fait y'a du monde qui se bouscule:
    Il nous faut commencer par deux loads (1 cycle, ports 2 et 3).
    ensuite, il nous faut deux AVX_ADD (2 cycles, port 1)
    puis deux store (1 cycle, ports 2 et 3)

    Les deux calculs pour l'update des itérateurs de boucle à la fin, ils peuvent être casés dans le premier cycle des loads, vu qu'il y a une ALU sur le port 0,1 et 5 et qu'elles ne foutent rien.

    Ca fait 4 cycles en tout, pour deux cases de tableau traité: c'est plutôt pas mal non?
    J'imagine que les compilateurs sont capables de compter sur ça, par contre?


    La mémoire met fin à la fête, comme d'habitude, mais j'imagine que si on effectue l'arithmétique au plus vite, il y aurait éventuellement un gain quand-même, mais pas sur un cas aussi trivial.

    - - - Mise à jour - - -

    Citation Envoyé par Møgluglu Voir le message
    Même si tu n'as qu'un port SSE_ADD, l'additionneur flottant est un pipeline à 3 étages. Si tu n'as qu'un seul (vecteur d')accumulateur, tu devras attendre deux cycles le temps que la nouvelle valeur de l'accumulateur sorte du pipeline avant de pouvoir la réinjecter dans l'addition suivante.

    Il te faut donc au minimum 3 accumulateurs pour pouvoir lancer une addition par cycle.
    Ha ouais, j'avais vraiment RIEN compris.
    On ne peut utiliser qu'une unité de calcul par port, mais ces unités sont pipelinées, et à un nombre d'étages différent les unes des autres?

    Donc en fait, y'a un double parallélisme d'instructions: le nombre de ports différents du scheduler qui proposent des unités d'exécution pour les instructions implémentant ta boucle, et en plus le taille du pipeline pour chaque unité.

    Cet exemple, je le comprends bien maintenant:
    Code:
    for(whatever; i+=8) {
     somme_partielle1 = _mm256_add_ps(somme_partielle1, array[i]);
     somme_partielle2 = _mm256_add_ps(somme_partielle2, array[i+1]);
     somme_partielle3 = _mm256_add_ps(somme_partielle3, array[i+2]);
     somme_partielle4 = _mm256_fmadd_ps(array[i+3], one, somme_partielle4);
     somme_partielle5 = _mm256_fmadd_ps(array[i+4], one, somme_partielle5);
     somme_partielle6 = _mm256_fmadd_ps(array[i+5], one, somme_partielle6);
     somme_partielle7 = _mm256_fmadd_ps(array[i+6], one, somme_partielle7);
     somme_partielle8 = _mm256_fmadd_ps(array[i+7], one, somme_partielle8);
    }
    Ce détournement de FMA
    Mais si chaque load_ps ou store_ps nous prend 50 cycles CPU chacun, ça risque de gâcher la fête. Mais c'est drôle quand-même!
    Dernière modification par vectra ; 04/02/2016 à 18h33.

  23. #8393
    Oui, c'est ça. Le pipeline a une largeur (superscalaire) et une profondeur (nombre d'étage).
    La largeur est le débit d'exécution (flops/cycle). La profondeur est la latence (cycles). Le parallélisme dont tu as besoin pour saturer le pipeline (nombre d'accumulateurs ou flops) est le produit latence×débit.

    Par exemple, sur un GPU, si tu as 10 fois plus de débit mais aussi 10 fois plus de latence que sur ton CPU, tu auras besoin de 100 fois plus de parallélisme pour l'exploiter.

    Citation Envoyé par vectra Voir le message
    Mais si chaque load_ps ou store_ps nous prend 50 cycles CPU chacun, ça risque de gâcher la fête. Mais c'est drôle quand-même!
    50 cycles de latence. La mémoire est un pipeline aussi. Si la bande passante suit derrière, tu peux démarrer un, voire deux loads indépendants par cycle.

    Même si tu n'as pas 50 accumulateurs pour couvrir la latence (c'est pas un GPU), le prefetcher hardware va détecter facilement que tu fais des accès séquentiels et il va te faire remonter les données dans le cache L1 avant même que tu les demandes. Au final, tant que tu as assez de parallélisme, c'est le débit qui limite, pas la latence.

  24. #8394
    Sur GPU, j'avais compris intuitivement que c'était l'accès parallèle qui cachait la latence. Qui était accrue sur GDDR5, de même que les débits. Ce qui donne au final des débits de malade, mais uniquement pour du code massivement parallèle.
    Dans les détails, c'est plus flou.

    Ah mais donc là, je confonds complètement débits et latences . Je me rends compte que je ne comprends pas du tout le fonctionnement de la mémoire.
    Y'a une publi de 50 pages dessus que j'ai dû imprimer 5 ou 6 fois sans avoir le courage de dépasser l'intro, je pense que la soirée va être goleri.


    En mode pour les nuls, supposons un débit mémoire de 21Go/s (DDR3 1333, dual channel) et une fréquence CPU de 3 ghz.
    Ca nous fait 21 Goctets en 3Gcycles, soit jusqu'à 7 octets débités par cycle CPU? Il faudrait 3 cycles pour remplir un registre SSE 128 bits alors?

    Et ce, en supposant qu'il faut payer 50 cycles rien que pour accéder au début du tableau, mais plus rien par la suite en théorie?
    Dernière modification par vectra ; 04/02/2016 à 19h24.

  25. #8395
    Bah si tu n'as rien dans le cache, en moyenne ça doit faire un truc du genre. Après honnêtement la DRAM c'est tellement le bordel que j'ai pas envie (et je n'en suis probablement pas capable) de bien calculer ce qui va se passer si tu fais ceci ou cela.
    J'ajouterais aussi que quand tu ne fais pas du streaming tes caches augmentent ton débit (et diminuent ta latence) de façon assez significative, alors que quand tu fais du streaming, tu pries pour que le prefetcher fasse bien son boulot.

    Maintenant, comme disait Mogluglu, "tu peux démarrer un voire deux loads indépendants par cycle" (a priori depuis Nehalem ou même Conroe c'est deux chez Intel), donc c'est pipeliné: tous les loads vont payer les 50 cycles d'accès à la mémoire, mais comme les latences se chevauchent, 2x64 bits reviendront à chaque cycle.
    Citation Envoyé par François
    L'ordinateur cantique, c'est l'avenir.

  26. #8396
    Citation Envoyé par vectra Voir le message
    J'avais compris, sur leur projet, que ce qui comptait pour eux était de faire rentrer le dispositif dans des objets plus petits qu'un rapsberry. Ensuite, il font du traitement du signal 1D avec des petits tampons si j'ai bien suivi.

    Moi, dans l'absolu, ça m'intéresse de savoir (*) si ma job sur GPU avec de gros volumes de mémoire *single-float* serait portable sur FPGA, et dans ce cas, dans quelle mesure on peut espérer accélérer le traitement. Alors je ne sais pas si on peut implémenter directement de la mémoire avec des portes logiques en FPGA, et si ça peut monter à 4Go, mais il semblerait que pas. Mon appli reste très fortement limitée par la bande-passante mémoire, donc s'il faut implanter de la mémoire externe sur un circuit, ça ne servirait à rien a priori.

    Ma seconde application du FPGA, ça serait des FFT 2D *single-float* et quelques traitements sur des images 1024*1024 se terminant par le découpage d'une zone utile bien plus petite. Pour l'instant c'est fait sur GPU, mais si on pouvait déporter ça sur un FPGA, voire FPGA intégré à une caméra d'acquisition (y'en a), on gagnerait un bon facteur de vitesse en amont des calculs, et ce juste parce qu'on pourrait fortement réduire le besoin en bande passante entre caméra et CPU->GPU.


    Je sais que mes questions peuvent paraître idiotes, mais j'ai plutôt une formation informatique de base et le FPGA sort clairement de mes compétences.


    (* surtout pour argumenter, dans ma thèse)
    Faut que je recherche, mauis il me semble qu'une connaissance doctorante à écrit un papier là dessus (performances pour le calcul de plusieurs FFT en parallèle entre une puce FPGA et un GPU). Je recherche ca, si je retrouve je te le file.

    Je crois que c'était là dedans:
    http://scitation.aip.org/content/aip...1063/1.4894211

  27. #8397
    Tu aurais accès au PDF?

    Sinon, je peux toujours lui demander sur ResearchGate...

  28. #8398
    Citation Envoyé par vectra Voir le message
    Tu aurais accès au PDF?
    Non, pas directement. C'est un peu trop "high level" pour moi et mon DUT en elec' donc je ne m'y suis pas interressé plus que ca. Je me souviens juste qu'elle m'avait montré des mesures faites pour des FFT parallélisées sur le GPU, c'est pour ca que j'y ait re-pensé.

  29. #8399
    Ca a l'air pas mal en effet.
    Bonne pioche... Bon, je vais claquos 20 $ sur mes deniers je pense
    Pire encore, je l'ai eu par le... côté obscur ^2
    Dernière modification par vectra ; 05/02/2016 à 15h14.

  30. #8400
    Citation Envoyé par vectra Voir le message
    Ca a l'air pas mal en effet.
    Bonne pioche... Bon, je vais claquos 20 $ sur mes deniers je pense
    Pire encore, je l'ai eu par le... côté obscur ^2
    Tu 'a acheté en bitcoins?

Page 280 sur 334 PremièrePremière ... 180230270272273274275276277278279280281282283284285286287288290330 ... DernièreDernière

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •