Page 1 of 1

gc.collect(): optimisation tas/heap Python 83 Premium CE 5.5

Unread postPosted: 20 May 2020, 17:16
by critor
12382Dans sa prochaine mise à jour 5.5 gratuite prévue pour Mai 2020, Texas Instruments va rajouter de formidables possibilités historiques à ta TI-83 Premium CE :
  • mise à jour en 5.5 de l'application SciTools
  • mise à jour en 5.5 de l'application Periodic
  • mise à jour en 5.5 de l'application Python (TI-83 Premium CE Édition Python uniquement)

Python 5.5 offre de nouveaux modules intégrés pour tes scripts Python :
  • time, certes déjà présent mais maintenant listé au menu et donc officiel
  • ti_system, avec diverses possibilités :
    • détection des simples pressions de touches clavier, y compris avec un clavier USB externe !
    • affichage dans la console à la ligne que tu veux
    • exportation de listes de nombres du contexte Python vers l'environnement de la calculatrice
    • importation dans le contexte Python de listes existant dans l'environnement de la calculatrice vers
    • et donc plus généralement un début d'intégration du Python à l'environnement mathématique de la calculatrice; plus besoin de traiter les tâches numériques à part, l'application Python 5.5 va enfin pouvoir servir s'articulier naturellement au sein de la résolution de problèmes et tâches complexes !
  • ti_plotlib, une bibliothèque graphique pour tracer dans un repère othogonal, conformément aux programmes de Mathématiques et Physique-Chimie, comparable à matplotl chez Casio ou encore matplotlib.pyplot, et gérant ici les diagrammes suivants :
    • nuage de points
    • diagramme en ligne brisée
    • droite de régression linéaire
  • ti_graphics pour contrôler directement les pixels de l'écran, comparable à kandinsky chez NumWorks ou encore casioplot
  • ti_hub, pour les projets d'objects connectés à l'aide de l'interface TI-Innovator Hub
  • ti_rover, pour les projets de robotique à l'aide du TI-Innovator Rover
Mais ce n'est pas tout car Python 5.5 gère également la possibilité inédite de rajouter des modules Python complémentaires :
  • ce_turtl, comparable à turtle
  • ce_box pour les diagrammes en boîte
  • ce_chart pour les histogrammes et aires entre courbes
  • ce_quivr pour les diagrammes utilisant des champs de vecteurs



Sommaire :



1) mémoire de tas / heap et module gc

Go to top

L'appel mem() avec le script mem.py suivant permet d'estimer la capacité du tas (heap) Python, et retournait jusqu'à présent près de 20K sur TI-83 Premium CE Édition Python :
Code: Select all
def sizeenv():
  s=0
  import __main__
  for o in dir(__main__):
    try:s+=size(eval(o))
    except:pass
  return s
def size(o):
  s,t=0,type(o)
  if t==str:s=49+len(o)
  if str(t)=="<class 'function'>":s=136
  if t==int:
    s=24
    while o:
      s+=4
      o>>=30
  if t==list:
    s+=64
    for so in o:s+=8+size(so)
  return s
def mem(v=1,r=1):
  try:
    l=[]
    try:
      l+=[r and 793+sizeenv()]
      if v*r:print(" ",l[0])
      l+=[0]
      l+=[""]
      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,0)
      except:pass
      return l[0]
  except:return 0

Les formidables nouveautés de la version 5.5 semblent hélas avoir un coût important, à vide nous trouvons désormais à peine 17,5K de libres avec la version 5.5, un effondrement non négligeable de plus de 2,5K. :'(

La TI-83 Premium CE Édition Python fait partie des très rares calculatrices à disposer du module gc (garbage collect), module qui va nous être bien pratique pour comprendre ce qui se passe. Retenons les appels suivants :
  • gc.mem_alloc() retourne l'espace occupé sur le tas (heap)
  • gc.mem_free() retourne l'espace libre sur le tas (heap)
  • gc.collect(), formidable fonction qui nettoie / optimise le tas (heap)

Testons à vide à l'aide du petit script suivant, sur l'ancienne et la nouvelle version :
Code: Select all
from gc import *
a, f = 0, 0
a, f = mem_alloc(), mem_free()
(a, f, a+f)

