 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
dug Guest
|
Posted: Thu Jan 06, 2005 11:00 pm Post subject: trace memoire |
|
|
Bonjour, dans le but de tracer les allocations memoires,
j'ai écris un petit programme qui redéfinit les opérateurs
new et delete globaux avec malloc et free.
Pour pouvoir tracer les allocations des blocs je reserve
un peu plus de memoire qu'il me faut et j'écris un compteur
à cet emplacement mémoire.
tout ça à l'air de bien fonctionner mais j'ai un doute sur
la façon dont je l'ai fait.
voila la fonction allouer qui reserve la memoire:
// le compteur est une union de char[4] et de int
// Tracesize = sizeof( l'union ci dessus )
void* Allouer(std::size_t size, const char *file, int line )
{
void *ptr = (void *)malloc(size + TraceSize);
if( ptr == 0 ) throw std::bad_alloc();
unsigned char* cptr = static_cast<unsigned char*>( ptr);
mCount++;// variable static de classe
for( int i = 0; i <4; i++) cptr[i] = mCount.mc[i] ;
TraceAllocation(cptr, mCount.Int(), size, file, line);
return (cptr + TraceSize);
}
Je créé un objet avec new, qui appelle cette fonction.
Mon doute est que j'écris mon compteur à partir de l'adresse ptr
qui est réservée pour l'objet que je créé, est-ce qu'il ne risque
pas d'y avoir un mélange de données ( entre le compteur et l'objet?),
ou est-ce que l'objet va se ranger juste après ?
Ca dépend du système d'exploitation ?
je suis sous windows et j'utilise g++ (via Devcpp).
merci pour vos réponses.
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Jan 07, 2005 10:02 am Post subject: Re: trace memoire |
|
|
dug wrote:
| Quote: | Bonjour, dans le but de tracer les allocations memoires,
j'ai écris un petit programme qui redéfinit les opérateurs
new et delete globaux avec malloc et free.
Pour pouvoir tracer les allocations des blocs je reserve
un peu plus de memoire qu'il me faut et j'écris un compteur
à cet emplacement mémoire.
tout ça à l'air de bien fonctionner mais j'ai un doute sur
la façon dont je l'ai fait.
voila la fonction allouer qui reserve la memoire:
// le compteur est une union de char[4] et de int
// Tracesize = sizeof( l'union ci dessus )
void* Allouer(std::size_t size, const char *file, int line )
{
void *ptr = (void *)malloc(size + TraceSize);
if( ptr == 0 ) throw std::bad_alloc();
unsigned char* cptr = static_cast<unsigned char*>( ptr);
mCount++;// variable static de classe
for( int i = 0; i <4; i++) cptr[i] = mCount.mc[i] ;
TraceAllocation(cptr, mCount.Int(), size, file, line);
return (cptr + TraceSize);
}
Je créé un objet avec new, qui appelle cette fonction.
Mon doute est que j'écris mon compteur à partir de l'adresse ptr
qui est réservée pour l'objet que je créé, est-ce qu'il ne risque
pas d'y avoir un mélange de données ( entre le compteur et
l'objet?),
ou est-ce que l'objet va se ranger juste après ?
Ca dépend du système d'exploitation ?
je suis sous windows et j'utilise g++ (via Devcpp).
merci pour vos réponses.
|
|
|
| Back to top |
|
 |
