Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

limitations du nombre de dlopen

3 réponses
Avatar
Basile Starynkevitch [news]
Bonjour

Un maître et viel ami à moi (Jacques Pitrat) développe un système
reflexif qui genère des fichiers en C, puis les compile et les charge
à l'exécution par dlopen. Mais il n'arrive pas à générer et charger
plus de 32 fichiers .so (correspondant à environ cent mille lignes de
sources générés). J'ignore sa distribution, mais ça pourrait être une
mandrake d'il y a 3 ans.

J'ai écrit un petit programme, disponible (licence GPL) en
http://starynkevitch.net/Basile/manydl.c qui teste cette limite en
générant (dans des fichiers genf_*.c) des sources (de fonctions
générées aléatoirement), puis les compile en genf_*.so puis les charge
par dlopen pour enfin les appeller. L'argument du programme compilé
par "gcc -O -Wall -o manydl manydl.c -ldl" est le nombre de fichiers
générés.

Sous ma Debian/Sid avec glibc 2.3.2 et noyau 2.6.9, je n'arrive pas à
tomber sur une limite. Même ./manydl 1500 fonctionne!

Quelqu'un disposant d'une distribution un peu plus ancienne (que ma
Debian/sid), et d'un noyau 2.4, pourrait-il essayer mon programme de
test et me dire (ou plutot poster ici) s'il réussit (avec par exemple
100 ou 300 comme argument)? Il convient plutot de telecharger et
tester mon programme dans un repertoire temporaire (qui contiendra la
foultitude de fichier .c puis .so produits).

Merci beaucoup!

--
Basile STARYNKEVITCH http://starynkevitch.net/Basile/
email: basile<at>starynkevitch<dot>net
aliases: basile<at>tunes<dot>org = bstarynk<at>nerim<dot>net
8, rue de la Faïencerie, 92340 Bourg La Reine, France

3 réponses

Avatar
Erwann ABALEA
Bonjour,

On Fri, 17 Dec 2004, Basile Starynkevitch [news] wrote:

Quelqu'un disposant d'une distribution un peu plus ancienne (que ma
Debian/sid), et d'un noyau 2.4, pourrait-il essayer mon programme de


J'ai une vieille machine, avec une vieille distrib (RedHat 5.1 un peu
modifiée), ton programme est en train de tourner, avec une petite
correction (Glibc 2.0.7, qui n'a pas de symbole gnu_get_libc_version()
et gnu_get_libc_release()). C'est un noyau 2.2.20, par contre, est-ce
important?

Bon. Par contre, ça va prendre du temps. C'est un Pentium 133, et:
-----
after 1 generated & compiled files (800 instrs) time
.. CPU= 0.02u+0.02s self, 16.72u+0.45s children; real= 34.63 [sec]
-----
Ca te donne une idée du temps que prendra la génération et la compilation
des 300 fichiers demandés :)

--
Erwann ABALEA - RSA PGP Key ID: 0x2D0EABD5
-----
Je pensais que seul le corps des messages pouvait être cancellé. J'avais
suggéré de mettre le message DANS LES TITRES ! Or, il semble qu' aucune
trace des posts n'apparaisse après cancel. ON NE PEUT MEME PLUS DEVINER!
-+- CS in : Guide du Neuneu d'Usenet - Le régime cancel -+-

Avatar
Erwann ABALEA
Bonsoir,

On Sat, 18 Dec 2004, Erwann ABALEA wrote:

On Fri, 17 Dec 2004, Basile Starynkevitch [news] wrote:

Quelqu'un disposant d'une distribution un peu plus ancienne (que ma
Debian/sid), et d'un noyau 2.4, pourrait-il essayer mon programme de


J'ai une vieille machine, avec une vieille distrib (RedHat 5.1 un peu
modifiée), ton programme est en train de tourner, avec une petite
correction (Glibc 2.0.7, qui n'a pas de symbole gnu_get_libc_version()
et gnu_get_libc_release()). C'est un noyau 2.2.20, par contre, est-ce
important?


