1

Pour info, MAYLIB fonctionne sans optimisation avec CLANG, mais dès qu'on active les optimisations, ca plante pour un not enough memory.
Le code mal compilé est le suivant:
  size_t n;
  int i, j;
  void *s = &i;
  for (i = 10; i < (int) (CHAR_BIT*sizeof n) && s != NULL; i++) {
    n = 1UL << i;
    s =  malloc (n);
    if (s != NULL)
      free (s);
  }
  n = 1UL << (i-2);
  s = &i;
  for (j = i-3; j > i-8; j--) {
    s = malloc (n + (1UL << j));
    if (s != NULL) {
      free (s);
      n += 1UL <<j;
    }
  }

qui est là pour calculer la taille max allouable par le système.

Sans optimisation, clang calcule bien n=10468982784 (sur ma machine), mais dès -O, il retourne n=9079256848778919936 qui est faux !
C'est lié au bug de llvm suivant: http://llvm.org/bugs/show_bug.cgi?id=18868

2

C'est audacieux de la part d'un compilateur qui se veut honnete grin

3

Mouais. C'est discutable.

Cette façon de calculer la mémoire disponible, en plus d'être conceptuellement crade, n'est probablement pas sûre sur tous les OS (au pif je dirais que tu risques de déclencher l'OOM killer, etc.).
Maintenant j'imagine bien que si tu l'utilises, c'est que tu n'as pas de moyen de faire ça plus proprement.

Après, je suis d'accord que l'optimisation que fait le compilateur n'est pas correcte en théorie, mais la différence n'est visible que dans des cas pathologiques, et pour les programmes qui font beaucoup de petites allocations le gain est probablement sensible. Je suis d'habitude contre les optimisations qui provoquent des effets de bord, mais là ça ne me choque pas qu'elle soit activée par défaut.
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

4

Zerosquare (./3) :
Cette façon de calculer la mémoire disponible, en plus d'être conceptuellement crade, n'est probablement pas sûre sur tous les OS (au pif je dirais que tu risques de déclencher l'OOM killer, etc.).Maintenant j'imagine bien que si tu l'utilises, c'est que tu n'as pas de moyen de faire ça plus proprement.

En quoi c'est crade ? Je suis sûr de ne pas déclencher l'OOM killer vu que ca ne réserve de l'espace virtuel, et pas de l'espace réel.

Zerosquare (./3) :
Après, je suis d'accord que l'optimisation que fait le compilateur n'est pas correcte en théorie, mais la différence n'est visible que dans des cas pathologiques, et pour les programmes qui font beaucoup de petites allocations le gain est probablement sensible. Je suis d'habitude contre les optimisations qui provoquent des effets de bord, mais là ça ne me choque pas qu'elle soit activée par défaut.

? Je ne suis pas sûr de comprendre ta phrase ? Le code suivant n'est pas optimisé
int f(int *);
int g(int n)
{
  int *p = malloc (12);
  if (p)
    {
      int n = f(p);
      free(p);
      return n;
    }
  return 0;
}

Donc elle est où l'optimisation utile ?

5

PpHd (./4) :
En quoi c'est crade ? Je suis sûr de ne pas déclencher l'OOM killer vu que ca ne réserve de l'espace virtuel, et pas de l'espace réel.
Je considère que déterminer la mémoire disponible de cette façon est foireux pour plusieurs raisons :
- en-dehors des OS "simples", rien ne garantit que la quantité de mémoire dispo ne variera pas entre le moment où tu fais ton estimation et le moment où tu utilises le résultat, mais même pendant que tu fais ton estimation.
- le résultat obtenu dépend complètement de la stratégie d'allocation de la libc et de l'OS. Si ça ne fait que réserver de la mémoire sans l'allouer réellement tant qu'elle n'est pas accédée, le résultat peut être beaucoup plus grand que la mémoire physique réellement disponible.
PpHd (./4) :
Donc elle est où l'optimisation utile ?
Ce que je veux dire, c'est que la seule façon de résoudre le problème du bug report que tu as cité (en supposant qu'on ne peut pas prévoir à l'avance si l'allocation sur la pile va échouer), c'est de désactiver l'inlining de malloc()/free() pour des allocations de petite taille.
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

6

Zerosquare (./5) :
Ce que je veux dire, c'est que la seule façon de résoudre le problème du bug report que tu as cité (en supposant qu'on ne peut pas prévoir à l'avance si l'allocation va échouer), c'est de désactiver l'inlining de malloc()/free() pour des allocations de petite taille.