dug Guest
|
Posted: Fri Jan 07, 2005 5:11 pm Post subject: Re: trace memoire |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in news:1105092159.058208.141980
@z14g2000cwz.googlegroups.com:
| Quote: | void* Allouer(std::size_t size, const char *file, int line )
{
void *ptr = (void *)malloc(size + TraceSize);
if( ptr == 0 ) throw std::bad_alloc();
unsigned char* cptr = static_cast<unsigned char*>( ptr);
mCount++;// variable static de classe
for( int i = 0; i <4; i++) cptr[i] = mCount.mc[i] ;
TraceAllocation(cptr, mCount.Int(), size, file, line);
return (cptr + TraceSize);
}
|
J'ai pas bien saisi la réponse )
En y réfléchissant, je crois que la réponse est dans ma question.
Reprenez moi si je dis une ânerie:
Si j'alloue (size + tracesize) de place mémoire à l'adresse cptr, j'utilise le début
de la mémoire allouée sur la plage (0,tracesize)
pour numéroter le bloc mémoire, et je retourne le reste de mémoire allouée sur la
plage ( tracesize, tracesize+size) qui a pour adresse de début cptr + Tracesize.
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Mon Jan 10, 2005 1:37 pm Post subject: Re: trace memoire |
|
|
dug wrote:
| Quote: | kanze (AT) gabi-soft (DOT) fr wrote in news:1105092159.058208.141980
@z14g2000cwz.googlegroups.com:
void* Allouer(std::size_t size, const char *file, int line )
{
void *ptr = (void *)malloc(size + TraceSize);
if( ptr == 0 ) throw std::bad_alloc();
unsigned char* cptr = static_cast<unsigned char*>( ptr);
mCount++;// variable static de classe
for( int i = 0; i <4; i++) cptr[i] = mCount.mc[i] ;
TraceAllocation(cptr, mCount.Int(), size, file, line);
return (cptr + TraceSize);
}
J'ai pas bien saisi la réponse )
|
C'est parce que le texte que j'avais ajouté s'est perdu quelque
part. (Je poste souvent à travers Google, et ils sont en train
de faire des modifications souvent en ce moment.)
Le principe de base, c'est que le compilateur ne sait rien de ce
que tu fais dans la fonction operator new(). Tout ce qu'il a,
c'est l'adresse que tu renvoies -- pour lui, c'est ça, le début
du bloc alloué.
La deuxième chose que j'avais dit, c'est que ton code ne marche
pas sur la plupart des machines, parce qu'il ne respecte pas
l'alignement. La norme dit qu'une fonction operator new doit
renvoyer une adresse suffisamment alignée pour tous les types de
données. Sur ma machine, par exemple, ça veut dire une adresse
multiple de 8. Or, tu prends l'adresse rétournée par malloc
(elle aussi convenablement alignée pour touts les types, donc
une multiple de , et tu en ajoutes 4. Sur un Sparc, ça
garantit prèsque un core dump si tu y mets des doubles ; sur un
Intel, il n'y aura pas de core dump, mais le programme
s'exécutera d'une façon notablement moins rapide.
Enfin, je me suis posé la question sur ton histoire de memcpy
(que tu émules en plus avec une boucle explicite). Moi, dans un
cas pareil, je déclare quelque chose du genre :
union BlockHeader
{
int count ;
MaxAlign dummyForAlignment ;
} ;
void*
operator new( size_t n )
{
BlockHeader* p = malloc( n + sizeof( BlockHeader* ) ) ;
if ( p == NULL ) {
throw std::bad_alloc() ;
}
p->count = ++ mCount ;
return p + 1 ;
}
MaxAlign est défini comme un type qui a besoin de l'alignement
maximal.
Enfin, je ne sais pas d'où tu espère tirer les paramètres de
file et de line. (J'utilise une trace de pile dans mon propre
code.)
| Quote: | En y réfléchissant, je crois que la réponse est dans ma
question.
Reprenez moi si je dis une ânerie:
Si j'alloue (size + tracesize) de place mémoire à l'adresse
cptr, j'utilise le début de la mémoire allouée sur la plage
(0,tracesize) pour numéroter le bloc mémoire, et je retourne
le reste de mémoire allouée sur la plage ( tracesize,
tracesize+size) qui a pour adresse de début cptr + Tracesize.
|
C'est ce que tu fais dans ta fonction. Malheureusement, ta
fonction n'est pas correcte en ce qui concerne la gestion de
l'alignement, ni en ce qui concerne les paramètres à passer --
ta fonction ne sera appelée que dans le cas d'un new de
placement.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
| Back to top |
|
 |
dug Guest
|
Posted: Wed Jan 12, 2005 6:04 pm Post subject: Re: trace memoire |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in news:1105364229.646393.29580 (AT) c13g2000cwb (DOT) googlegroups.com:
Merci d'avoir pris le temps de répondre, et désolé de n'être pas
revenu lire plus tôt le newsgroup.
| Quote: | La deuxième chose que j'avais dit, c'est que ton code ne marche
pas sur la plupart des machines, parce qu'il ne respecte pas
l'alignement. La norme dit qu'une fonction operator new doit
renvoyer une adresse suffisamment alignée pour tous les types de
données. Sur ma machine, par exemple, ça veut dire une adresse
multiple de 8. Or, tu prends l'adresse rétournée par malloc
(elle aussi convenablement alignée pour touts les types, donc
une multiple de , et tu en ajoutes 4. Sur un Sparc, ça
garantit prèsque un core dump si tu y mets des doubles ; sur un
Intel, il n'y aura pas de core dump, mais le programme
s'exécutera d'une façon notablement moins rapide.
En effet je me suis pas inquiété de l'alignement de la mémoire |
Sur un AMD ca fonctionne malgré tout, en tout cas chez moi.
| Quote: | Enfin, je me suis posé la question sur ton histoire de memcpy
(que tu émules en plus avec une boucle explicite). Moi, dans un
cas pareil, je déclare quelque chose du genre :
union BlockHeader
{
int count ;
MaxAlign dummyForAlignment ;
} ;
void*
operator new( size_t n )
{
BlockHeader* p = malloc( n + sizeof( BlockHeader* ) ) ;
if ( p == NULL ) {
throw std::bad_alloc() ;
}
p->count = ++ mCount ;
return p + 1 ;
}
|
Effectivement c'est plus clair.
mon BlockHearder est défini comme ceci:
union Uni
{
....
// plusieurs fonctions, operators
....
int mi;
char mc[4];
};
je conçois qu'il est mal adapté au problème!
| Quote: | MaxAlign est défini comme un type qui a besoin de l'alignement
maximal.
comment garantir que MaxAlign ait besoin de l'alignement maximum? |
J'ai vu sur ton site que tu avais déclaré MaxAlign comme
une union de int, long, long double, double et de pointeurs.
N'est t-on pas certain d'avoir l'alignement maximun avec un
type long double ?
| Quote: | Enfin, je ne sais pas d'où tu espère tirer les paramètres de
file et de line. (J'utilise une trace de pile dans mon propre
code.)
|
en fait j'utilise une macro pour remplacer toutes mes occurences de new
#define new new(__FILE__,__LINE__)
et je surcharge new qui sera appellé:
inline void * operator new(unsigned int size, const char *file, int line)
{
void* p = memoire::inst().Allouer(size,file,line);
return p;
};
| Quote: |
En y réfléchissant, je crois que la réponse est dans ma
question.
Reprenez moi si je dis une ânerie:
Si j'alloue (size + tracesize) de place mémoire à l'adresse
cptr, j'utilise le début de la mémoire allouée sur la plage
(0,tracesize) pour numéroter le bloc mémoire, et je retourne
le reste de mémoire allouée sur la plage ( tracesize,
tracesize+size) qui a pour adresse de début cptr + Tracesize.
C'est ce que tu fais dans ta fonction. Malheureusement, ta
fonction n'est pas correcte en ce qui concerne la gestion de
l'alignement, ni en ce qui concerne les paramètres à passer --
ta fonction ne sera appelée que dans le cas d'un new de
placement.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
|
| Back to top |
|
 |
Loïc Joly Guest
|
Posted: Wed Jan 12, 2005 9:42 pm Post subject: Re: trace memoire |
|
|
dug wrote:
| Quote: | en fait j'utilise une macro pour remplacer toutes mes occurences de new
#define new new(__FILE__,__LINE__)
|
Ce code n'est en général pas légal, et en plus, il ne marchera pas dans
ce genre de code :
char *toto=new char[100];
MaClasse *m = new (toto) MaClasse;
Ou encore :
class A
{
void operator new (size_t size);
}
--
Loïc
|
|
| Back to top |
|
 |
Dug Guest
|
Posted: Thu Jan 13, 2005 7:56 am Post subject: Re: trace memoire |
|
|
Loïc Joly <loic.actarus.joly (AT) wanadoo (DOT) fr> wrote in
news:41e599a4$0$19438$8fcfb975 (AT) news (DOT) wanadoo.fr:
| Quote: | dug wrote:
en fait j'utilise une macro pour remplacer toutes mes occurences de
new #define new new(__FILE__,__LINE__)
Ce code n'est en général pas légal, et en plus, il ne marchera pas
dans ce genre de code :
char *toto=new char[100];
MaClasse *m = new (toto) MaClasse;
Ou encore :
class A
{
void operator new (size_t size);
}
|
Oui tu as raison de le souligner, cependant quel autre moyen
peut-on utiliser pour avoir une trace des appels? ( à des fins de
débugage )
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Thu Jan 13, 2005 12:50 pm Post subject: Re: trace memoire |
|
|
dug wrote:
| Quote: | kanze (AT) gabi-soft (DOT) fr wrote in
news:1105364229.646393.29580 (AT) c13g2000cwb (DOT) googlegroups.com:
La deuxième chose que j'avais dit, c'est que ton code ne
marche pas sur la plupart des machines, parce qu'il ne
respecte pas l'alignement. La norme dit qu'une fonction
operator new doit renvoyer une adresse suffisamment alignée
pour tous les types de données. Sur ma machine, par exemple,
ça veut dire une adresse multiple de 8. Or, tu prends
l'adresse rétournée par malloc (elle aussi convenablement
alignée pour touts les types, donc une multiple de , et tu
en ajoutes 4. Sur un Sparc, ça garantit prèsque un core dump
si tu y mets des doubles ; sur un Intel, il n'y aura pas de
core dump, mais le programme s'exécutera d'une façon
notablement moins rapide.
En effet je me suis pas inquiété de l'alignement de la mémoire
Sur un AMD ca fonctionne malgré tout, en tout cas chez moi.
|
Les AMD implémente l'architecture Intel (IA-32). Pour des
raisons historiques, l'architecture Intel n'enforce pas
l'alignement -- on peut accéder à tout à n'importe quelle
adresse. À un prix : si les données sont mal-alignées, le
hardware effectue deux accès mémoires à la place d'un, ce qui
peut rallentir notablement.
Ce qui est vrai pour l'Intel ne l'est pas pour la plupart des
processeurs. Sur un Sparc, ou la plupart des autres RISC ou sur
un gros IBM, accéder à des données mal-alignées peut provoquer
un core dump.
| Quote: | Enfin, je me suis posé la question sur ton histoire de
memcpy (que tu émules en plus avec une boucle explicite).
Moi, dans un cas pareil, je déclare quelque chose du genre :
union BlockHeader
{
int count ;
MaxAlign dummyForAlignment ;
} ;
void*
operator new( size_t n )
{
BlockHeader* p = malloc( n + sizeof( BlockHeader* ) ) ;
if ( p == NULL ) {
throw std::bad_alloc() ;
}
p->count = ++ mCount ;
return p + 1 ;
}
Effectivement c'est plus clair.
mon BlockHearder est défini comme ceci:
union Uni
{
....
// plusieurs fonctions, operators
....
int mi;
char mc[4];
};
je conçois qu'il est mal adapté au problème!
|
C'est surtout l'utilisation de l'équivalent de memcpy que je
trouve bizarre. Pour la reste, on se trouve à un niveau très,
très bas, où servent parfois des choses qu'on éviterait à des
niveaux plus élevés.
| Quote: | MaxAlign est défini comme un type qui a besoin de
l'alignement maximal.
comment garantir que MaxAlign ait besoin de l'alignement
maximum?
|
En croisant les doigts ? :-)
Sérieusement, il n'y a pas de garantie de la norme, quoiqu'on y
met. Alors, on expérimente, et on espère avoir couvert tous les
cas.
| Quote: | J'ai vu sur ton site que tu avais déclaré MaxAlign comme une
union de int, long, long double, double et de pointeurs. N'est
t-on pas certain d'avoir l'alignement maximun avec un type
long double ?
|
Probablement. Ce que j'ai écrit, c'est un peu un heuristique ;
un essai de couvrir tous les cas réelement possible. Au départ,
j'avais aussi des pointeurs à membre et des pointeurs à fonction
membre. Dans la pratique, j'ai constaté qu'ils s'implémentent
toujours comme s'ils étaient des struct d'autres types, et que
dans certains cas, ils pouvaient être fort grands. Or, une des
utilisations à l'époque était pour des classes de tableaux, où
les données étaient déclarées :
union
{
MaxAlign dummyForAlignement ;
unsigned char data[ sizeof( T ) * N ] ;
} ;
(T et N étant des paramètres du template). Et j'ai constaté que
dans les cas comme T == char et N == 3, j'en perdais pas mal de
mémoire. Plus que je ne voulais.
| Quote: | Enfin, je ne sais pas d'où tu espère tirer les paramètres de
file et de line. (J'utilise une trace de pile dans mon
propre code.)
en fait j'utilise une macro pour remplacer toutes mes
occurences de new #define new new(__FILE__,__LINE__)
|
Ce qui ne va pas sans poser de problèmes quand je définis des
new spécifiques à une classe:-). (Formellement, en le faisant,
tu introduis un comportement indéfini. Pratiquement, si tu le
fais avant l'inclusion de la STL, il y a de fortes chances que
tu aies des erreurs de compilation, et si tu le fais après, il y
a quand même des constructions qui ne vont plus.)
Dans mon code, je fais un walkback de la pile. Ce qui ne va pas
sans problèmes -- pour commencer, il n'y a absolument pas de
moyen de le faire de façon portable. Et évidemment,
l'information que je peux afficher, ce sont des adresses en
hexadécimal. Mais 1) je ne touche pas à l'interface de new, 2)
je n'ai pas que l'adresse où on a appelé new, mais aussi qui l'a
appelé lui, etc. (très utile quand on utilise une fonction
usine), et 3) je peux stocké ces informations dans le bloc, et
ne les afficher qu'en cas d'erreur (fuite de mémoire, etc.).
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
| Back to top |
|
 |