Premier résultat: echec, mais pas sur le nombre de bibliothèques qu'on
peut ouvrir:

-----
dynloading #1 genf_A0
dlopen ./genf_A0.so failed ./genf_A0.so: undefined symbol: dynlin
08048000-0804a000 r-xp 00000000 03:01 686135 /home/eabalea/tmp/manydl/manydl
0804a000-0804c000 rw-p 00001000 03:01 686135 /home/eabalea/tmp/manydl/manydl
40000000-4000a000 r-xp 00000000 03:01 899074 /lib/ld-2.0.7.so
4000a000-4000b000 rw-p 00009000 03:01 899074 /lib/ld-2.0.7.so
4000b000-4000d000 rw-p 00000000 00:00 0
40010000-40012000 r-xp 00000000 03:01 899084 /lib/libdl-2.0.7.so
40012000-40013000 rw-p 00001000 03:01 899084 /lib/libdl-2.0.7.so
40013000-400a4000 r-xp 00000000 03:01 899078 /lib/libc-2.0.7.so
400a4000-400ac000 rw-p 00090000 03:01 899078 /lib/libc-2.0.7.so
400ac000-400b8000 rw-p 00000000 00:00 0
400b8000-400bd000 r-xp 00000000 03:01 686137 /home/eabalea/tmp/manydl/genf_A0.so
400bd000-400be000 rw-p 00004000 03:01 686137 /home/eabalea/tmp/manydl/genf_A0.so
bfffc000-c0000000 rwxp ffffd000 00:00 0
-----

J'ai d'abord pensé que gcc avait viré dynlin qui n'est pas utilisé (sauf
dans 2 printf()), et j'ai donc initialisé dynlin à time(NULL) (que gcc ne
peut pas optimiser), mais ça n'a rien donné.

Et j'ai regardé la page de man de dlopen(), pour apprendre que pour que
les symboles de l'exécutable soient accessibles aux bibliothèques chargées
dynamiquement, il faut compiler l'exécutable avec l'option '-rdynamic', ce
que j'ai fait.

