Salome HOME
Sysinfo update and complements
[modules/adao.git] / src / daComposant / daCore / PlatformInfo.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2024 EDF R&D
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
22
23 """
24     Informations sur le code et la plateforme, et mise à jour des chemins.
25
26     La classe "PlatformInfo" permet de récupérer les informations générales sur
27     le code et la plateforme sous forme de strings, ou d'afficher directement
28     les informations disponibles par les méthodes. L'impression directe d'un
29     objet de cette classe affiche les informations minimales. Par exemple :
30         print(PlatformInfo())
31         print(PlatformInfo().getVersion())
32         created = PlatformInfo().getDate()
33
34     La classe "PathManagement" permet de mettre à jour les chemins système pour
35     ajouter les outils numériques, matrices... On l'utilise en instanciant
36     simplement cette classe, sans même récupérer d'objet :
37         PathManagement()
38
39     La classe "SystemUsage" permet de  sous Unix les différentes tailles
40     mémoires du process courant. Ces tailles peuvent être assez variables et
41     dépendent de la fiabilité des informations du système dans le suivi des
42     process.
43 """
44 __author__ = "Jean-Philippe ARGAUD"
45 __all__ = []
46
47 import os
48 import sys
49 import platform
50 import socket
51 import locale
52 import logging
53 import re
54 import numpy
55
56 # ==============================================================================
57 def uniq( __sequence ):
58     """
59     Fonction pour rendre unique chaque élément d'une liste, en préservant l'ordre
60     """
61     __seen = set()
62     return [x for x in __sequence if x not in __seen and not __seen.add(x)]
63
64 class PathManagement(object):
65     """
66     Mise à jour du path système pour les répertoires d'outils
67     """
68     __slots__ = ("__paths")
69
70     def __init__(self):
71         "Déclaration des répertoires statiques"
72         parent = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
73         self.__paths = {}
74         self.__paths["daNumerics"] = os.path.join(parent, "daNumerics")
75         #
76         for v in self.__paths.values():
77             if os.path.isdir(v):
78                 sys.path.insert(0, v )
79         #
80         # Conserve en unique exemplaire chaque chemin
81         sys.path = uniq( sys.path )
82         del parent
83
84     def getpaths(self):
85         """
86         Renvoie le dictionnaire des chemins ajoutés
87         """
88         return self.__paths
89
90 # ==============================================================================
91 class PlatformInfo(object):
92     """
93     Rassemblement des informations sur le code et la plateforme
94     """
95     __slots__ = ("has_salome", "has_yacs", "has_adao", "has_eficas")
96
97     def __init__(self):
98         "Sans effet"
99         self.has_salome = bool( "SALOME_ROOT_DIR" in os.environ )
100         self.has_yacs   = bool(   "YACS_ROOT_DIR" in os.environ )
101         self.has_adao   = bool(   "ADAO_ROOT_DIR" in os.environ )
102         self.has_eficas = bool( "EFICAS_ROOT_DIR" in os.environ )
103         PathManagement()
104
105     def getName(self):
106         "Retourne le nom de l'application"
107         import daCore.version as dav
108         return dav.name
109
110     def getVersion(self):
111         "Retourne le numéro de la version"
112         import daCore.version as dav
113         return dav.version
114
115     def getDate(self):
116         "Retourne la date de création de la version"
117         import daCore.version as dav
118         return dav.date
119
120     def getYear(self):
121         "Retourne l'année de création de la version"
122         import daCore.version as dav
123         return dav.year
124
125     def getSystemInformation(self, __prefix=""):
126         __msg  = ""
127         __msg += "\n%s%30s : %s"%(__prefix, "platform.system", platform.system())
128         __msg += "\n%s%30s : %s"%(__prefix, "sys.platform", sys.platform)
129         __msg += "\n%s%30s : %s"%(__prefix, "platform.version", platform.version())
130         __msg += "\n%s%30s : %s"%(__prefix, "platform.platform", platform.platform())
131         __msg += "\n%s%30s : %s"%(__prefix, "platform.machine", platform.machine())
132         if len(platform.processor()) > 0:
133             __msg += "\n%s%30s : %s"%(__prefix, "platform.processor", platform.processor())
134         #
135         if sys.platform.startswith('linux'):
136             if hasattr(platform, 'linux_distribution'):
137                 __msg += "\n%s%30s : %s"%(__prefix,
138                     "platform.linux_distribution", str(platform.linux_distribution()))  # noqa: E128
139             elif hasattr(platform, 'dist'):
140                 __msg += "\n%s%30s : %s"%(__prefix,
141                     "platform.dist", str(platform.dist()))  # noqa: E128
142         elif sys.platform.startswith('darwin'):
143             if hasattr(platform, 'mac_ver'):
144                 # https://fr.wikipedia.org/wiki/MacOS
145                 __macosxv10 = {
146                     '0' : 'Cheetah',      '1' : 'Puma',        '2' : 'Jaguar',         # noqa: E241,E203
147                     '3' : 'Panther',      '4' : 'Tiger',       '5' : 'Leopard',        # noqa: E241,E203
148                     '6' : 'Snow Leopard', '7' : 'Lion',        '8' : 'Mountain Lion',  # noqa: E241,E203
149                     '9' : 'Mavericks',    '10': 'Yosemite',    '11': 'El Capitan',     # noqa: E241,E203
150                     '12': 'Sierra',       '13': 'High Sierra', '14': 'Mojave',         # noqa: E241,E203
151                     '15': 'Catalina',
152                 }
153                 for key in __macosxv10:
154                     __details = platform.mac_ver()[0].split('.')
155                     if (len(__details) > 0) and (__details[1] == key):
156                         __msg += "\n%s%30s : %s"%(__prefix,
157                             "platform.mac_ver", str(platform.mac_ver()[0] + "(" + __macosxv10[key] + ")"))  # noqa: E128
158                 __macosxv11 = {
159                     '11': 'Big Sur',      '12': 'Monterey',    '13': 'Ventura',  # noqa: E241
160                     '14': 'Sonoma',
161                 }
162                 for key in __macosxv11:
163                     __details = platform.mac_ver()[0].split('.')
164                     if (__details[0] == key):
165                         __msg += "\n%s%30s : %s"%(__prefix,
166                             "platform.mac_ver", str(platform.mac_ver()[0] + "(" + __macosxv11[key] + ")"))  # noqa: E128
167             elif hasattr(platform, 'dist'):
168                 __msg += "\n%s%30s : %s"%(__prefix, "platform.dist", str(platform.dist()))
169         elif os.name == 'nt':
170             __msg += "\n%s%30s : %s"%(__prefix, "platform.win32_ver", platform.win32_ver()[1])
171         #
172         __msg += "\n"
173         __msg += "\n%s%30s : %s"%(__prefix, "platform.python_implementation", platform.python_implementation())
174         __msg += "\n%s%30s : %s"%(__prefix, "sys.executable", sys.executable)
175         __msg += "\n%s%30s : %s"%(__prefix, "sys.version", sys.version.replace('\n', ''))
176         __msg += "\n%s%30s : %s"%(__prefix, "sys.getfilesystemencoding", str(sys.getfilesystemencoding()))
177         if sys.version_info.major == 3 and sys.version_info.minor < 11:  # Python 3.10
178             __msg += "\n%s%30s : %s"%(__prefix, "locale.getdefaultlocale", str(locale.getdefaultlocale()))
179         else:
180             __msg += "\n%s%30s : %s"%(__prefix, "locale.getlocale", str(locale.getlocale()))
181         __msg += "\n"
182         __msg += "\n%s%30s : %s"%(__prefix, "os.cpu_count", os.cpu_count())
183         if hasattr(os, 'sched_getaffinity'):
184             __msg += "\n%s%30s : %s"%(__prefix, "len(os.sched_getaffinity(0))", len(os.sched_getaffinity(0)))
185         else:
186             __msg += "\n%s%30s : %s"%(__prefix, "len(os.sched_getaffinity(0))", "Unsupported on this platform")
187         __msg += "\n"
188         __msg += "\n%s%30s : %s"%(__prefix, "platform.node", platform.node())
189         __msg += "\n%s%30s : %s"%(__prefix, "socket.getfqdn", socket.getfqdn())
190         __msg += "\n%s%30s : %s"%(__prefix, "os.path.expanduser", os.path.expanduser('~'))
191         return __msg
192
193     def getApplicationInformation(self, __prefix=""):
194         __msg  = ""
195         __msg += "\n%s%30s : %s"%(__prefix, "ADAO version", self.getVersion())
196         __msg += "\n"
197         __msg += "\n%s%30s : %s"%(__prefix, "Python version", self.getPythonVersion())
198         __msg += "\n%s%30s : %s"%(__prefix, "Numpy version", self.getNumpyVersion())
199         __msg += "\n%s%30s : %s"%(__prefix, "Scipy version", self.getScipyVersion())
200         __msg += "\n%s%30s : %s"%(__prefix, "NLopt version", self.getNloptVersion())
201         __msg += "\n%s%30s : %s"%(__prefix, "MatplotLib version", self.getMatplotlibVersion())
202         __msg += "\n%s%30s : %s"%(__prefix, "GnuplotPy version", self.getGnuplotVersion())
203         __msg += "\n%s%30s : %s"%(__prefix, "Sphinx version", self.getSphinxVersion())
204         __msg += "\n%s%30s : %s"%(__prefix, "Fmpy version", self.getFmpyVersion())
205         return __msg
206
207     def getAllInformation(self, __prefix="", __title="Whole system information"):
208         __msg  = ""
209         if len(__title) > 0:
210             __msg += "\n" + "=" * 80 + "\n" + __title + "\n" + "=" * 80 + "\n"
211         __msg += self.getSystemInformation(__prefix)
212         __msg += "\n"
213         __msg += self.getApplicationInformation(__prefix)
214         return __msg
215
216     def getPythonVersion(self):
217         "Retourne la version de python disponible"
218         return ".".join([str(x) for x in sys.version_info[0:3]])  # map(str,sys.version_info[0:3]))
219
220     # Tests des modules système
221
222     def _has_numpy(self):
223         try:
224             import numpy  # noqa: F401
225             has_numpy = True
226         except ImportError:
227             raise ImportError("Numpy is not available, despites the fact it is mandatory.")
228         return has_numpy
229     has_numpy = property(fget = _has_numpy)
230
231     def _has_scipy(self):
232         try:
233             import scipy
234             import scipy.version
235             import scipy.optimize  # noqa: F401
236             has_scipy = True
237         except ImportError:
238             has_scipy = False
239         return has_scipy
240     has_scipy = property(fget = _has_scipy)
241
242     def _has_matplotlib(self):
243         try:
244             import matplotlib  # noqa: F401
245             has_matplotlib = True
246         except ImportError:
247             has_matplotlib = False
248         return has_matplotlib
249     has_matplotlib = property(fget = _has_matplotlib)
250
251     def _has_sphinx(self):
252         try:
253             import sphinx  # noqa: F401
254             has_sphinx = True
255         except ImportError:
256             has_sphinx = False
257         return has_sphinx
258     has_sphinx = property(fget = _has_sphinx)
259
260     def _has_nlopt(self):
261         try:
262             import nlopt  # noqa: F401
263             has_nlopt = True
264         except ImportError:
265             has_nlopt = False
266         return has_nlopt
267     has_nlopt = property(fget = _has_nlopt)
268
269     def _has_sdf(self):
270         try:
271             import sdf  # noqa: F401
272             has_sdf = True
273         except ImportError:
274             has_sdf = False
275         return has_sdf
276     has_sdf = property(fget = _has_sdf)
277
278     def _has_fmpy(self):
279         try:
280             import fmpy  # noqa: F401
281             has_fmpy = True
282         except ImportError:
283             has_fmpy = False
284         return has_fmpy
285     has_fmpy = property(fget = _has_fmpy)
286
287     def _has_buildingspy(self):
288         try:
289             import buildingspy  # noqa: F401
290             has_buildingspy = True
291         except ImportError:
292             has_buildingspy = False
293         return has_buildingspy
294     has_buildingspy = property(fget = _has_buildingspy)
295
296     def _has_control(self):
297         try:
298             import control  # noqa: F401
299             has_control = True
300         except ImportError:
301             has_control = False
302         return has_control
303     has_control = property(fget = _has_control)
304
305     def _has_modelicares(self):
306         try:
307             import modelicares  # noqa: F401
308             has_modelicares = True
309         except ImportError:
310             has_modelicares = False
311         return has_modelicares
312     has_modelicares = property(fget = _has_modelicares)
313
314     # Tests des modules locaux
315
316     def _has_gnuplot(self):
317         try:
318             import Gnuplot  # noqa: F401
319             has_gnuplot = True
320         except ImportError:
321             has_gnuplot = False
322         return has_gnuplot
323     has_gnuplot = property(fget = _has_gnuplot)
324
325     def _has_models(self):
326         try:
327             import Models  # noqa: F401
328             has_models = True
329         except ImportError:
330             has_models = False
331         return has_models
332     has_models = property(fget = _has_models)
333
334     def _has_linkmod(self):
335         try:
336             import LinkMod  # noqa: F401
337             has_linkmod = True
338         except ImportError:
339             has_linkmod = False
340         return has_linkmod
341     has_linkmod = property(fget = _has_linkmod)
342
343     # Versions
344
345     def getNumpyVersion(self):
346         "Retourne la version de numpy disponible"
347         import numpy.version
348         return numpy.version.version
349
350     def getScipyVersion(self):
351         "Retourne la version de scipy disponible"
352         if self.has_scipy:
353             import scipy
354             __version = scipy.version.version
355         else:
356             __version = "0.0.0"
357         return __version
358
359     def getMatplotlibVersion(self):
360         "Retourne la version de matplotlib disponible"
361         if self.has_matplotlib:
362             import matplotlib
363             __version = matplotlib.__version__
364         else:
365             __version = "0.0.0"
366         return __version
367
368     def getGnuplotVersion(self):
369         "Retourne la version de gnuplotpy disponible"
370         if self.has_gnuplot:
371             import Gnuplot
372             __version = Gnuplot.__version__
373         else:
374             __version = "0.0"
375         return __version
376
377     def getSphinxVersion(self):
378         "Retourne la version de sphinx disponible"
379         if self.has_sphinx:
380             import sphinx
381             __version = sphinx.__version__
382         else:
383             __version = "0.0.0"
384         return __version
385
386     def getNloptVersion(self):
387         "Retourne la version de nlopt disponible"
388         if self.has_nlopt:
389             import nlopt
390             __version = "%s.%s.%s"%(
391                 nlopt.version_major(),
392                 nlopt.version_minor(),
393                 nlopt.version_bugfix(),
394             )
395         else:
396             __version = "0.0.0"
397         return __version
398
399     def getSdfVersion(self):
400         "Retourne la version de sdf disponible"
401         if self.has_sdf:
402             import sdf
403             __version = sdf.__version__
404         else:
405             __version = "0.0.0"
406         return __version
407
408     def getFmpyVersion(self):
409         "Retourne la version de fmpy disponible"
410         if self.has_fmpy:
411             import fmpy
412             __version = fmpy.__version__
413         else:
414             __version = "0.0.0"
415         return __version
416
417     def getCurrentMemorySize(self):
418         "Retourne la taille mémoire courante utilisée"
419         return 1
420
421     def MaximumPrecision(self):
422         "Retourne la précision maximale flottante pour Numpy"
423         import numpy
424         try:
425             numpy.array([1.,], dtype='float128')
426             mfp = 'float128'
427         except Exception:
428             mfp = 'float64'
429         return mfp
430
431     def MachinePrecision(self):
432         # Alternative sans module :
433         # eps = 2.38
434         # while eps > 0:
435         #     old_eps = eps
436         #     eps = (1.0 + eps/2) - 1.0
437         return sys.float_info.epsilon
438
439     def __str__(self):
440         import daCore.version as dav
441         return "%s %s (%s)"%(dav.name, dav.version, dav.date)
442
443 # ==============================================================================
444 def vt( __version ):
445     "Version transformée pour comparaison robuste, obtenue comme un tuple"
446     serie = []
447     for sv in re.split("[_.+-]", __version):
448         serie.append(sv.zfill(6))
449     return tuple(serie)
450
451 def isIterable( __sequence, __check = False, __header = "" ):
452     """
453     Vérification que l'argument est un itérable interne.
454     Remarque : pour permettre le test correct en MultiFonctions,
455     - Ne pas accepter comme itérable un "numpy.ndarray"
456     - Ne pas accepter comme itérable avec hasattr(__sequence, "__iter__")
457     """
458     if isinstance( __sequence, (list, tuple, map, dict) ):
459         __isOk = True
460     elif type(__sequence).__name__ in ('generator', 'range'):
461         __isOk = True
462     elif "_iterator" in type(__sequence).__name__:
463         __isOk = True
464     elif "itertools" in str(type(__sequence)):
465         __isOk = True
466     else:
467         __isOk = False
468     if __check and not __isOk:
469         raise TypeError("Not iterable or unkown input type%s: %s"%(__header, type(__sequence),))
470     return __isOk
471
472 def date2int( __date: str, __lang="FR" ):
473     """
474     Fonction de secours, conversion pure : dd/mm/yy hh:mm ---> int(yyyymmddhhmm)
475     """
476     __date = __date.strip()
477     if __date.count('/') == 2 and __date.count(':') == 0 and __date.count(' ') == 0:
478         d, m, y = __date.split("/")
479         __number = (10**4) * int(y) + (10**2) * int(m) + int(d)
480     elif __date.count('/') == 2 and __date.count(':') == 1 and __date.count(' ') > 0:
481         part1, part2 = __date.split()
482         d, m, y = part1.strip().split("/")
483         h, n = part2.strip().split(":")
484         __number = (10**8) * int(y) + (10**6) * int(m) + (10**4) * int(d) + (10**2) * int(h) + int(n)
485     else:
486         raise ValueError("Cannot convert \"%s\" as a D/M/Y H:M date"%__date)
487     return __number
488
489 def vfloat(__value: numpy.ndarray):
490     """
491     Conversion en flottant d'un vecteur de taille 1 et de dimensions quelconques
492     """
493     if hasattr(__value, "size") and __value.size == 1:
494         return float(__value.flat[0])
495     elif isinstance(__value, (float, int)):
496         return float(__value)
497     else:
498         raise ValueError("Error in converting multiple float values from array when waiting for only one")
499
500 def strvect2liststr( __strvect ):
501     """
502     Fonction de secours, conversion d'une chaîne de caractères de
503     représentation de vecteur en une liste de chaînes de caractères de
504     représentation de flottants
505     """
506     for st in ("array", "matrix", "list", "tuple", "[", "]", "(", ")"):
507         __strvect = __strvect.replace(st, "")  # Rien
508     for st in (",", ";"):
509         __strvect = __strvect.replace(st, " ")  # Blanc
510     return __strvect.split()
511
512 def strmatrix2liststr( __strvect ):
513     """
514     Fonction de secours, conversion d'une chaîne de caractères de
515     représentation de matrice en une liste de chaînes de caractères de
516     représentation de flottants
517     """
518     for st in ("array", "matrix", "list", "tuple", "[", "(", "'", '"'):
519         __strvect = __strvect.replace(st, "")  # Rien
520     __strvect = __strvect.replace(",", " ")  # Blanc
521     for st in ("]", ")"):
522         __strvect = __strvect.replace(st, ";")  # "]" et ")" par ";"
523     __strvect = re.sub(r';\s*;', r';', __strvect)
524     __strvect = __strvect.rstrip(";")  # Après ^ et avant v
525     __strmat = [__l.split() for __l in __strvect.split(";")]
526     return __strmat
527
528 def checkFileNameConformity( __filename, __warnInsteadOfPrint=True ):
529     if sys.platform.startswith("win") and len(__filename) > 256:
530         __conform = False
531         __msg = (
532             " For some shared or older file systems on Windows, a file " + \
533             "name longer than 256 characters can lead to access problems." + \
534             "\n  The name of the file in question is the following:" + \
535             "\n  %s")%(__filename,)
536         if __warnInsteadOfPrint:
537             logging.warning(__msg)
538         else:
539             print(__msg)
540     else:
541         __conform = True
542     #
543     return __conform
544
545 def checkFileNameImportability( __filename, __warnInsteadOfPrint=True ):
546     if str(__filename).count(".") > 1:
547         __conform = False
548         __msg = (
549             " The file name contains %i point(s) before the extension " + \
550             "separator, which can potentially lead to problems when " + \
551             "importing this file into Python, as it can then be recognized " + \
552             "as a sub-module (generating a \"ModuleNotFoundError\"). If it " + \
553             "is intentional, make sure that there is no module with the " + \
554             "same name as the part before the first point, and that there is " + \
555             "no \"__init__.py\" file in the same directory." + \
556             "\n  The name of the file in question is the following:" + \
557             "\n  %s")%(int(str(__filename).count(".") - 1), __filename)
558         if __warnInsteadOfPrint is None:
559             pass
560         elif __warnInsteadOfPrint:
561             logging.warning(__msg)
562         else:
563             print(__msg)
564     else:
565         __conform = True
566     #
567     return __conform
568
569 # ==============================================================================
570 class SystemUsage(object):
571     """
572     Permet de récupérer les différentes tailles mémoires du process courant
573     """
574     __slots__ = ()
575     #
576     # Le module resource renvoie 0 pour les tailles mémoire. On utilise donc
577     # plutôt : http://code.activestate.com/recipes/286222/ et Wikipedia
578     #
579     _proc_status = '/proc/%d/status' % os.getpid()
580     _memo_status = '/proc/meminfo'
581     _scale = {
582         'o'  : 1.0,     # Multiples SI de l'octet          # noqa: E203
583         'ko' : 1.e3,                                       # noqa: E203
584         'Mo' : 1.e6,                                       # noqa: E203
585         'Go' : 1.e9,                                       # noqa: E203
586         'kio': 1024.0,  # Multiples binaires de l'octet    # noqa: E203
587         'Mio': 1024.0 * 1024.0,                            # noqa: E203
588         'Gio': 1024.0 * 1024.0 * 1024.0,                   # noqa: E203
589         'B'  : 1.0,     # Multiples binaires du byte=octet # noqa: E203
590         'kB' : 1024.0,                                     # noqa: E203
591         'MB' : 1024.0 * 1024.0,                            # noqa: E203
592         'GB' : 1024.0 * 1024.0 * 1024.0,                   # noqa: E203
593     }
594
595     def __init__(self):
596         "Sans effet"
597         pass
598
599     def _VmA(self, VmKey, unit):
600         "Lecture des paramètres mémoire de la machine"
601         try:
602             t = open(self._memo_status)
603             v = t.read()
604             t.close()
605         except IOError:
606             return 0.0            # non-Linux?
607         i = v.index(VmKey)        # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
608         v = v[i:].split(None, 3)  # whitespace
609         if len(v) < 3:
610             return 0.0            # invalid format?
611         # convert Vm value to bytes
612         mem = float(v[1]) * self._scale[v[2]]
613         return mem / self._scale[unit]
614
615     def getAvailablePhysicalMemory(self, unit="o"):
616         "Renvoie la mémoire physique utilisable en octets"
617         return self._VmA('MemTotal:', unit)
618
619     def getAvailableSwapMemory(self, unit="o"):
620         "Renvoie la mémoire swap utilisable en octets"
621         return self._VmA('SwapTotal:', unit)
622
623     def getAvailableMemory(self, unit="o"):
624         "Renvoie la mémoire totale (physique+swap) utilisable en octets"
625         return self._VmA('MemTotal:', unit) + self._VmA('SwapTotal:', unit)
626
627     def getUsableMemory(self, unit="o"):
628         """Renvoie la mémoire utilisable en octets
629         Rq : il n'est pas sûr que ce décompte soit juste...
630         """
631         return self._VmA('MemFree:', unit) + self._VmA('SwapFree:', unit) + \
632             self._VmA('Cached:', unit) + self._VmA('SwapCached:', unit)
633
634     def _VmB(self, VmKey, unit):
635         "Lecture des paramètres mémoire du processus"
636         try:
637             t = open(self._proc_status)
638             v = t.read()
639             t.close()
640         except IOError:
641             return 0.0            # non-Linux?
642         i = v.index(VmKey)        # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
643         v = v[i:].split(None, 3)  # whitespace
644         if len(v) < 3:
645             return 0.0            # invalid format?
646         # convert Vm value to bytes
647         mem = float(v[1]) * self._scale[v[2]]
648         return mem / self._scale[unit]
649
650     def getUsedMemory(self, unit="o"):
651         "Renvoie la mémoire résidente utilisée en octets"
652         return self._VmB('VmRSS:', unit)
653
654     def getVirtualMemory(self, unit="o"):
655         "Renvoie la mémoire totale utilisée en octets"
656         return self._VmB('VmSize:', unit)
657
658     def getUsedStacksize(self, unit="o"):
659         "Renvoie la taille du stack utilisé en octets"
660         return self._VmB('VmStk:', unit)
661
662     def getMaxUsedMemory(self, unit="o"):
663         "Renvoie la mémoire résidente maximale mesurée"
664         return self._VmB('VmHWM:', unit)
665
666     def getMaxVirtualMemory(self, unit="o"):
667         "Renvoie la mémoire totale maximale mesurée"
668         return self._VmB('VmPeak:', unit)
669
670 # ==============================================================================
671 if __name__ == "__main__":
672     print("\n AUTODIAGNOSTIC\n")