Nous découvrons donc que le tas Python de la TI-83 Premium CE Édition Python a dans tous les cas une capacité totale de 19,968 Ko.

Ce n'est donc pas la capacité globale qui change mais la consommation du tas à vide, à peine plus de 600 o en version 5.4, et maintenant plus de 3 Ko en version 5.5. En effet lorsque tu lances tes scripts Python plusieurs choses sont initialisées et consomment du tas avant même l'exécution de ta première ligne de code. Et c'est là qu'il y a une lourde différence :

En passant il est normal ici de trouver un peu moins d'espace mémoire libre qu'avec le script précédent, vu qu'il le tas a subit une consommation supplémentaire à cause de l'imporation du module gc.

Tentons maintenant un appel explicite demandant de nettoyer la mémoire, avec gc.collect().

Et ben non, pas de chance ici, le nettoyage mémoire non seulement ne nous libère rien mais arriver même à consommer un petit peu. :troll

D'où le classement définitif en terme de capacité tas (heap) maximale utilisable pour tes scripts, avec la capacité totale précisée lorsque le module gc est disponible :
  1. 1,032942 Mo : Casio Graph 90+E
  2. 1,022145 / 1,024512 Mo : HP Prime G1 (version alpha)
  3. 100,560 Ko : Casio Graph 35+E II
  4. 32,339 Ko : NumWorks (firmware Omega)
  5. 31,624 Ko : NumWorks
  6. 19,500 / 19,968 Ko : TI-83 Premium CE Édition Python (ancienne version)
  7. 17,359 / 19,968 Ko : TI-83 Premium CE Édition Python (nouvelle version)
  1. 2,049276 Mo : TI-Nspire (application MicroPython)
  2. 1,032942 Mo : Casio Graph 90+E / fx-CG50
  3. 1,022145 Mo : HP Prime G1 (version alpha)
  4. 257,636 / 258,048 Ko : Casio Graph 35+E / 75+ / 35+ USB Power Graphic 2 / 75/95 USB Power Graphic 2 / fx-9750/9860GII USB Power Graphic 2
  5. 100,560 Ko : Casio Graph 35+E II / fx-9750/9860GIII
  6. 32,339 Ko : NumWorks (firmware Omega)
  7. 31,624 Ko : NumWorks
  8. 31,520 / 32,256 Ko : Casio Graph 35+E II / 85 / 35+ USB Power Graphic 1 / 75/95 USB Power Graphic 1 / fx-9750/9860GIII / fx-9750/9860GII USB Power Graphic 1 / fx-9860G
  9. 22,605 / 22,912 Ko : TI-83 Premium CE + TI-Python (firmware tiers)
  10. 19,500 / 19,968 Ko : TI-83 Premium CE + TI-Python + TI-83 Premium CE Édition Python (ancienne version)
  11. 17,359 / 19,968 Ko : TI-83 Premium CE Édition Python (nouvelle version)

La TI-83 Premium CE Édition Python était déjà la pire solution Python pour la capacité tas, et cela ne fait donc qu'empirer.

C'est probablement largement suffisant pour les petits algo-musements de quelques lignes qui seront traités en Mathématiques ou Physique-Chimie.

Le problème est ailleurs, ceux qui auront suffisamment accroché pour avoir envie d'aller plus loin risquent d'être rapidement déçus par leur calculatrice...
Ceux qui aborderont des projets (SNT, NSI, ... ou même non scolaires) risquent d'obtenir des erreurs de mémoire assez rapidement après le début du projet...

Car le Python ce n'est pas du C, les objets Python les plus élémentaires sont extrêmement gourmands en mémoire :
  • 64 octets rien que pour une liste vide
  • plus 8 octets pour chaque élément de liste supplémentaire, sans compter la taille de l'élément en question
  • 24 octets pour un entier nul
  • 28 octets pour un entier court non nul
  • 49 octets rien que pour une chaîne vide
  • plus 1 octet par caractère de chaîne supplémentaire
  • ...
Alors imagine la catastrophe que cela pourrait être pour des projets tu multiplies le nombre de ces objets au sein de listes, ou pire lorsque tu passes à la 2ème dimension avec des listes de listes... :#roll#:

Mais attends nous n'avons pas encore dit notre dernier mot, passons aux modules importables et voyons ce que la fonction gc.collect() peut bien donner dessus. ;)




2) importations modules et consommation tas / heap

Go to top

Voyons maintenant un petit peu ce que consomme l'importation de chaque module disponible sur le tas (heap), grâce ici aux formidables possibiltés exclusives du module gc.

Il suffit d'appeler les fonctions du module gc vues plus haut, juste avant et après l'importation d'un module, afin de vérifier l'espace consommé sur le tas. Nous allons même tenter en prime un nettoyage du tas après importation, et voir si cela améliore les choses.

Voici un script en ce sens, volontairement minimaliste sans définition de fonction afin de minimiser les chances de déclencher un nettoyage mémoire en dehors des appels explicites à gc.collect() :
Code: Select all
from gc import mem_free, collect

smod = input('Module : ')
mf1, mf2, mf3 = 0, 0, 0
scmd = 'from ' + smod + ' import *'
collect()
mf1 = mem_free()
exec(scmd)
mf2 = mem_free()
collect()
mf3 = mem_free()
print("initial: ", mf1)
print("importation: ", mf2, mf2-mf1)
print("nettoyage: ", mf3, mf3-mf1)

Voici donc les consommations de tas à l'importation puis après nettoyage des différents modules intégrés :
  • builtins : 800 o à l'importation, 720 o après nettoyage
  • array : 96 o à l'importation, 16 o après nettoyage
  • collections : 96 o à l'importation, 16 o après nettoyage
  • gc : 112 o à l'importation, 32 o après nettoyage (mesure possiblement faussée, puisque le module est déjà partiellement importé)
  • math : 320 o à l'importation, 240 o après nettoyage
  • random : 160 o à l'importation, 80 o après nettoyage
  • sys : 208 o à l'importation, 128 o après nettoyage
  • time : 112 o à l'importation, 32 o après nettoyage
  • ti_graphics : 2,880 Ko à l'importation, 1,584 Ko après nettoyage
  • ti_hub : 256 o à l'importation, 176 o après nettoyage
  • ti_plotlib : 7,216 Ko à l'importation, 3,504 Ko après nettoyage
  • ti_rover : 4,832 Ko à l'importation, 2,352 Ko après nettoyage
  • ti_system : 208 o à l'importation, 128 o après nettoyage
  • ce_box : 13,440 Ko à l'importation, 6,704 Ko après nettoyage
  • ce_chart : 13,328 Ko à l'importation, 6,448 Ko après nettoyage
  • ce_quivr : 8,832 Ko à l'importation, 3,904 Ko après nettoyage
  • ce_turtl : 9,792 Ko à l'importation, 4,944 Ko après nettoyage


Et oui, c'est fantastique, l'appel gc.collect() à ce jour exclusif sur TI-83 Premium CE Edition Pyton te permet de libérer du tas, et ce de façon très significative dans le contexte de l'utilisation des plus gros modules dont certains te remplissaient quasiment tout les tas ! :bj:

ti_graphics, ti_plotlib, ti_rover, ce_box, ce_chart, ce_quivr et ce_turtl, la consommation énorme de chacun de ces modules à l'importation est immédiatement quasiment réduite de moitié ! :D

Re: gc.collect(): optimisation tas/heap Python 83 Premium CE

Unread postPosted: 20 May 2020, 20:37
by jean-baptiste boric
Est-ce qu'appeler le garbage collector manuellement a vraiment un impact sur la quantité de mémoire disponible en pratique? Ça m'étonnerait qu'on gratte plus, Micro/CircuitPython devrait déjà l’appeler automatiquement quand le tas est plein pour faire de la place...

Re: gc.collect(): optimisation tas/heap Python 83 Premium CE

Unread postPosted: 20 May 2020, 20:40
by critor
L'article était surtout pour montrer l'espace occupé par chaque module, on les découvre. :)

En pratique, je me doute que gc.collect() est appelé automatiquement, notamment lorsque mon script mem() épuise le tas, et même sur les modèles qui n'exposent pas ce fonctionnement interne via un module gc.