Jean-Marc Bourguet Guest
|
Posted: Thu Jan 13, 2005 1:10 pm Post subject: Re: trace memoire |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] writes:
| Quote: | dug wrote:
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in
news:1105364229.646393.29580 (AT) c13g2000cwb (DOT) googlegroups.com:
La deuxième chose que j'avais dit, c'est que ton code ne
marche pas sur la plupart des machines, parce qu'il ne
respecte pas l'alignement. La norme dit qu'une fonction
operator new doit renvoyer une adresse suffisamment alignée
pour tous les types de données. Sur ma machine, par exemple,
ça veut dire une adresse multiple de 8. Or, tu prends
l'adresse rétournée par malloc (elle aussi convenablement
alignée pour touts les types, donc une multiple de , et tu
en ajoutes 4. Sur un Sparc, ça garantit prèsque un core dump
si tu y mets des doubles ; sur un Intel, il n'y aura pas de
core dump, mais le programme s'exécutera d'une façon
notablement moins rapide.
En effet je me suis pas inquiété de l'alignement de la mémoire
Sur un AMD ca fonctionne malgré tout, en tout cas chez moi.
Les AMD implémente l'architecture Intel (IA-32). Pour des raisons
historiques, l'architecture Intel n'enforce pas l'alignement -- on
peut accéder à tout à n'importe quelle adresse. À un prix : si les
données sont mal-alignées, le hardware effectue deux accès mémoires
à la place d'un, ce qui peut rallentir notablement.
|
Petite question aux eventuels connaisseurs des details, est-ce sur les
processeur recent que la penalite d'acces non aligne existe pour tout
acces non aligne ou simplement pour ceux qui recouvrent en plus une
ligne de cache?
| Quote: | Ce qui est vrai pour l'Intel ne l'est pas pour la plupart des
processeurs. Sur un Sparc, ou la plupart des autres RISC ou sur
un gros IBM, accéder à des données mal-alignées peut provoquer
un core dump.
|
Je n'ai jamais travaille avec de gros IBM, mais il y a quelques
elements me font douter de ce que tu dis:
- l'impression que ces betes sont programmee en COBOL
- l'idee que les programmes COBOL sont pleins d'acces non alignes
(souvenir de cours d'architecture des ordinateurs)
- le souvenir que POWER avait un probleme avec les donnees
mal-alignees (ou bien pas supportee du tout, ou bien necessitant
un TRAP couteux) et que les versions suivantes les supportent
beaucoup mieux, a peut pres au du moment ou ils se sont mis
a la reutiliser pour les AS-400 (j'arrive pas a m'en sortir avec
leur nouvelle terminologie ?Series -- je sais c'est un derive
particulier des POWER)
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
|
|
| Back to top |
|
 |
dug Guest
|
Posted: Thu Jan 13, 2005 10:19 pm Post subject: Re: trace memoire |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in news:1105620646.230564.59170
@f14g2000cwb.googlegroups.com:
| Quote: | dug wrote:
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in
news:1105364229.646393.29580 (AT) c13g2000cwb (DOT) googlegroups.com:
Enfin, je ne sais pas d'où tu espère tirer les paramètres de
file et de line. (J'utilise une trace de pile dans mon
propre code.)
en fait j'utilise une macro pour remplacer toutes mes
occurences de new #define new new(__FILE__,__LINE__)
Ce qui ne va pas sans poser de problèmes quand je définis des
new spécifiques à une classe:-). (Formellement, en le faisant,
tu introduis un comportement indéfini. Pratiquement, si tu le
fais avant l'inclusion de la STL, il y a de fortes chances que
tu aies des erreurs de compilation, et si tu le fais après, il y
a quand même des constructions qui ne vont plus.)
|
Oui il faut être prudent en utilisant une telle macro, mais c'
est bien pratique pour les quelques cas ou ca marche d'avoir le nom
du fichier et la ligne de code qui à fait un appel à new en clair.
D'ailleurs malgré mes recherches je n'ai pas trouvé de code source
pour savoir comment était écrite la macro __FILE__ ou __LINE__...
| Quote: |
Dans mon code, je fais un walkback de la pile. Ce qui ne va pas
sans problèmes -- pour commencer, il n'y a absolument pas de
moyen de le faire de façon portable. Et évidemment,
l'information que je peux afficher, ce sont des adresses en
hexadécimal. Mais 1) je ne touche pas à l'interface de new, 2)
je n'ai pas que l'adresse où on a appelé new, mais aussi qui l'a
appelé lui, etc. (très utile quand on utilise une fonction
usine), et 3) je peux stocké ces informations dans le bloc, et
ne les afficher qu'en cas d'erreur (fuite de mémoire, etc.).
|
Et à partir des adresses comment retrouves-tu la partie de code
qui a lancer l'appel, en desassemblant le programme ?
| Quote: |
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
|
| Back to top |
|
 |
