micropython dans KhiCAS
Posté le 01/02/2022 14:22
J'ai avance sur le portage de MicroPython dans KhiCAS pour graph 90, ca compile, mais j'ai un crash lors de l'initialisation de MicroPython, lie a l'allocation memoire. Ca plante au 1er appel d'allocation dans la fonction mp_init (py/runtime.c) sur une demande d'allocation de 24 bits, lorsque le gc est actif, le pointeur renvoye est nul. Si je desactive le garbage collector, ca ne marche pas non plus, ca plante un peu plus tard a la 5eme allocation memoire (avec kmalloc de gint, mais c'est pas kmalloc la cause, car si on desactive les arena en ram en ne conservant que le malloc systeme ca plante tout autant).
C'est probablement lie a une mauvaise configuration. Mon mpconfigport.h est
https://www-fourier.univ-grenoble-alpes.fr/~parisse/tmp/mpconfigport.h, j'ai beau le comparer avec celui de CasioPython je ne vois rien qui explique le crash (
https://github.com/Zezombye/casiopy/blob/master/ports/minimal/mpconfigport.h). La compilation se fait avec des commandes du type
sh3eb-elf-gcc -DNUMWORKS -DMICROPY_LIB -I. -I.. -I../py -Ibuild -Wall -ansi -std=gnu99 -DFFCONF_H=\"lib/oofatfs/ffconf.h\" -Os -g -DMODULE_ULAB_ENABLED=1 -mb -m4a-nofpu -mhitachi -fdata-sections -ffunction-sections -fno-strict-aliasing -fno-exceptions -c -MD -o build/./main.o main.c
(le flag NUMWORKS sert a contourner un bug de sprintf dans un module additionnel, ca n'a rien a voir avec le code de micropython)
Le source complet (giac+mp) est la
https://www-fourier.univ-grenoble-alpes.fr/~parisse/tmp/giac2.tgz (se compile avec ./mklib dans micropython-1.12/fxcg et make dans giac2)
L'addin en 2 parties
https://www-fourier.univ-grenoble-alpes.fr/~parisse/tmp/khicas.g3a et
https://www-fourier.univ-grenoble-alpes.fr/~parisse/tmp/khicas.ac2
Pour lancer MicroPython depuis le shell de KhiCAS, faire shift-PRGM puis 8 pour mettre python( en ligne de commande et valider. Le crash apparait avec le print du malloc fautif que j'ai rajoute dans py/malloc.c, on devine aussi le msg d'erreur de micropython (FATAL uncaught NLR ...) genere suite au pointeur nul (non catche par un nlr_push).
Citer : Posté le 08/02/2022 12:35 | #
Oui c'est ça, en fait le GC est capable de lire les contenus des objets pour trouver les sous-objets dedans, et ainsi déterminer tous les objets accessibles. C'est possible parce que c'est lui qui les alloue avec son malloc dédié, et c'est pour ça que je voulais vérifier le gc_init() - il faut absolument que tous les pointeurs pointant dans la zone concernée aient été créés par le GC.
Mon code n'aidera probablement pas pour les crashs par rapport à celui de CasioPython, il réduit juste le risque de fuite de mémoire en ajoutant quelques pointeurs. Si tu as des fuites de mémoire dans le futur, n'hésite pas à revenir là-dessus, d'autres registres pourraient être liés.
D'ici là, est-ce que par hasard le comportement change (ie. Pascal(4) marche par exemple) si tu prends un tas plus grand ? Histoire de voir si tu tombes ou pas à court de mémoire à un moment. J'en doute mais on sait jamais.
Citer : Posté le 08/02/2022 12:56 | #
Pas de changement si j'augmente le tas. Le plus curieux c'est que le GC ne semble pas appele (je ne vois pas les messages que j'ai rajoute pour verifier que je passe par ton nouveau code). Donc c'est peut-etre un probleme de parse independant de celui du GC (le GC fonctionne bien avec Mandelbrot). Dans string.c de la libc je vois aussi memcmp et memcpy marque comme builtin gcc, sont-ils connus comme etant bugfree?
Citer : Posté le 08/02/2022 13:16 | #
Ha ha tout de suite les bons réflexes je vois
Dans CGDoom j'ai remplacé memcpy() par la version de gint, y'a probablement une bonne raison (mais ça pourrait être les perfs plutôt qu'un bug). Et le string.c que j'ai a un memcp qui est tout naïf (que je n'ai pas écrit) et paraît impeccable.
Tu peux essayer de remplacer memcpy() par le truc naïf, si ça aide on pourra voir pour te mettre une version optimisée après.
Il n'y a pas de "builtin" memcpy en fait, GCC peut parfois remplacer la copie par des accès pointeurs manuels mais ultimement ce n'est pas lui qui fournit la fonction. Il est assez bien connu que le code compilé par GCC doit être linké avec libgcc et une libc fournissant memcmy, memmove, memset et memcmp.
Ajouté le 08/02/2022 à 13:17 :
J'ai un commit qui s'intitule "use [gint] memcpy instead of likely-broken syscall", donc en fait peut-être que c'était un bug x)
Citer : Posté le 08/02/2022 15:46 | #
J'ai ca dans string.c, ca te parait bon?
void *memccpy(void *dest, const void *src, int c, size_t num) {
char* d = (char*)dest;
char* s = (char*)src;
while ((*d = *s) != (char)c && num > 0) {
d++;
s++;
num--;
}
return num == 0 ? NULL : (void*)(++d);
}
void *memchr(const void *ptr, int c, size_t n) {
char* s = (char*)ptr;
while (*s != (char)c && n > 0) {
s++;
n--;
}
return n == 0 ? NULL : (void*)s;
}
int memcmp(const void *p1, const void *p2, unsigned int n) {
char* s1 = (char*)p1;
char* s2 = (char*)p2;
while (n-- != 0 && *s1 == *s2) {
s1++;
s2++;
}
return *s1 - *s2;
}
void* memcpy(void* destination, const void* source, size_t num) {
char* d = (char*)destination;
char* s = (char*)source;
while (num-- > 0) {
*d = *s;
d++;
s++;
}
return destination;
}
void* memmove(void* destination, const void* source, size_t num) {
void* d = malloc(num);
memcpy(d, source, num);
memcpy(destination, d, num);
free(d);
return destination;
}
// Syscall
void *memset(void *dest, int c, unsigned int n) {
char* d = (char*)dest;
for (;n>0;n--,d++) { *d = (char)c; }
return dest;
}
Citer : Posté le 08/02/2022 15:51 | #
Ça a l'air bon.
Citer : Posté le 08/02/2022 16:03 | #
Ca continue a planter. Cette fois-ci les premiers Pascal marchent, mais le mandelbrot ne compile plus (crash).
Ajouté le 08/02/2022 à 16:10 :
Par exemple la j'ai un TLB ERROR avec PC=0x08134DB0 qui se trouve dans le tas du gc (qui commence en 0x08133ed4, taille 64k)
Ajouté le 08/02/2022 à 17:10 :
Bon, j'ai rechange un #if 1 en un #if 0 pour gc_relloc, et ca a l'air mieux, j'ai Pascal et le Mandelbrot qui ont l'air de tourner. Je testerai d'autres scripts, peut-etre jeudi.
Citer : Posté le 08/02/2022 18:40 | #
Ok, on croise les doigts... heureusement il y a CasioPython comme référence, juste au cas où.
Citer : Posté le 11/02/2022 21:34 | #
Je n'ai plus eu de mauvaises surprises avec des scripts MicroPython.
Mais un nouveau truc bizarre, cette fois dans la USTL. La comparaison de deux vector<T> pour T=shot int ne marche plus correctement, alors qu'avant tous les changements dans la libc ca semblait marcher, je veux dire que le CAS fonctionnait.
Bon, j'ai contourne le bug pour les degres partiels de polynomes, le CAS a de nouveau l'air de marcher, enfin pour ce que j'ai teste.
Citer : Posté le 11/02/2022 21:35 | #
Compile un exemple minimal et regarde ce que le code assembleur fait. Ça va probablement se ramener à memcmp() ou un truc du genre, je suppose...
Citer : Posté le 12/02/2022 08:07 | #
Du cote de la USTL cela donne
bool cmemlink::operator== (const cmemlink& l) const noexcept
{
return (l.m_Size == m_Size &&
(l.m_Data == m_Data || 0 == memcmp (l.m_Data, m_Data, m_Size)));
}
Le code actuel de memcmp,
int memcmp(const void *p1, const void *p2, unsigned int n) {
char* s1 = (char*)p1;
char* s2 = (char*)p2;
while (n-- != 0 && *s1 == *s2) {
s1++;
s2++;
}
return *s1 - *s2;
}
C'est pas un style que j'aime, mais je ne vois pas ce qui cloche. J'aurais plutot fait
int memcmp(const void *p1, const void *p2, unsigned int n) {
char* s1 = (char*)p1;
char* s2 = (char*)p2;
for (;n>0;--n,++s1,++s2){
if (*s1!=*s2)
return *s1 - *s2;
}
return 0;
}