QCC 2020 épisode 4 : Python et tas (heap)
Posted: 08 Aug 2020, 22:40
Quelle Calculatrice programmable Choisir 2020
(index des épisodes)
Episode 4 - Python et tas (heap)
(index des épisodes)
Episode 4 - Python et tas (heap)
Les interpréteurs MicroPython ou similaires qu'elles font tourner font appel à 3 types de mémoires avec les rôles suivants :
Dans l'épisode précédent nous avons comparé les tailles de stack offertes par les calculatrices programmables en langage Python.
Aujourd'hui nous allons nous intéresser au heap. Cet espace est extrêmement important et surtout sur les plateformes nomades, car contrairement à d'autres langages les objets Python les plus simples ont le défaut d'être assez gros. Ce sera le plus souvent le heap le facteur le plus limitant pour tes projets.
- la mémoire de stockage qui accueille et conserve tes scripts
- le stack (pile) qui, à l'exécution, accueille les références vers les objets créés
- le heap (tas) qui, à l'exécution, accueille le contenu de ces objets
Dans l'épisode précédent nous avons comparé les tailles de stack offertes par les calculatrices programmables en langage Python.
Aujourd'hui nous allons nous intéresser au heap. Cet espace est extrêmement important et surtout sur les plateformes nomades, car contrairement à d'autres langages les objets Python les plus simples ont le défaut d'être assez gros. Ce sera le plus souvent le heap le facteur le plus limitant pour tes projets.
Le temps de construire ensemble notre protocole de tests, commençons par les TI-83 Premium CE Edition Python et TI-84 Plus CE-T Edition Python. Elles sont hautement intéressantes pour comprendre ce qui se passe, puisque disposant du module Python gc. Le module gc nous offre en effet plusieurs fonctions bien utiles ici :
Les TI-83 Premium CE Edition Python et TI-84 Plus CE-T Edition Python disposent donc d'un heap avec exactement 19,968 Ko de capacité.
Mais lorsque l'on accède à l'environnement Python, nombre de choses sont initialisées et ce heap n'est pas vide. Les dernières versions respectives 5.5.1 et 5.5.5 ne nous offrent plus que 17,104 Ko de libres sur le heap, alors que la version 5.4 de l'année dernière culminait à 19,408 Ko.
Précisions que cet espace libre a de plus ici été amputé de par notre importation du module gc. Ce module n'étant hélas disponible que sur une minorité de Pythonnettes il va nous falloir procéder autrement, surtout si l'on souhaite obtenir des mesures comparables.
Donnons quelques éléments de taille en mémoire d'objets Python usuels, du moins sur les plateformes 32 bits que sont nos calculatrices :
Une piste consiste alors à tenter de remplir le heap jusqu'à déclenchement d'une erreur, et retourner alors l'espace maximal que l'on a réussi à consommer. Voici justement une fonction en ce sens :
L'appel
Mais voilà autre petit problème, le résultat n'est pas toujours le même, dépendant en effet de l'état du heap lors de l'appel. Rien que sur les résultats ci-contre, nous avons une marge d'erreur de 1 à 2%.
C'est beaucoup, en tous cas suffisamment pour inverser injustement des modèles au classement. Or cette année, nous tenons à être aussi précis que possible comme tu as pu le voir dès notre 1er épisode, afin justement de produire un classement aussi équitable que possible.
Certes, on pourrait nettoyer ça avant chaque appel avec
L'absence du module gc et donc de
Et bien voici l'élément final du protocole de test que nous te proposons, avec une boucle répétant des appels
Nous aurions donc 17,233 Ko disponibles sur le heap.
Mais ici encore lorsque nous réalisons notre appel, le heap a déjà été entâmé par l'importation de notre script de test.
Pas grave, il nous suffit tout simplement d'utiliser le module gc pour connaître la consommation heap de notre script.
736 octets donc, qu'il nous suffira d'ajouter à toutes les valeurs obtenues dans ce qui suit.
Nous avons donc ici sur TI-83 Premium CE Edition Python et TI-84 Plus CE-T Edition Python 17,233+0,736= 17,969 Ko. Et entre nous, ce n'est franchement pas beaucoup.
gc.collect()
pour nettoyer le heap en supprimant les valeurs d'objets Python qui ne sont plus référencéesgc.mem_alloc()
pour connaître la consommation du heap en octetsgc.mem_free()
pour connaître l'espace heap disponible en octets
Les TI-83 Premium CE Edition Python et TI-84 Plus CE-T Edition Python disposent donc d'un heap avec exactement 19,968 Ko de capacité.
Mais lorsque l'on accède à l'environnement Python, nombre de choses sont initialisées et ce heap n'est pas vide. Les dernières versions respectives 5.5.1 et 5.5.5 ne nous offrent plus que 17,104 Ko de libres sur le heap, alors que la version 5.4 de l'année dernière culminait à 19,408 Ko.
Précisions que cet espace libre a de plus ici été amputé de par notre importation du module gc. Ce module n'étant hélas disponible que sur une minorité de Pythonnettes il va nous falloir procéder autrement, surtout si l'on souhaite obtenir des mesures comparables.
Donnons quelques éléments de taille en mémoire d'objets Python usuels, du moins sur les plateformes 32 bits que sont nos calculatrices :
- pour un entier nul : 24 octets déjà...
- pour un entier court non nul (codable sur 31 bits + 1 bit de signe) : 28 octets
- pour un entier long :
- 28 octets
- + 4 octets pour chaque groupe de 30 bits utilisé par son écriture binaire au-delà des 31 bits précédents
- pour une chaîne:
- 49 octets
- + 1 octet par caractère
- pour une liste :
- 64 octets
- + 8 octets par élément
- + les tailles de chaque élément
- Code: Select all
def size(o):
t = type(o)
s = t == str and 49 + len(o)
if t == int:
s = 24
while o:
s += 4
o >>= 30
elif t == list:
s = 64 + 8*len(o)
for so in o:
s += size(so)
return s
Une piste consiste alors à tenter de remplir le heap jusqu'à déclenchement d'une erreur, et retourner alors l'espace maximal que l'on a réussi à consommer. Voici justement une fonction en ce sens :
- Code: Select all
def mem(v=1):
try:
l=[]
try:
l.append(0)
l.append(0)
l.append("")
l[2] += "x"
while 1:
try:
l[2] += l[2][l[1]:]
except:
if l[1] < len(l[2]) - 1:
l[1] = len(l[2]) - 1
else:
raise(Exception)
except:
if v:
print("+", size(l))
try:
l[0] += size(l)
except:
pass
try:
l[0] += mem(v)
except:
pass
return l[0]
except:
return 0
L'appel
mem(0)
semble marcher comme souhaité, retournant une valeur qui peut comme prévu légèrement dépasser les 17,104 Ko trouvés plus haut.Mais voilà autre petit problème, le résultat n'est pas toujours le même, dépendant en effet de l'état du heap lors de l'appel. Rien que sur les résultats ci-contre, nous avons une marge d'erreur de 1 à 2%.
C'est beaucoup, en tous cas suffisamment pour inverser injustement des modèles au classement. Or cette année, nous tenons à être aussi précis que possible comme tu as pu le voir dès notre 1er épisode, afin justement de produire un classement aussi équitable que possible.
Certes, on pourrait nettoyer ça avant chaque appel avec
gc.collect()
, mais ce ne serait pas juste puisque nous n'aurons pas cette possibilité sur nombre de modèles concurrents. Il nous faut donc trouver autre chose.L'absence du module gc et donc de
gc.collect()
ne signifie absolument pas que le heap ne sera jamais nettoyé. C'est juste que nous ne contrôlons pas le moment où il le sera.Et bien voici l'élément final du protocole de test que nous te proposons, avec une boucle répétant des appels
mem(0)
, ce qui devrait finir par déclencher des nettoyages du heap, et te signalant à chaque fois que la valeur retournée bat ainsi un nouveau record :- Code: Select all
def testmem():
m = 0
while 1:
t = mem(0)
if t > m:
m = t
input(str(m))
testmem()
signale au départ rapidement plusieurs nouveaux records d'occupation mémoire. Battre chaque nouveau record est de plus en plus difficile, et les nouveaux affichages nécessitent de plus en plus de temps. Nous arrêtons le test lorsque le dernier record n'aura pas pu être battu malgré 5 minutes écoulées depuis son affichage.Nous aurions donc 17,233 Ko disponibles sur le heap.
Mais ici encore lorsque nous réalisons notre appel, le heap a déjà été entâmé par l'importation de notre script de test.
Pas grave, il nous suffit tout simplement d'utiliser le module gc pour connaître la consommation heap de notre script.
736 octets donc, qu'il nous suffira d'ajouter à toutes les valeurs obtenues dans ce qui suit.
Nous avons donc ici sur TI-83 Premium CE Edition Python et TI-84 Plus CE-T Edition Python 17,233+0,736= 17,969 Ko. Et entre nous, ce n'est franchement pas beaucoup.
Prenons maintenant l'ancienne TI-83 Premium CE munie du module externe TI-Python interdit aux examens français, mais restant utilisable en classe ainsi qu'aux évaluations si l'enseignant le permet.
Ce n'est pas la panacée mais c'est quand même sensiblement mieux, avec 19,496+0,736= 20,232 Ko.
Conscient du problème de sous-dimensionnement de ce heap, Lionel Debroux a développé un firmware tiers pour le module externe TI-Python.
Si tu l'installes tu bénéficieras donc d'un espace heap disponible nettement amélioré, avec 22,158+0,736= 22,894 Ko.
C'est donc au-delà de la capacité heap de 19,968 Ko trouvée plus haut pour le firmware officiel, mais c'est normal puisque l'on se rend compte que Lionel a en effet passé la capacité heap à 22,912 Ko.
Ce n'est pas la panacée mais c'est quand même sensiblement mieux, avec 19,496+0,736= 20,232 Ko.
Conscient du problème de sous-dimensionnement de ce heap, Lionel Debroux a développé un firmware tiers pour le module externe TI-Python.
Si tu l'installes tu bénéficieras donc d'un espace heap disponible nettement amélioré, avec 22,158+0,736= 22,894 Ko.
C'est donc au-delà de la capacité heap de 19,968 Ko trouvée plus haut pour le firmware officiel, mais c'est normal puisque l'on se rend compte que Lionel a en effet passé la capacité heap à 22,912 Ko.
Arrive maintenant la NumWorks. Depuis l'année dernière, nous passons de la version 12.2 à 14.4. Enormément de choses ont été apportées par les mises à jour intermédiaires.
Et justement, le heap qui était à 15,557+0,736= 16,293 Ko utilisables pour tes scripts, double à 31,485+0,736= 32,221 Ko !
Mais la chose ne s'arrête pas là. Il est possible très facilement sur ta NumWorks d'installer un firmware tiers, Omega. Basé sur le firmware officiel dont il suit les évolutions, il lui rajoute plein de fonctionnalités utiles et légitimes qui auront le gros avantage de rester disponible en mode examen !
Sur la dernière édition matérielle NumWorks N0110, Omega permet notamment l'ajout d'applications. Plusieurs sont disponibles dont l'application de mathématiques intégrée KhiCAS par Bernard Parisse, enseignant chercheur à l'Université de Grenoble, une version adaptée aux plateformes nomades qui s'inspire de son propre logiciel de Mathématiques intégré Xcas, et en reprend notamment le moteur de calcul formel GIAC.
Et bien Bernard est justement en train de te préparer une mise à jour majeure de KhiCAS pour l'année scolaire 2020-2021, déjà accessible en version de test. Au menu des nouveautés une sous-application tableur / feuille de calculs, ainsi que l'intégration d'un véritable interpréteur MicroPython !
Et grosse surprise puisque nous bondissons ici à 39,747+0,736= 40,483 Ko de heap disponible, Bernard ayant en effet eu la bonne idée de passer la capacité heap à 40 Ko !
Mais ce n'est pas tout, KhiCAS est notamment la seule solution Python sur calculatrices à te permettre de choisir toi-même la taille du heap, par défaut donc de 40 Ko, et ce librement entre 16 Ko et 64 Ko, une formidable option pour estimer la consommation heap de tes projets !
Passons donc ça à 64 Ko, et effectivement nous obtenons maintenant un espace heap disponible de 63,660+0,736= 64,396 Ko !
Et justement, le heap qui était à 15,557+0,736= 16,293 Ko utilisables pour tes scripts, double à 31,485+0,736= 32,221 Ko !
Mais la chose ne s'arrête pas là. Il est possible très facilement sur ta NumWorks d'installer un firmware tiers, Omega. Basé sur le firmware officiel dont il suit les évolutions, il lui rajoute plein de fonctionnalités utiles et légitimes qui auront le gros avantage de rester disponible en mode examen !
Sur la dernière édition matérielle NumWorks N0110, Omega permet notamment l'ajout d'applications. Plusieurs sont disponibles dont l'application de mathématiques intégrée KhiCAS par Bernard Parisse, enseignant chercheur à l'Université de Grenoble, une version adaptée aux plateformes nomades qui s'inspire de son propre logiciel de Mathématiques intégré Xcas, et en reprend notamment le moteur de calcul formel GIAC.
Et bien Bernard est justement en train de te préparer une mise à jour majeure de KhiCAS pour l'année scolaire 2020-2021, déjà accessible en version de test. Au menu des nouveautés une sous-application tableur / feuille de calculs, ainsi que l'intégration d'un véritable interpréteur MicroPython !
Et grosse surprise puisque nous bondissons ici à 39,747+0,736= 40,483 Ko de heap disponible, Bernard ayant en effet eu la bonne idée de passer la capacité heap à 40 Ko !
Mais ce n'est pas tout, KhiCAS est notamment la seule solution Python sur calculatrices à te permettre de choisir toi-même la taille du heap, par défaut donc de 40 Ko, et ce librement entre 16 Ko et 64 Ko, une formidable option pour estimer la consommation heap de tes projets !
Passons donc ça à 64 Ko, et effectivement nous obtenons maintenant un espace heap disponible de 63,660+0,736= 64,396 Ko !
La Casio Graph 35+E II nous crève maintenant le plafond avec pas moins de 99,490+0,736= 100,226 Ko de heap disponible dans son application Python officielle !
Il existe aussi une application Python tierce pour les Casio Graph monochromes, CasioPython. Elle est compatible avec les modèles suivants, mais hélas bloquée par le mode examen :
Sur les deux premiers nous nous envolons à pas moins de 257,026+0,736= 257,762 Ko !
En effet selon le module gc, la capacité heap a ici été réglée à 258,048 Ko.
Hélas, un bug toujours pas corrigé depuis l'année dernière fait que CasioPython reconnaît bêtement la Graph 35+E II comme un ancien modèle, n'y réservant alors qu'une capacité heap de 32,256 Ko.
Nous n'obtenons alors qu'un espace heap libre de 31,163+0,736= 31,899 Ko, ici donc sans aucun intérêt par rapport à l'application Python officielle.
- Graph 75+E
- Graph 35+E via une installation du système Graph 75+E
- Graph 35+E II
Sur les deux premiers nous nous envolons à pas moins de 257,026+0,736= 257,762 Ko !
En effet selon le module gc, la capacité heap a ici été réglée à 258,048 Ko.
Hélas, un bug toujours pas corrigé depuis l'année dernière fait que CasioPython reconnaît bêtement la Graph 35+E II comme un ancien modèle, n'y réservant alors qu'une capacité heap de 32,256 Ko.
Nous n'obtenons alors qu'un espace heap libre de 31,163+0,736= 31,899 Ko, ici donc sans aucun intérêt par rapport à l'application Python officielle.
La Casio Graph 90+E nous met maintenant en orbite avec un formidable 1031,713+0,736= 1032,449 Ko soit 1,032 Mo, de quoi développer de fantastiques projets !
Pour les TI-Nspire CX II, nous ne disposons hélas pas à ce jour de préversion de la mise à jour qui devrait sortir mi-septembre 2020 et rajouter la programmation Python.
Pour les anciens modèles TI-Nspire CX et TI-Nspire monochromes par contre, si non encore mis à jour en version 4.5.1 ou supérieure, il est possible de leur installer le jailbreak Ndless qui autorise à son tour par la suite l'installation d'applications tierces.
Une fois Ndless installé, on peut par exemple rajouter l'application MicroPython qui nous fait littéralement quitter l'attraction terrestre avec pas moins de 2080,065+0,736= 2080,801 Ko soit 2,081 Mo !
En creusant un petit peu grâce au module gc ici disponible, nous découvrons que la capacité heap est de 2,049 Mo.
Mais pour les seules anciennes TI-Nspire CX, ce n'est pas tout. Bernard Parisse est également en train de préparer ici la même mise à jour majeure de l'application KhiCAS que pour NumWorks, avec feuille de calcul / tableur et véritable interpréteur MicroPython intégrés, également disponible en version de test !
Nous sommes ici en retrait même si cela reste parfaitement honorable, avec 1023,812+0,736= 1024,548 Ko soit 1,025 Mo.
En effet la capacité heap n'est ici que de 1,025 Mo selon le module gc.
Pour les anciens modèles TI-Nspire CX et TI-Nspire monochromes par contre, si non encore mis à jour en version 4.5.1 ou supérieure, il est possible de leur installer le jailbreak Ndless qui autorise à son tour par la suite l'installation d'applications tierces.
Attention toutefois, contrairement aux applications Omega pour NumWorks, Ndless fait hélas le choix de s'effacer totalement devant le mode examen !
Les applications Ndless seront donc inutilisables, y compris donc les applications parfaitement légitimes comme MicroPython apportant des fonctionnalités disponibles en mode examen sur d'autres modèles.
Les applications Ndless seront donc inutilisables, y compris donc les applications parfaitement légitimes comme MicroPython apportant des fonctionnalités disponibles en mode examen sur d'autres modèles.
Une fois Ndless installé, on peut par exemple rajouter l'application MicroPython qui nous fait littéralement quitter l'attraction terrestre avec pas moins de 2080,065+0,736= 2080,801 Ko soit 2,081 Mo !
En creusant un petit peu grâce au module gc ici disponible, nous découvrons que la capacité heap est de 2,049 Mo.
Mais pour les seules anciennes TI-Nspire CX, ce n'est pas tout. Bernard Parisse est également en train de préparer ici la même mise à jour majeure de l'application KhiCAS que pour NumWorks, avec feuille de calcul / tableur et véritable interpréteur MicroPython intégrés, également disponible en version de test !
Nous sommes ici en retrait même si cela reste parfaitement honorable, avec 1023,812+0,736= 1024,548 Ko soit 1,025 Mo.
En effet la capacité heap n'est ici que de 1,025 Mo selon le module gc.
Une mise à jour HP Prime rajoutant une application Python est dans les tuyaux. Aucune date de sortie communiquée à ce jour, mais une version intégrant cette fonctionnalité a été publiée par erreur en octobre 2019.
Nous ne pourrons en l'état la retenir au classement, surtout que nous n'avons aucune garantie qu'elle sorte en 2020-2021, mais nous testons quand même lorsque possible afin de pouvoir t'estimer ce que vaudra la mise à jour en question.
Donc ici encore nous bénéficions d'un heap correctement dimensionné, avec 1017,692+0,736= 1018,428 Ko soit 1,018 Mo de disponibles sur le heap.
Le module gc nous apprend en effet que HP a réglé la capacité de son heap ici encore à 1,025 Mo, exactement comme Bernard.
Cela a sûrement été corrigé depuis, mais cette vieille version est en pratique très instable. Nous te déconseillons fortement de l'installer dans le contexte d'évaluations.
Nous ne pourrons en l'état la retenir au classement, surtout que nous n'avons aucune garantie qu'elle sorte en 2020-2021, mais nous testons quand même lorsque possible afin de pouvoir t'estimer ce que vaudra la mise à jour en question.
Donc ici encore nous bénéficions d'un heap correctement dimensionné, avec 1017,692+0,736= 1018,428 Ko soit 1,018 Mo de disponibles sur le heap.
Le module gc nous apprend en effet que HP a réglé la capacité de son heap ici encore à 1,025 Mo, exactement comme Bernard.
Résumé de nos mesures, avec donc l'espace heap Python disponible à vide pour chacun des modèles :
- en bas ne tient compte que des seules capacités d'origine officielles de la machine en mode examen sur les versions actuellement à notre disposition
- en haut tient compte de toutes les possibilités évoquées pour d'autres situations (installation d'applications, mises à jour à venir, contexte hors mode examen...)