drkm Guest
|
Posted: Thu Jan 13, 2005 11:56 pm Post subject: Re: trace memoire |
|
|
dug <dug8C (AT) hotmail (DOT) com> writes:
| Quote: | D'ailleurs malgré mes recherches je n'ai pas trouvé de code source
pour savoir comment était écrite la macro __FILE__ ou __LINE__...
|
Que veux-tu dire ? Tu veux savoir comment sont implémentées ces
macros ? Ça me semble assez évident. Tu peux regarder les sources de
CPP par exemple.
--drkm
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Jan 14, 2005 9:25 am Post subject: Re: trace memoire |
|
|
Jean-Marc Bourguet wrote:
| Quote: | kanze (AT) gabi-soft (DOT) fr writes:
dug wrote:
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in
news:1105364229.646393.29580 (AT) c13g2000cwb (DOT) googlegroups.com:
La deuxième chose que j'avais dit, c'est que ton code ne
marche pas sur la plupart des machines, parce qu'il ne
respecte pas l'alignement. La norme dit qu'une fonction
operator new doit renvoyer une adresse suffisamment
alignée pour tous les types de données. Sur ma machine,
par exemple, ça veut dire une adresse multiple de 8. Or,
tu prends l'adresse rétournée par malloc (elle aussi
convenablement alignée pour touts les types, donc une
multiple de , et tu en ajoutes 4. Sur un Sparc, ça
garantit prèsque un core dump si tu y mets des doubles ;
sur un Intel, il n'y aura pas de core dump, mais le
programme s'exécutera d'une façon notablement moins
rapide.
En effet je me suis pas inquiété de l'alignement de la
mémoire Sur un AMD ca fonctionne malgré tout, en tout cas
chez moi.
Les AMD implémente l'architecture Intel (IA-32). Pour des
raisons historiques, l'architecture Intel n'enforce pas
l'alignement -- on peut accéder à tout à n'importe quelle
adresse. À un prix : si les données sont mal-alignées, le
hardware effectue deux accès mémoires à la place d'un, ce
qui peut rallentir notablement.
Petite question aux eventuels connaisseurs des details, est-ce
sur les processeur recent que la penalite d'acces non aligne
existe pour tout acces non aligne ou simplement pour ceux qui
recouvrent en plus une ligne de cache?
|
Bonne question. La dernière fois que j'ai mésuré, c'était sur un
8086 ; on en a fait du progrès depuis. Mais a priori, je ne vois
pas où il y aurait une différence. Avec la cache, il serait bien
possible de supprimer le coût, mais il faudrait des portes en
plus, et je me démande si ça vaudrait la peine -- les programmes
en général ne font pas les accès non alignés, ce n'est donc pas
la peine de les accélérer.
| Quote: | Ce qui est vrai pour l'Intel ne l'est pas pour la plupart
des processeurs. Sur un Sparc, ou la plupart des autres RISC
ou sur un gros IBM, accéder à des données mal-alignées peut
provoquer un core dump.
Je n'ai jamais travaille avec de gros IBM, mais il y a
quelques elements me font douter de ce que tu dis:
|
Je n'ai jamais travaillé sur un gros IBM, mais j'ai réelement
travaillé sur des gros Siemens, qui se disaient compatible. Et
je sais qu'on avait un rapport d'erreur sur le Fortran suivant :
REAL X(10)
DOUBLE PRECISION Y(3),Z(3)
EQUIVALENCE X(2),Y(1),Z(2)
Ces lignes force une mauvaise alignement sur au moins un des
tableaux de double ; notre implémentation le detectait pas, et
le programme crashait lors des accès.
J'ai aussi de l'expérience en assembleur sur un Interdata 8/32,
dont l'architecture s'inspirait de très près de l'IBM 360.
(Enfin, ce n'est pas tout à fait vrai que je n'ai jamais
travaillé sur un gros IBM. La machine hôte à la Dresdner Bank
était une AS/400. Mais d'une part, je m'en occupais très peu, et
de l'autre, ce qu'on faisait sur elle était en Cobol, et
uniquement en Cobol, et donc, on ne voyait pas les contraints
hardware. Tandis que sur le Siemens, je travaillais sur des
compilateurs, où je voyais vraiment de près ce que faisait le
hardware.)
Note qu'à l'époque ou l'architecture 360 a vu les jours, c'était
déjà une innovation de pouvoir accéder aux octets directement ;
la plupart des machines (sinon toutes les autres) étaient à
adressage mot.
Autant que je sache, le premier processeur à plus de 8 bits à
supporter des accès non aligné, c'était le 8086. Où le choix se
justifiait surtout parce qu'il supportait un mapping de
l'assembleur 8080 (et évidemment, sur le 8080, il n'y avait pas
de problème d'alignement, parce que le bus mémoire n'était que
de 8 bits). En tout cas, le marketing d'Intel le présentait
comme une grande innovation, et aucune des machines que j'avais
vu avant (PDP-11, Mitra 125) ne le supportaient.
| Quote: | - l'impression que ces betes sont programmee en COBOL
|
Souvent, oui.
| Quote: | - l'idee que les programmes COBOL sont pleins d'acces non
alignes (souvenir de cours d'architecture des
ordinateurs)
|
Les accès en Cobol sont des accès octet pour la plupart. Il y a
effectivement des instructions très élaborées qui travaille sur
des chaînes d'octet, et elles n'exigent pas l'alignement.
En revanche, d'après mes souvenirs sur le Siemens, les
instructions d'arithmetique BCD exigeaient un alignement (mais
je ne suis pas sûr -- ce n'est pas moi qui s'est occupé de cette
partie-là). Et les instructions sur des entiers et des virgule
flottant l'exigeaient ; là, j'y étais.
| Quote: | - le souvenir que POWER avait un probleme avec les donnees
mal-alignees (ou bien pas supportee du tout, ou bien
necessitant un TRAP couteux) et que les versions
suivantes les supportent beaucoup mieux, a peut pres au
du moment ou ils se sont mis a la reutiliser pour les
AS-400 (j'arrive pas a m'en sortir avec leur nouvelle
terminologie ?Series -- je sais c'est un derive
particulier des POWER)
|
C'est effectivement possible que la situation a évolué. Mon
expérience sur le Siemens date de la fin des années 80. Depuis
lors, à part le coup d'oeil à l'IBM et une application en Java
sur PC pour la Dresdner Bank, je n'ai touché que des machines
Unix -- surtout SunOS, puis Solaris, mais aussi HP/UX et un très
petit peu AIX. Et en dehors des Sparc, je n'ai jamais eu
l'occasion de régarder trop sous le capot. Les compilateurs
générait ce qu'il fallait, et ça me suffisait.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Jan 14, 2005 9:33 am Post subject: Re: trace memoire |
|
|
dug wrote:
| Quote: | kanze (AT) gabi-soft (DOT) fr wrote in news:1105620646.230564.59170
@f14g2000cwb.googlegroups.com:
dug wrote:
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in
news:1105364229.646393.29580 (AT) c13g2000cwb (DOT) googlegroups.com:
Enfin, je ne sais pas d'où tu espère tirer les paramètres
de file et de line. (J'utilise une trace de pile dans mon
propre code.)
en fait j'utilise une macro pour remplacer toutes mes
occurences de new #define new new(__FILE__,__LINE__)
Ce qui ne va pas sans poser de problèmes quand je définis
des new spécifiques à une classe:-). (Formellement, en le
faisant, tu introduis un comportement indéfini.
Pratiquement, si tu le fais avant l'inclusion de la STL, il
y a de fortes chances que tu aies des erreurs de
compilation, et si tu le fais après, il y a quand même des
constructions qui ne vont plus.)
Oui il faut être prudent en utilisant une telle macro, mais
c'est bien pratique pour les quelques cas ou ca marche d'avoir
le nom du fichier et la ligne de code qui à fait un appel à
new en clair.
D'ailleurs malgré mes recherches je n'ai pas trouvé de code
source pour savoir comment était écrite la macro __FILE__ ou
__LINE__...
|
Ce sont des built-in ; le compilateur s'arrange pour qu'ils
marchent. Il serait en effet impossible à les écrire au moyen
des #define toi-même.
| Quote: | Dans mon code, je fais un walkback de la pile. Ce qui ne va
pas sans problèmes -- pour commencer, il n'y a absolument
pas de moyen de le faire de façon portable. Et évidemment,
l'information que je peux afficher, ce sont des adresses en
hexadécimal. Mais 1) je ne touche pas à l'interface de new,
2) je n'ai pas que l'adresse où on a appelé new, mais aussi
qui l'a appelé lui, etc. (très utile quand on utilise une
fonction usine), et 3) je peux stocké ces informations dans
le bloc, et ne les afficher qu'en cas d'erreur (fuite de
mémoire, etc.).
Et à partir des adresses comment retrouves-tu la partie de
code qui a lancer l'appel, en desassemblant le programme ?
|
Sur mon système, il existe un programme « nm » qui sort le
mapping entre les symbolès et les adresses ; avec VC++, je crois
qu'il y a une option /Fm qui fait que l'éditeur de liens génère
ce map lors de la compilation. Ensuite, on cherche dans le
map -- ce n'est normalement pas trop difficile à trouver les
fonctions qui ont été appelées. Et mes fonctions sont assez
petites pour que ça suffit.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
|
|
| Back to top |
|
 |