Et après un './manydl 300', voici les dernières lignes:
-----
[...]
called all 300 functions r535848 sR45637 dynlin35735 tab(83 3040 2951 2966 ...

total time for 300 files 552198 instructions 1235735 executed:
... CPU= 16.30u+3.71s self, 0.00u+0.00s children; real= 48.40 sec
id $Id: manydl.c 1.3.1.2 Sat, 18 Dec 2004 00:53:26 +0100 basile $
-----

Oui, j'ai triché sur le temps, j'ai viré l'étape de la compilation, j'ai
conservé les .so précédemment compilés. La brouette qui a fait ce travail
est mon serveur de courrier, et le temps de réponse s'en ressent.

--
Erwann ABALEA - RSA PGP Key ID: 0x2D0EABD5
-----
Looking at Sun man pages versus Linux man pages is like
looking at a Van Gogh or Monet after studying the
work of the high school football player taking
art as an "easy" elective.
Amy Graf, BitMover


Avatar
Basile Starynkevitch [news]
On 2004-12-19, Erwann ABALEA wrote:
Bonsoir,

On Sat, 18 Dec 2004, Erwann ABALEA wrote:

On Fri, 17 Dec 2004, Basile Starynkevitch [news] wrote:

Quelqu'un disposant d'une distribution un peu plus ancienne (que ma
Debian/sid), et d'un noyau 2.4, pourrait-il essayer mon programme




On le trouve sur http://starynkevitch.net/Basile/manydl.c



Et après un './manydl 300', voici les dernières lignes:
-----
[...]
called all 300 functions r535848 sR45637 dynlin35735 tab(83 3040 2951 2966 ...



Un grand merci à tous les participants à cette discussion. Pour ma
part, j'ai lancer sur ma Debian/Sid Athlon2000 (à 1.66GHz) avec 412Mo
de RAM, j'ai lancé un gros test à trente mille fichiers

./manydl 30000

ca dure un jour et demi, mais ca marche:

running ./manydl max.counter 30000 glibc version 2.3.2 release stable
on sys Linux release 2.6.9ours version #2 Tue Oct 19 18:42:36 CEST 2004
before generation of 30000 files with CC=gcc and CFLAGS=-O
generating genf_A0 (#1); compiling 800 instructions .
after 1 generated & compiled files (800 instrs) time
.. CPU= 0.00u+0.00s self, 1.06u+0.04s children; real= 2.01 [sec]

....

after 29985 generated & compiled files (54663941 instrs) time
.. CPU= 55.90u+122.87s self, 93260.79u+6259.91s children; real= 115906.65 [sec]
generating genf_F2998 (#29986); compiling 1834 instructions .
generating genf_G2998 (#29987); compiling 1553 instructions .
generating genf_H2998 (#29988); compiling 2785 instructions .
generating genf_I2998 (#29989); compiling 1029 instructions .
generating genf_J2998 (#29990); compiling 1989 instructions .
generating genf_A2999 (#29991); compiling 1044 instructions .
generating genf_B2999 (#29992); compiling 1682 instructions .
generating genf_C2999 (#29993); compiling 1143 instructions .
generating genf_D2999 (#29994); compiling 1128 instructions .
generating genf_E2999 (#29995); compiling 2162 instructions .
generating genf_F2999 (#29996); compiling 1631 instructions .
generating genf_G2999 (#29997); compiling 2789 instructions .
generating genf_H2999 (#29998); compiling 2200 instructions .
generating genf_I2999 (#29999); compiling 1973 instructions .
generating genf_J2999 (#30000); compiling 2075 instructions .

generated 54690958 instructions in 30000 files
dynloading #1
after 1 dlopened files time
.. CPU= 55.93u+122.98s self, 93305.19u+6262.88s children; real= 115954.56 [sec]
dynloading #2
dynloading #3
dynloading #4
dynloading #5


dynloading #29985
after 29985 dlopened files time
.. CPU= 476.27u+134.40s self, 93305.19u+6262.88s children; real= 116926.82 [sec]
dynloading #29986
dynloading #29987
dynloading #29988
dynloading #29989
dynloading #29990
dynloading #29991
dynloading #29992
dynloading #29993
dynloading #29994
dynloading #29995
dynloading #29996
dynloading #29997
dynloading #29998
dynloading #29999
dynloading #30000


*** 30000 shared objects have been loaded successfully
.. CPU= 476.69u+134.41s self, 93305.19u+6262.88s children; real= 116927.29 [sec]
08048000-0804b000 r-xp 00000000 03:08 1864158 /home/basile/tmp/ManyDL_30K/manydl
0804b000-0804c000 rwxp 00002000 03:08 1864158 /home/basile/tmp/ManyDL_30K/manydl
0804c000-09960000 rwxp 0804c000 00:00 0
60740000-60741000 rwxp 60740000 00:00 0
60741000-6074d000 r-xp 00000000 03:08 1930339 /home/basile/tmp/ManyDL_30K/genf_J2999.so
6074d000-6074e000 rwxp 0000b000 03:08 1930339 /home/basile/tmp/ManyDL_30K/genf_J2999.so
6074e000-6075a000 r-xp 00000000 03:08 1930337 /home/basile/tmp/ManyDL_30K/genf_I2999.so
6075a000-6075b000 rwxp 0000b000 03:08 1930337 /home/basile/tmp/ManyDL_30K/genf_I2999.so
6075b000-60768000 r-xp 00000000 03:08 1930335 /home/basile/tmp/ManyDL_30K/genf_H2999.so
60768000-60769000 rwxp 0000c000 03:08 1930335 /home/basile/tmp/ManyDL_30K/genf_H2999.so
60769000-60779000 r-xp 00000000 03:08 1930333 /home/basile/tmp/ManyDL_30K/genf_G2999.so
b7e72000-b7e7f000 r-xp 00000000 03:08 1864361 /home/basile/tmp/ManyDL_30K/genf_E0.so
b7e7f000-b7e80000 rwxp 0000c000 03:08 1864361 /home/basile/tmp/ManyDL_30K/genf_E0.so
b7e80000-b7e90000 r-xp 00000000 03:08 1864178 /home/basile/tmp/ManyDL_30K/genf_D0.so
b7e90000-b7e91000 rwxp 0000f000 03:08 1864178 /home/basile/tmp/ManyDL_30K/genf_D0.so
b7e91000-b7fba000 r-xp 00000000 03:02 3597462 /lib/tls/libc-2.3.2.so
b7fba000-b7fc2000 rwxp 00129000 03:02 3597462 /lib/tls/libc-2.3.2.so
b7fc2000-b7fc6000 rwxp b7fc2000 00:00 0
b7fc6000-b7fc8000 r-xp 00000000 03:02 3597465 /lib/tls/libdl-2.3.2.so
b7fc8000-b7fc9000 rwxp 00002000 03:02 3597465 /lib/tls/libdl-2.3.2.so
b7fd2000-b7fd9000 r-xp 00000000 03:08 1864172 /home/basile/tmp/ManyDL_30K/genf_C0.so
b7fd9000-b7fda000 rwxp 00006000 03:08 1864172 /home/basile/tmp/ManyDL_30K/genf_C0.so
b7fda000-b7fe1000 r-xp 00000000 03:08 1864169 /home/basile/tmp/ManyDL_30K/genf_B0.so
b7fe1000-b7fe2000 rwxp 00006000 03:08 1864169 /home/basile/tmp/ManyDL_30K/genf_B0.so
b7fe2000-b7fe7000 r-xp 00000000 03:08 1864164 /home/basile/tmp/ManyDL_30K/genf_A0.so
b7fe7000-b7fe8000 rwxp 00004000 03:08 1864164 /home/basile/tmp/ManyDL_30K/genf_A0.so
b7fe8000-b7fea000 rwxp b7fe8000 00:00 0
b7fea000-b8000000 r-xp 00000000 03:02 1177422 /lib/ld-2.3.2.so
b8000000-b8001000 rwxp 00015000 03:02 1177422 /lib/ld-2.3.2.so
bfffe000-c0000000 rw-p bfffe000 00:00 0
ffffe000-fffff000 ---p 00000000 00:00 0


calling genf_A0 #0
<genf_A0> x=0 y=0 r#13 s76407
after 1 executed functions time
.. CPU= 476.76u+157.39s self, 93305.19u+6262.88s children; real= 116950.65 [sec]
calling genf_B0 #1
<genf_B0> x#13 y#13 r72124 s69748
calling genf_C0 #2
<genf_C0> x72124 y72124 rU s…70393
calling genf_D0 #3
<genf_D0> xU yU r82542 s"44559
calling genf_E0 #4
<genf_E0> x82542 y82542 r@ s79002
calling genf_F0 #5
<genf_F0> x@ y@ r0 s 67424
calling genf_G0 #6
<genf_G0> x0 y0 r39646 s39100

<genf_J2999> x)4125 y)4125 r(64157 sX05395

called all 30000 functions r(64157 s)4125 dynlin2881890 tab)4612 295136 294503 294796 ...

total time for 30000 files 54690958 instructions 132881890 executed:
... CPU= 479.32u+162.08s self, 93305.19u+6262.88s children; real= 118747.74 sec
id $Id: manydl.c 1.3.1.2 Sat, 18 Dec 2004 00:53:26 +0100 basile $

mon test de trente mille fichiers C générés et compilés a réussi, y
compris pour leur chargement dynamique; j'ai pu "ouvrir" (par dlopen)
les 30_000 fichiers .so correspondant ensemble. Le code source
correspondant fait 78.9millions de lignes C totalisant
2227Megaoctets. Le repertoire contenant les sources et les fichiers
.so totalisent 3979 megaoctets. l'execution prend 1jour et
demi. L'essentiel du temps est l'invocation du compilateur C. Au
premier dlopen (apres generation et compilation des 30_000 fichiers)
le temps est

after 1 dlopened files time
.. CPU= 55.93u+122.98s self, 93305.19u+6262.88s children; real= 115954.56 [sec]
au dernier dlopen, le temps est
*** 30000 shared objects have been loaded successfully
.. CPU= 476.69u+134.41s self, 93305.19u+6262.88s children; real= 116927.29 [sec]

Il faut donc a peu près mille secondes réelles pour dlopen-er 30 mille
fichiers. (ma machine est un Athlon2000 à 1.66GHz et 512Mo de RAM)

L'execution se fait normalement, mais comme le code généré (l'ensemble
des segments textuels des 30_000 fichiers .so générés) est plus gros
que ma mémoire vive (je n'ai que 512Mo de RAM) j'ai eu beaucoup de
swap pendant l'execution:

calling genf_A0 #0
<genf_A0> x=0 y=0 r#13 s76407
after 1 executed functions time
.. CPU= 476.76u+157.39s self, 93305.19u+6262.88s children; real 116950.65 [sec]
...
calling genf_J2999 #29999
<genf_J2999> x)4125 y)4125 r(64157 sX05395

called all 30000 functions r(64157 s)4125 dynlin2881890 tab)4612 295136 294503 294796 ...

total time for 30000 files 54690958 instructions 132881890 executed:
... CPU= 479.32u+162.08s self, 93305.19u+6262.88s children; real= 118747.74 sec
id $Id: manydl.c 1.3.1.2 Sat, 18 Dec 2004 00:53:26 +0100 basile $

L'execution des 30000 fonctions (en fait des 29999 dernieres) a donc
pris 1797.09 secondes réelles, et 2.56 secondes CPU utilisateur, et
4.69 secondes CPU système. On voit bien que le système a passé son
temps à swapper pendant cette execution (et je l'ai observé par
ailleurs).

La carte (/proc/XXX/maps) du processus est grosse.

le code C généré contient des tests, tableaux, goto, voici un extrait

r += 36 * ((r+s) & 0xf);
r = s + 3 * x - 14 * y;
tab[21] ++;
if (x>s) r += 28 * x; else s += y + tab[105];
s += (9 * r) & 0x3ffff + 6;
r += 79 * ((r+s) & 0xf);
s += (122 * r) & 0x3ffff + 5;
s += x + 22;
s += (67 * r) & 0x3ffff + 7;
s += x + 18;
s += (35 * r) & 0x3ffff + 5;
while (r>2) { dynlin++; s += tab[r & 127]; r = (r/2) & 0xffff; };
r = tab[s & 127] + 28; tab[r & 127] += 4;
r &= 0x3fffff; s &= 0x1fffff;
while (r>2) { dynlin++; s += tab[r & 127]; r = (r/2) & 0xffff; };
r = tab[s & 127] + 9; tab[r & 127] += 2;
if (r>s) r += 19; else s -= 16;
while (r>2) { dynlin++; s += tab[r & 127]; r = (r/2) & 0xffff; };
r = tab[s & 127] + 17; tab[r & 127] += 2;

if (3*r == 5 *s) {dynlin -= 300; goto end;}
if (x>s) r += 16 * x; else s += y + tab[83];
r = s + 7 * x - 16 * y;
tab[93] ++;

En guise de conclusion, vous n'avez pas de crainte à avoir pour
utiliser dlopen: la limite (qui est celle de l'espace d'addressage)
est difficile à atteindre (je n'ai pas réussi, et je ne tente pas un
test encore plus gros): il vous faudrait plusieurs jours pour générer
et compiler le code C correspondant.

Cordialement

(merci à Jacques Pitrat, qui m'a posé une question qui m'a suggéré
cette experimentation).


--
Basile STARYNKEVITCH http://starynkevitch.net/Basile/
email: basile<at>starynkevitch<dot>net
aliases: basile<at>tunes<dot>org = bstarynk<at>nerim<dot>net
8, rue de la Faïencerie, 92340 Bourg La Reine, France