donnée static const Pi=3.14 [C++/résolu] - C++ - Programmation
Marsh Posté le 10-04-2006 à 20:28:02
Test:: Pi est externe et non-définie (quoiqu'il me semble que quand tu l'initialises dans la définition de la classe elle est lié statiquement et donc ca devrai compiler)
Pi est static et est définie
tu dois définir Test:: Pi dans un .cpp
const float Test:: Pi=3.14;
Marsh Posté le 10-04-2006 à 20:31:37
skelter a écrit : (quoiqu'il me semble que quand tu l'initialises dans la définition de la classe elle est lié statiquement et donc ca devrai compiler) |
chez moi ca compile et ca lie (g++ 3.4)
Marsh Posté le 10-04-2006 à 20:40:57
trop de la balle, il y a -fno-threadsafe-statics (donc l'inverse aussi).
ça ne résoud pas mon problème.
Si ++fab passe par là, il me dira p-e, il utilise gcc4 il me semble.
Marsh Posté le 10-04-2006 à 20:53:16
en fait je crois que sur une vieille version (<3) ca ne passait pas l'édition des lien, sur la 3.4 ca passe et à nouveau plus sur la 4
le comportement le plus proche du standard est celui de g++ 4, en fait on peut initialiser directement dans la définition de la classe seulement si la variable static constante est entiere
Marsh Posté le 10-04-2006 à 22:31:35
> si la variable static constante est entiere
oui, ok, je vois, j'ai dû lire ça quelquepart
c'est quoi la raison au fait?
Marsh Posté le 10-04-2006 à 23:03:56
aucune idée, ce n'est pas expliqué dans le stroustrup ni dans le standard
Marsh Posté le 10-04-2006 à 23:23:15
ni sur cpptips, bs renvoi direct à son livre
http://cpptips.hyperformix.com/cpp [...] tatic_init
Marsh Posté le 10-04-2006 à 23:28:17
Ok, prise de tête quoi.
Je vais mettre le sujet en ``irrésolvable``
En attendant, je vais utiliser des variables globales, voire un #define.
Marsh Posté le 10-04-2006 à 23:35:25
je ne penses pas qu'il puisse y avoir de différence au niveau du code généré, en fait pourquoi il y en aurait ?
Marsh Posté le 10-04-2006 à 23:35:44
constante inline, ça n'a pas de sens.
ça n'en aura jamais -- je dis ça par ce qu'il y a eu jadis un proposal la dessus mis aux oubliettes.
Marsh Posté le 10-04-2006 à 23:47:36
ben, si je déclare par exemple:
lib.h:
static int a;
lib.cpp:
int a=0;
en ASM il va me chercher l'adresse de la constante, la charger dans un registre, et l'utiliser
si je met:
#define A 0
il va me mettre un ``xor eax,eax`` tout bête et 10 fois plus rapide.
moins efficace avec d'autre valeurs, mais même principe.
Marsh Posté le 10-04-2006 à 23:56:14
La même avec static int const a, en compilation optimisée ?
et même sans utiliser de compilation optimisée, les "static const" sont quasi toujours optimisés.
Marsh Posté le 11-04-2006 à 00:00:32
+1, le compilateur ne peut pas deviner la constance de a, il faut la lui communiquer et le mot-clef const est la pour ca
et puis dans un programme un minimun complexe ces optimisations seront "silencieuses", ne sacrifie pas la structure de ton code au profit d'optimisations subtentielles qui n'aurait sans doute pas lieu d'etre si tu faisais les choses dans l'ordre (une fois le programme terminé, en se basant sur les informations de profilage)
Marsh Posté le 11-04-2006 à 00:01:45
ReplyMarsh Posté le 11-04-2006 à 00:10:17
> (une fois le programme terminé, en se basant sur les informations de profilage)
- je vais pas attendre le profilage pour me rendre compte que j'utilise minimum 1Mega*25 fois cette constante par seconde.
> et même sans utiliser de compilation optimisée, les "static const" sont quasi toujours optimisés.
- tu m'explique comment le compilo fait pour optimiser une constante dans un .cpp quand tu lui donne le .h? ou tu m'explique comment le linker fait pour optimiser cette même constante là où il faut sans les sources.
Marsh Posté le 11-04-2006 à 00:17:03
Citation : - je vais pas attendre le profilage pour me rendre compte que j'utilise minimum 1Mega*25 fois cette constante par seconde. |
elle sera placée dans un registre ou en cache, j'imagine, dans la mesure ou le compilateur dispose des informations necessaires
Citation : |
idem, il en connait l'adresse et pourra généré le code pour la placer en registre par exemple, mais c'est sur qu'il ne pourra pas l'inserer dans le code mais ca c'est pratiquement invisible comme optimisation
tu pourrait pas nous montrer un exemple avec et sans qu'on puisse tester pour voir la différence de performance ?
Marsh Posté le 11-04-2006 à 00:18:09
nargy a écrit : ben, si je déclare par exemple: |
ouais sauf qu'en float, y'a pas de constante (a part 0 et 1)
Marsh Posté le 11-04-2006 à 00:31:34
Pi c'est pour exemple, mes constantes sont des coordonnées polaires sur 6+1 plans:
Real AlphaMin=-1;
Real AlphaMax=1;
Real BetaMin=-1;
Real BetaMax=1;
int GammaMin=0;
int GammaMax=5;
int GammaNull=-1;
avec Real=float,double ou long double
non, sérieux, si je dis que j'ai besoin de constantes inline, c'est que j'en ai vraiment besoin. ça veux peut être rien dire en C++ une constante inline, mais c'est assez explicite sur ce que j'ai besoin.
Si vous avez autre chose d'équivalent, je prends, mais moi je connais pas...
Pour les tests de prefs, je veux bien, mais je sens que ça va encore être prise de tête, et finalement on aura pas toutes les réponses que l'on attends comme avec le coup des pointeurs de fonctions/fonctions virtuelles.
Et finalement, d'expérience, les compilos ils optimisent jamais comme on imagine. Là je peut pas faire mieux qu'installer gcc4.
Aller, vous conaissez les concepteurs de quake, ils ont pour devise:
Citation : |
Moi, je prends.
Marsh Posté le 11-04-2006 à 00:50:04
Enfin, merci de vos conseils.
Je les prends tout de même en compte, je les utiliserai sûrement dans d'autres parties de code.
Merci.
Marsh Posté le 11-04-2006 à 01:48:23
Bon ok, voilà le listing ASM avec gcc4 -O2 et Real=double:
Code :
|
``define`` et ``static const`` utilisent le prefetch, et ``class static const`` peut utiliser le cache sauf si le segment de donnée est trop gros (ce qui est le certainement cas dans mon programme, ainsi que pour le segment de code).
Quelques cycles de différence.
Edit: testé avec pi=3.14
Marsh Posté le 11-04-2006 à 16:56:55
Suivant ta platforme et les options, gcc va p-e essayer de regrouper les constantes similaires de toute façon (pooling).
J'ai du mal a saisir ce que tu veux vraiment obtenir in fine: un fldpi? chargement par immediats (movl $1374389535, %ebx; movl $1074339512, %esi; push; push)? reference memoire?
Pour ma part, quand j'ai des 'constantes' re-utilisable qui trainent, plutot que d'esperer que le compilo/linker les regroupent, je les colle explicitement dans une meme section R/O: j'ai comme ça une ligne de cache chaude avec plusieurs de ces constantes sous le coude.
Le seul probleme c'est d'obtenir que ces constantes ne soient pas construites, ce qui n'est pas forcément évident.
Par exemple & flemme voici ce que j'utilise pour des 'packed scalars'; fonctionne avec gcc et msvc.
D'abord une union pour enrober le tout et prodiguer la magie necessaire pour eliminer les constructeurs, tout est dans l'utilisation d'entiers comme premier champs.
Code :
|
Puis la declaration du contenu de la section, aussi visible de tous.
Code :
|
Enfin, qque part dans un coin obscur, la definition des valeurs.
Code :
|
On est d'accord c'est un peu ampoulé. Mais on obtient une section R/O cacheable à souhait remplie de constantes triées sur le volet.
Et une section PIPOBIMBO dans un binaire, ça le fait. Non?
Marsh Posté le 11-04-2006 à 17:47:11
> J'ai du mal a saisir ce que tu veux vraiment obtenir in fine: un fldpi? chargement par immediats (movl $1374389535, %ebx; movl $1074339512, %esi; push; push)? reference memoire?
Le plus rapide possible, pour un bloc de donnée qui ne tient pas dans le cache entièrement, et un bloc de code non plus. Je ne connais pas assez bien l'assembleur des pentiums, mais il me semble que mettre les constantes directement dans le bloc de code avec movl $1074339512, %esi .. est le plus rapide dans ce cas, puisque est mis en prefetch.
> Et une section PIPOBIMBO dans un binaire, ça le fait. Non?
je ne connais pas le terme PIPOBIMBO. Le code assembleur que j'ai montré plus haut est fait par le compilo GCC4, sur un programme qui fait un printf() des constantes (d'où les pushl). En fait, ce que je cherche c'est à optimiser au max, sans mettre de l'assembleur dans le code C++. Si je comprends bien, tu fait une double déclaration avec union d'entiers et de flottant, j'utilise ça aussi dans d'autres parties de code (par ex. extraire l'exposant binaire d'un nombre réel sans utiliser frexp de math.h). Mais pour mes constantes je préfère laisser le compilo faire les optimisations necessaire s'il s'agit de traiter des flottant comme des entiers, car je compte compiler mon programme avec plusieurs tailes de flottants (float,double,long double) (au moins pour tester). Celà m'obligerai à utiliser des #define trop souvent. Comme derrière j'ai des structures de données (très) complexes je ne préfère pas alourdir encore le code.
Je pense, mais peut être à tord, que dans ces conditions un movl avec une constante en paramètre permet dans un cas général d'avoir une meilleure optimisation que d'avoir des constantes accesibles par déréférences. Le compilo s'arrange pour garder en registre les constantes si c'est possible, et il génère de nouvelle constantes (comme par ex. (min+max)/2.0) sans instruction supplémentaire.
De plus, je n'utilise jamais, mais alors jamais jamais, d'identificateurs avec '_' devant, et encore moins '__'. Ces identificateurs sont sujets à changement dans d'autre versions de librairies, de compilo ou de système. C'est trop le bordel, quoi. Ceci dit, je comprends que dans certains cas celà permet de coller au mieux à la plateforme.
mov (constante, registre) est le plus rapide, je me trompe?
Marsh Posté le 11-04-2006 à 18:39:11
nargy a écrit : > J'ai du mal a saisir ce que tu veux vraiment obtenir in fine: un fldpi? chargement par immediats (movl $1374389535, %ebx; movl $1074339512, %esi; push; push)? reference memoire? |
Sauf que dans le cas des flottants, sur x86, il n'y pas moyen de charger des immédiats directement sur la pile de la fpu; si tu passes par un GPR, avec par exemple movl $1074339512, %esi, il faudra ensuite l'écrire qque part et charger ça sur la pile.
Je simplifie un peu, il y a des exceptions http://enrico.phys.cmu.edu/QCDclus [...] /vc102.htm d'ou mon allusion à fldpi. Ca ne s'arrange pas avec SSE.
De toute façons gcc est parfaitement au courant de toutes ces nuances d'encodage.
Ensuite la bande passante de decodage, que tu essaies de transiger, est une denrée rare.
nargy a écrit : > Et une section PIPOBIMBO dans un binaire, ça le fait. Non? |
Non, tu te méprends sur la finalité de mon union. Comme précisé dans le post précédent cette union ne sert qu'a s'assurer de l'abscence de constructeurs à l'initialization de mes constantes.
Si le compilateur produit un constructeur, par définition il ne peut déposer mes constantes dans une section Read-Only, or c'est la l'objet de toutes ces contortions.
Comme expliqué précedement le seul moyen de generer des constantes en flottant c'est:
a) de les charger depuis la mémoire.
b) de les calculer d'une façon ou d'une autre.
Gcc et le linker vont de toute façon essayer de regrouper toutes les constantes, je prend juste les devants et m'assurant de leur unicité et de leur cacheabilité.
nargy a écrit : |
Ton modele de coût est bien trop simpliste et de toute façon, encore une fois, c'est techniquement impossible pour des flottants sur un x86.
Marsh Posté le 11-04-2006 à 18:50:07
nargy a écrit : > si la variable static constante est entiere |
sans doute à cause d'une difficulté d'implémentation quelconque pour les <pas types entiers>. C'est proposé pour 0x de supporter les constantes littérales flottantes.
Marsh Posté le 11-04-2006 à 18:56:18
sinon, on rêve tous de constantes extern inlinées dès possibles Faut faire son deuil : ou multiple définitions, ou bien payer un petit prix à l'accès . J'ai récemment gagner 17k de .text et bien 4k de .data en virant la définition d'une
namespace Foo { const string TAG("foo" ); } hors du .hpp en faveur d'un extern const. Ce const était d'autant plus dommageable, que pour chaque .cpp incluant le .hpp, bam, une instance de TAG ... même si personne n'utilise ...
Marsh Posté le 11-04-2006 à 20:09:44
Merci pour vos commentaire, ça m'aide beaucoup.
tbp>
ok, c'est noté, pour les affectations de flottants. je me faisait une fausse idée sur la question. je vais étudier ce lien.
> De toute façons gcc est parfaitement au courant de toutes ces nuances d'encodage.
ouf, tant mieux!
> Ensuite la bande passante de decodage, que tu essaies de transiger, est une denrée rare
- Là encore je dois me faire une fausse idée, de ce que j'ai vaguement lu.
> cette union ne sert qu'a s'assurer de l'abscence de constructeurs à l'initialization
- ok, j'imagine que c'est plus efficace sans présumer des capacités du compilateur et des options de compil.
> je prend juste les devants et m'assurant de leur unicité et de leur cacheabilité.
- ok, je comprends
mais j'aurai quand même une question: comment fonctionne le cache? je ne demande pas une réponse exhaustive, mais si vous avez un lien sur une doc, ou quelques recommandations. J'ai toujours considéré que pour un code trop long ou des données trop fournies les optimisations par cache devenaient secondaires, dû à la saturation du cache.
taz>
> C'est proposé pour 0x de supporter les constantes littérales flottantes.
cool
> sinon, on rêve tous de constantes extern inlinées dès possibles
- ouais, faut faire le deuil.
> J'ai récemment gagner 17k de .text et bien 4k de .data en virant la définition d'une
namespace Foo { const string TAG("foo"; }
- à mon avis, l'optimisation sur les chaînes de caractères, il faut faire le deuil aussi la plupart du temps, quand j'utilise des chaînes, c'est pas dans une optique de performances. Le moindre printf te bouffe tout les cycles que tu peut économiser. Et ça doit saturer le cache.
Marsh Posté le 11-04-2006 à 20:12:29
ReplyMarsh Posté le 11-04-2006 à 20:14:42
nargy a écrit : |
que ce soit une string, ça n'est que pour l'exemple. dès que tu as un objet pas POD, ben il faut faire attention
Marsh Posté le 11-04-2006 à 20:18:30
> dès que tu as un objet pas POD, ben il faut faire attention
- ouais
- qui confirme l'utilité de l'union de Tbp.
Marsh Posté le 11-04-2006 à 20:20:54
Taz a écrit : sinon, on rêve tous de constantes extern inlinées dès possibles Faut faire son deuil : ou multiple définitions, ou bien payer un petit prix à l'accès . |
Non, non et non. Il n'y a rien de gratuit en ce bas monde. Si une constante est 'inlinée' comme vous dites, au lieu d'un accès mémoire explicite vous payez pour de la bande passante de decodage car l'instruction requiert plus de place pour etre encodée. Savoir si cela est un gain ou non requiert de prendre en compte un peu plus de facteurs.
Encore une fois un compilo comme gcc 4.x est parfaitement à meme d'effectuer ce genre de transformation de lui meme. Encore faut-il pour cela exposer les choses clairement.
Taz a écrit : |
Ca n'a strictement rien a voir.
Marsh Posté le 11-04-2006 à 20:24:42
nargy a écrit : taz> |
Ah, je n'en vois aucunes traces :|
J'apprécierai (vu mon état de fatigue), un lien vers le proposal en question
Marsh Posté le 11-04-2006 à 20:28:51
1) pas d'accord du tout. Et puis ça coute peut etre plus cher sur ton x86, pas ailleurs. Je vois pas plus court qu'un li ... l'inline de constantes permet très souvent de propager d'autres optimisations. Montre moi comment gcc peut optimiser a + b avec a et b extern const int ...
2) au contraire si.
et puis tu nous fais le parano niveau cache ... alors poursuis ton raisonnement
Marsh Posté le 11-04-2006 à 20:29:22
++fab a écrit : Ah, je n'en vois aucunes traces :| |
bon je commence ma recherche ...
Marsh Posté le 11-04-2006 à 20:33:44
tiens ça a à voir avec mon problème http://www.open-std.org/jtc1/sc22/ [...] /n1469.pdf
Marsh Posté le 11-04-2006 à 20:41:56
nargy a écrit : |
Moui, effectivement ça a voir avec le fait de traiter des POD ou pas, mais en fait pas seulement: comment produire un +/- infinie dans un initialiseur? Ou un NaN?
nargy a écrit : |
Pas de lien sous la main. Tu as differentes caches, je ne parles que de celles pour les instructions & données, de differents niveaux 1/2/3/etc en ordre croissant de taille. En general tout cela fonctionne par 'ligne' avec une regle du genre MRU (Most Recently Used). En gros.
Par exemple sur un K8 (Opteron, AMD64) les lignes de cache de donnée font 64 octets, chacune étant plus ou moins independante des autres. Quand il manque de place, le cpu évince celle qui a été utilisée en dernier. En gros.
Il faut aussi noter qu'il n'y a pas d'unité plus petite que la ligne de cache. Quand tu fais une operation d'écriture au mileu d'une ligne, c'est tout la ligne qui est marquée comme tripotée. Moralité il ne faut pas mélanger ce qui est en lecture seule et ce qui est en écriture.
Donc il se peut que tu ais en cache tout un jeu de donnée provenant des 4 coins de la mémoire, tout est affaire de flux.
nargy a écrit : trop fort ce lien! |
Tout est possible. De toute façon gcc sait generer fld1, fldpi etc... pour peu qu'il reconnaisse la constante, qu'il estime que ça permet de gagner du temps (ou de la place si tu optmises pour la taille) etc...
Marsh Posté le 10-04-2006 à 20:19:25
Bonjour à tous,
Je viens d'installer la dernière version de mon compilo, et alors qu'avant j'utilisais des données static const, j'obtient maintenant une erreur à l'édition des liens. Par contre, dans le flot global ça fonctionne toujours:
Comment faire pour créer une constante inline propre à une classe?
Merci d'avance
Réponse: C++ n'accepte que les entiers initialisés dans la classe.
Solutions alternatives:
- simple: un bon vieux #define
- style C: mettre la constante au dehors de la classe
- optimisé: regrouper toutes les constantes dans une même union de structures, afin d'améliorer l'utilisation du cache du processeur. (merci à tbp pour cette solution)
- longue: attendre que la norme C++ évolue
En addition:
- plus optimisé: ne pas utiliser de compilation séparée.
Message édité par nargy le 11-04-2006 à 23:39:16