Jean-Marc Bourguet Guest
|
Posted: Fri Jan 14, 2005 12:44 pm Post subject: Re: trace memoire |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] writes:
| Quote: | Petite question aux eventuels connaisseurs des details, est-ce
sur les processeur recent que la penalite d'acces non aligne
existe pour tout acces non aligne ou simplement pour ceux qui
recouvrent en plus une ligne de cache?
Bonne question. La dernière fois que j'ai mésuré, c'était sur un
8086 ; on en a fait du progrès depuis. Mais a priori, je ne vois pas
où il y aurait une différence. Avec la cache, il serait bien
possible de supprimer le coût, mais il faudrait des portes en plus,
et je me démande si ça vaudrait la peine -- les programmes en
général ne font pas les accès non alignés, ce n'est donc pas la
peine de les accélérer.
|
Suivant la maniere dont le cache est implemente, ca peut ne pas couter
grand chose (mais bon, je ne suis plus tres au courant des manieres
efficaces d'implementer des caches, cela fait des annees que je n'ai
plus fait de conception de circuits).
| Quote: | Ce qui est vrai pour l'Intel ne l'est pas pour la plupart des
processeurs. Sur un Sparc, ou la plupart des autres RISC ou sur
un gros IBM, accéder à des données mal-alignées peut provoquer
un core dump.
Je n'ai jamais travaille avec de gros IBM, mais il y a quelques
elements me font douter de ce que tu dis:
Je n'ai jamais travaillé sur un gros IBM,
|
Mais tu as quand meme une experience directe plus proche que moi. Si
j'ai le temps j'essaierai de voir exactement ou mon raisonnement foire
(c'est peut-etre simplement ma memoire a moins j'ai deduit des choses
trop vite).
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
|
|
| Back to top |
|
 |
Christophe Lephay Guest
|
Posted: Fri Jan 14, 2005 1:15 pm Post subject: Re: trace memoire |
|
|
<kanze (AT) gabi-soft (DOT) fr> a écrit dans le message de news:
[email]1105694724.147198.227840 (AT) z14g2000cwz (DOT) googlegroups.com[/email]...
| Quote: | Autant que je sache, le premier processeur à plus de 8 bits à
supporter des accès non aligné, c'était le 8086. Où le choix se
justifiait surtout parce qu'il supportait un mapping de
l'assembleur 8080 (et évidemment, sur le 8080, il n'y avait pas
de problème d'alignement, parce que le bus mémoire n'était que
de 8 bits).
|
C'était surtout le cas sur le 8088, ce qui suffit à justifier un accès octet
pour tous les futurs processeurs prétendant à une compatibilité.
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|