Il n'y a pas de inlining de malloc / free avec clang ? Où alors je ne l'ai jamais vu (et ce n'est pas la source du bug).
Zerosquare (./5) :
- en-dehors des OS "simples", rien ne garantit que la quantité de mémoire dispo ne variera pas entre le moment où tu fais ton estimation et le moment où tu utilises le résultat (voire pendant que tu fais estimation).

Il n'y a pas grand chose de garantie dans un OS... (pour info, je fais un mmap juste après l'estimation).
J'ai fait un petit test rapide : lancer 9x un programme qui fait un tel calcul :
23945 pphd      20   0  9,8g 239m  356 D   0,7  6,0   0:04.49 t-charge                                
23946 pphd      20   0  9,8g 741m  364 D   0,7 18,7   0:11.13 t-charge                                
23951 pphd      20   0  9,8g 439m  356 D   0,7 11,1   0:05.82 t-charge                                
23942 pphd      20   0  9,8g 338m  356 D   0,3  8,5   0:05.04 t-charge                                
23943 pphd      20   0  9,8g 281m  356 D   0,3  7,1   0:04.67 t-charge                                
23944 pphd      20   0  9,8g 259m  356 D   0,3  6,6   0:04.63 t-charge                                
23947 pphd      20   0  9,8g 302m  356 D   0,3  7,6   0:04.53 t-charge                                
23948 pphd      20   0  9,8g 302m  356 D   0,3  7,6   0:04.79 t-charge                                
23949 pphd      20   0  9,8g 303m  356 D   0,3  7,7   0:04.76 t-charge 

Toutes les instances ont alloués le même montant de la mémoire (sur un ordi avec 4Go de RAM ça fait presque 98G de virtualisé cheeky Mais l'OOM killer n'est pas venu ).
Donc il semblerait que le maximum allouable soit indépendant des autres process sous Linux.
Il faudrait que je fasse ce test sous MS Windows, mais j'ai vraiment peut de mettre en carafe MS Windows par un test aussi violent !
Zerosquare (./5) :
- le résultat obtenu dépend complètement de la stratégie d'allocation de la libc et de l'OS. Si ça ne fait que réserver de la mémoire sans l'allouer réellement tant qu'elle n'est pas accédée, le résultat peut être beaucoup plus grand que la mémoire physique réellement disponible.

Oui. Et ça reste le maximum allouable et c'est ce que je veux. Ce n'est pas la taille de la RAM.

7

maintenant tu fais le meme test, mais tu mets un memset juste apres ton malloc ^^

8

squalyl (./7) :
maintenant tu fais le meme test, mais tu mets un memset juste apres ton malloc ^^

cheeky Heu... Joker

9

Pour info, Linux en 64 bits est vraiment accomodant avec la mémoire virtuelle.
Sur une machine 8Gio, j'ai lancé le code suivant: size_t n = get_max_size(); char *p = malloc(n); printf ("p= %p\n", p); char *p2 = malloc(1UL<<32); printf ("p2= %p\n", p2); char *p3 = malloc(n); printf ("p3= %p\n", p3); char *p4 = malloc(n); printf ("p4= %p\n", p4); char *p5 = malloc(n); printf ("p5= %p\n", p5); char *p6 = malloc(n); printf ("p6= %p\n", p6); char *p7 = malloc(n); printf ("p7= %p\n", p7); char *p8 = malloc(n); printf ("p8= %p\n", p8); char *p9 = malloc(n); printf ("p9= %p\n", p9); char *p10 = malloc(n); printf ("p10= %p\n", p10);
avec la fonction get_max_size définit en ./1.

Les allocations marchent !!!!
p= 0x2b7164044010
p2= 0x2b7524046010
p3= 0x2b7624047010
p4= 0x2b79e4048010
p5= 0x2b7da4049010
p6= 0x2b816404a010
p7= 0x2b852404b010
p8= 0x2b88e404c010
p9= 0x2b8ca404d010
p10= 0x2b906404e010


Et un top donne 139G de mémoire virtuelle alloué (492 octets réel) !

J'ai essayé de voir jusqu'où je peux aller smile
je peux allouer 4312 fois la taille max calculée avant que malloc me retourne NULL !
Soit 62.7 Tio de mémoire virtuelle ! (top n'arrive même plus à afficher la mémoire virutelle du process !)

Sous Windows, avec une machine 4Gio, j'obtiens : 3.5Gio.

Je serrais curieux de voir le comportement sur les autres OS.

10

Moi je vois ça comme un truc rigolo, mais quel peut en être l'intérêt, dans la pratique ?

11

Je ne sais pas trop
Par exemple, au lieu de faire un système de vecteur avec réallocation si une demande d'élargissement échoue si pas assez de mémoire, tu fais une allocation virtuelle de 16Gio, comme çà tu n'as plus à gérer l'élargissement automatique: le système s'en occupe (ensuite, savoir si c'est une bonne idée wink)

12

Pas idiot, reste à voir comment c'est géré en effet, si on gagne vraiment quelque chose, parce qu'à un moment, l'OS va bien devoir se pencher sur la mémoire réelle, réserver, et mapper ça comme il faut dans le range qu'il aura accordé au préalable. Mais pourquoi pas, ça serait marrant de savoir ça en effet grin

13

Mmmmmm....
Je crois que je vais m'en servir pour résoudre le problème des piles d'expression à créer pour les thread.
(déplacer suite à un realloc une pile d'expression MAY est très compliqué car elle est bourrée de pointeur vers elle même, donc un realloc est à éviter à tout prix).
"Aller, hop. 8Gio. Pas chez la mémoire virtuelle. Pas cher !"

14

J'ai implanté cette idée. Ca a l'air de bien marché. Effectivement, ca fait des trucs bizarres:
make check me fait un 1806g de RAM virtualisé vs 87Mo réellement alloué. smile
(J'ai peut être un peu exagéré grin ).