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