Salome HOME
Deal with float input in MemRepr
[modules/kernel.git] / src / Container / SALOME_ContainerHelper.py
1 #  -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2023-2024  CEA, EDF
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20
21 from collections import defaultdict
22
23 import pickle
24
25 class ScriptExecInfo:
26     @classmethod
27     def GetRepresentationOfTimeDelta(cls,endTime, startTime):
28        if endTime is None and startTime is None:
29           return "not measured"
30        td = endTime - startTime
31        import time
32        ts_of_td = time.gmtime(td.total_seconds())
33        return "{}.{:06d}".format(time.strftime("%H:%M:%S",ts_of_td),td.microseconds)
34     
35     @classmethod
36     def MemRepr(cls,memInByte):
37       m = int( memInByte )
38       UNITS=["B","kB","MB","GB"]
39       remain = 0
40       oss = ""
41       for i in range( len(UNITS) ):
42           if m<1024:
43               oss = "{:03d}".format( int( (remain/1024)*1000 ) )
44               oss = "{}.{} {}".format(m,oss,UNITS[i])
45               return oss
46           else:
47               if i!=3:
48                   remain = m%1024
49                   m//=1024
50       return "{} {}".format(m,UNITS[3])
51     
52     @classmethod
53     def SpeedRepr(cls,memInBytePerS):
54        return "{}/s".format( cls.MemRepr(memInBytePerS) )
55
56     def __init__(self):
57       self._measure_time_resolution_ms = None
58       self._cpu_mem_during_exec = None
59       self._start_exec_time = None
60       self._end_exec_time = None
61       self._start_input_time = None
62       self._end_input_time = None
63       self._start_output_time = None
64       self._end_output_time = None
65       self._input_mem = 0
66       self._input_hdd_mem = None
67       self._output_mem = 0
68       self._output_hdd_mem = None
69       self._start_pos_log = None
70       self._stop_pos_log = None
71       self._freestyle_log = []
72
73     @property
74     def freestyle(self):
75        return self._freestyle_log
76     
77     @freestyle.setter
78     def freestyle(self, value):
79        self._freestyle_log.append( value )
80
81     @property
82     def measureTimeResolution(self):
83       return self._measure_time_resolution_ms
84     
85     @measureTimeResolution.setter
86     def measureTimeResolution(self, value):
87       self._measure_time_resolution_ms = value
88
89     @property
90     def tracePosStart(self):
91       return self._start_pos_log
92     
93     @tracePosStart.setter
94     def tracePosStart(self,value):
95       self._start_pos_log = value
96
97     @property
98     def tracePosStop(self):
99       return self._stop_pos_log
100     
101     @tracePosStop.setter
102     def tracePosStop(self,value):
103       self._stop_pos_log = value
104       
105     @property
106     def CPUMemDuringExec(self):
107       return self._cpu_mem_during_exec
108     
109     @CPUMemDuringExec.setter
110     def CPUMemDuringExec(self,value):
111       self._cpu_mem_during_exec = value
112
113     @property
114     def CPUMemDuringExecStr(self):
115       return [(a,ScriptExecInfo.MemRepr(b)) for a,b in self._cpu_mem_during_exec.data]
116
117     @property
118     def inputMem(self):
119       return self._input_mem
120     
121     @inputMem.setter
122     def inputMem(self,value):
123       self._input_mem = value
124        
125     @property
126     def inputMemStr(self):
127       return ScriptExecInfo.MemRepr( self.inputMem )
128     
129     @property
130     def outputMem(self):
131       return self._output_mem
132     
133     @outputMem.setter
134     def outputMem(self,value):
135       self._output_mem = value
136        
137     @property
138     def outputMemStr(self):
139       return ScriptExecInfo.MemRepr( self.outputMem )
140     
141     def inputReadHDDSize(self):
142        return self.inputHDDMem.getSizeOfFileRead()
143     
144     def inputReadHDDSizeRepr(self):
145        return ScriptExecInfo.MemRepr( self.inputReadHDDSize() )
146     
147     def inputReadHDDSpeed(self):
148        return self.inputReadHDDSize() / ( self.endInputTime - self.startInputTime ).total_seconds()
149     
150     def inputReadHDDSpeedRepr(self):
151        return ScriptExecInfo.SpeedRepr( self.inputReadHDDSpeed() )
152     
153     def outputWriteHDDSize(self):
154        return self.outputHDDMem.getSizeOfFileRead()
155     
156     def outputWriteHDDSizeRepr(self):
157        return ScriptExecInfo.MemRepr( self.outputWriteHDDSize() )
158
159     def outputWriteHDDSpeed(self):
160       return self.outputWriteHDDSize() / ( self.endOutputTime - self.startOutputTime ).total_seconds()
161     
162     def outputWriteHDDSpeedRepr(self):
163       return ScriptExecInfo.SpeedRepr( self.outputWriteHDDSpeed() )
164     
165     @property
166     def inputHDDMem(self):
167       return self._input_hdd_mem
168     
169     @inputHDDMem.setter
170     def inputHDDMem(self,value):
171       self._input_hdd_mem = value
172
173     @property
174     def inputHDDMemStr(self):
175       if self._input_hdd_mem is None:
176          return "not computed"
177       return " ".join( [ ScriptExecInfo.MemRepr( elt.getSizeOfFileRead() ) for elt in self._input_hdd_mem] )
178     
179     @property
180     def outputHDDMem(self):
181       return self._output_hdd_mem
182     
183     @outputHDDMem.setter
184     def outputHDDMem(self,value):
185       self._output_hdd_mem = value
186
187     @property
188     def outputHDDMemStr(self):
189       if self._output_hdd_mem is None:
190          return "not computed"
191       return " ".join( [ ScriptExecInfo.MemRepr( elt.getSizeOfFileRead() ) for elt in self._output_hdd_mem] )
192
193     @property
194     def startInputTime(self):
195       return self._start_input_time
196     
197     @startInputTime.setter
198     def startInputTime(self,value):
199       self._start_input_time = value
200
201     @property
202     def endInputTime(self):
203       return self._end_input_time
204     
205     @endInputTime.setter
206     def endInputTime(self,value):
207       self._end_input_time = value
208
209     @property
210     def startExecTime(self):
211       return self._start_exec_time
212     
213     @startExecTime.setter
214     def startExecTime(self,value):
215       self._start_exec_time = value
216
217     @property
218     def endExecTime(self):
219       return self._end_exec_time
220     
221     @endExecTime.setter
222     def endExecTime(self,value):
223       self._end_exec_time = value
224
225     @property
226     def execTime(self):
227       if ( self.endExecTime is not None ) and (self.startExecTime is not None):
228         return self.endExecTime - self.startExecTime
229       return None
230     
231     @property
232     def fullExecTime(self):
233       return self.endOutputTime - self.startInputTime
234
235     @property
236     def startOutputTime(self):
237       return self._start_output_time
238     
239     @startOutputTime.setter
240     def startOutputTime(self,value):
241       self._start_output_time = value
242
243     @property
244     def endOutputTime(self):
245       return self._end_output_time
246     
247     @endOutputTime.setter
248     def endOutputTime(self,value):
249       self._end_output_time = value
250
251     @property
252     def execTimeStr(self):
253        return ScriptExecInfo.GetRepresentationOfTimeDelta(self.endExecTime,self.startExecTime)
254     
255     @property
256     def inputTimeStr(self):
257        return ScriptExecInfo.GetRepresentationOfTimeDelta(self.endInputTime,self.startInputTime)
258     
259     @property
260     def outputTimeStr(self):
261        return ScriptExecInfo.GetRepresentationOfTimeDelta(self.endOutputTime,self.startOutputTime)
262
263     def __str__(self):
264       CPUMemDuringExecForStr = self.CPUMemDuringExecStr
265       if len( CPUMemDuringExecForStr ) > 30:
266          CPUMemDuringExecForStr = "{} ...".format( str(CPUMemDuringExecForStr[:30]) )
267       else:
268          CPUMemDuringExecForStr = str( CPUMemDuringExecForStr )
269       return """start exec time = {self.startExecTime}
270 end exec time = {self.endExecTime}
271 exec_time = {self.execTimeStr}
272 Measure time resolution = {self.measureTimeResolution} ms
273 CPU and mem monitoring = {CPUMemDuringExecForStr}
274 input unpickling and ev load from disk time = {self.inputTimeStr}
275 output serialization and ev write to disk time = {self.outputTimeStr}
276 input memory size before exec (MemoryPeak 2x) = {self.inputMemStr}
277 input memory size from HDD = {self.inputHDDMemStr}
278 output memory size after exec (MemoryPeak 2x) = {self.outputMemStr}
279 output memory size from HDD = {self.outputHDDMemStr}
280 Start position in log = {self.tracePosStart}
281 End position in log = {self.tracePosStop}""".format(**locals())
282
283 class ScriptExecInfoDeco:
284   def __init__(self, eff, father):
285     self._eff = eff
286     self._father = father
287   @property
288   def father(self):
289     return self._father
290   def get(self):
291     return self._eff
292   def __getitem__(self,i):
293     return self._eff[i]
294   def __str__(self):
295     return self._eff.__str__()
296   def __repr__(self):
297     return self._eff.__repr__()
298   def log(self):
299     with open(self.father.father.logfile,"rb") as f:
300        cont = f.read()
301     return cont[self._eff.tracePosStart:self._eff.tracePosStop].decode()
302   @property
303   def nodeName(self):
304     return self.father.get().nodeName
305   @property
306   def code(self):
307     return self.father.code
308   @property
309   def ns_entry(self):
310     return self.father.father.ns_entry
311   @property
312   def computingNode(self):
313     return self.father.computingNode
314   
315   @property
316   def freestyle(self):
317       return self.get().freestyle
318   
319   @property
320   def measureTimeResolution(self):
321     return self.get().measureTimeResolution
322     
323   @property
324   def CPUMemDuringExec(self):
325     return self.get().CPUMemDuringExec
326
327   @property
328   def inputMem(self):
329     return self.get().inputMem
330   
331   @property
332   def outputMem(self):
333     return self.get().outputMem
334   
335   @property
336   def inputHDDMem(self):
337     return self.get().inputHDDMem
338   
339   @property
340   def outputHDDMem(self):
341     return self.get().outputHDDMem
342   
343   def inputReadHDDSize(self):
344     return self.get().inputReadHDDSize()
345   
346   def inputReadHDDSizeRepr(self):
347     return self.get().inputReadHDDSizeRepr()
348   
349   def inputReadHDDSpeed(self):
350     return self.get().inputReadHDDSpeed()
351   
352   def inputReadHDDSpeedRepr(self):
353     return self.get().inputReadHDDSpeedRepr()
354   
355   def outputWriteHDDSize(self):
356     return self.get().outputWriteHDDSize()
357   
358   def outputWriteHDDSizeRepr(self):
359     return self.get().outputWriteHDDSizeRepr()
360   
361   def outputWriteHDDSpeed(self):
362     return self.get().outputWriteHDDSpeed()
363   
364   def outputWriteHDDSpeedRepr(self):
365     return self.get().outputWriteHDDSpeedRepr()
366
367   @property
368   def startInputTime(self):
369     return self.get().startInputTime
370
371   @property
372   def endInputTime(self):
373     return self.get().endInputTime
374
375   @property
376   def startExecTime(self):
377     return self.get().startExecTime
378
379   @property
380   def endExecTime(self):
381     return self.get().endExecTime
382
383   @property
384   def execTime(self):
385     return self.get().execTime
386   
387   @property
388   def fullExecTime(self):
389      return self.get().fullExecTime
390
391   @property
392   def startOutputTime(self):
393     return self.get().startOutputTime
394
395   @property
396   def endOutputTime(self):
397     return self.get().endOutputTime
398
399 class ScriptInfoAbstract:
400   def __init__(self, scriptPtr):
401       self._node_name = scriptPtr.getName()
402       self._code = scriptPtr.getCode()
403       self._exec = [pickle.loads(elt.getObj()) for elt in scriptPtr.listOfExecs()]
404
405   @property
406   def execs(self):
407       return self._exec
408
409   @property
410   def nodeName(self):
411       return self._node_name
412
413   @property
414   def code(self):
415       return self._code
416   
417   @code.setter
418   def code(self,value):
419       self._code = value
420
421   def __len__(self):
422       return len( self._exec )
423   
424   def __getitem__(self,i):
425       return self._exec[i]
426
427   def __str__(self):
428       return """name = {self.nodeName}\ncode = {self.code}\nexecs = {self.execs}""".format(**locals())
429   
430   def __repr__(self):
431       return """ScriptInfo \"{self.nodeName}\"""".format(**locals())
432   
433 class ScriptInfoClt(ScriptInfoAbstract):
434   def __init__(self, scriptPtr):
435       self._node_name = scriptPtr.getName()
436       self._code = scriptPtr.getCode()
437       self._exec = [pickle.loads(elt.getObj()) for elt in scriptPtr.listOfExecs()]
438
439 class ScriptInfo(ScriptInfoAbstract):
440   def __init__(self, nodeName, code, execs):
441       self._node_name = nodeName
442       self._code = code
443       self._exec = execs
444
445 class ScriptInfoDeco:
446   def __init__(self, eff, father):
447     self._eff = eff
448     self._father = father
449   @property
450   def father(self):
451     return self._father
452   def get(self):
453     return self._eff
454   @property
455   def nodeName(self):
456     return self.get().nodeName
457   @property
458   def code(self):
459     return self.get().code
460   @property
461   def ns_entry(self):
462     return self.father.ns_entry
463   @property
464   def computingNode(self):
465     return self.father.computingNode
466   def __getitem__(self,i):
467     return ScriptExecInfoDeco( self._eff[i], self )
468   def __len__(self):
469     return self._eff.__len__()
470   def __str__(self):
471     return self._eff.__str__()
472   def __repr__(self):
473     return self._eff.__repr__()
474
475 class ContainerLogInfoAbstract:
476   
477   @property
478   def log(self):
479     with open(self.logfile,"rb") as f:
480        cont = f.read()
481     return cont.decode()
482
483   @property
484   def ns_entry(self):
485     return self._ns_entry
486   
487   @property
488   def logfile(self):
489     return self._log_file
490   
491   @property
492   def computingNode(self):
493     return ContainerLogInfoAbstract.ComputingNodeFromNSEntry( self.ns_entry )
494   
495   def __len__(self):
496     return len( self._scripts )
497   
498   def __getitem__(self,i):
499     return ScriptInfoDeco( self._scripts[i], self)
500   
501   def __str__(self):
502     return """NS entry = {self.ns_entry} LogFile = {self.logfile}""".format(**locals())
503   
504   @classmethod
505   def ComputingNodeFromNSEntry(cls, nsEntry):
506     return nsEntry.split("/")[2]
507   
508 class ContainerLogInfoClt(ContainerLogInfoAbstract):
509   def __init__(self,contLogPtr):
510     self._log_file = contLogPtr.getLogFile()
511     self._ns_entry = contLogPtr.getContainerEntryInNS()
512     self._scripts = [ScriptInfoClt(elt) for elt in contLogPtr.listOfScripts()]
513     
514 class ContainerLogInfo(ContainerLogInfoAbstract):
515   def __init__(self, nsEntry, logFile, scripts):
516      self._log_file = logFile
517      self._ns_entry = nsEntry
518      self._scripts = scripts
519
520 from abc import ABC, abstractmethod
521
522 class InOutputObjVisitorAbstract(ABC):
523   def __init__(self):
524       self._cur_obj = None
525       self._data = []
526
527   def enter(self):
528       self._cur_obj = ObjMemModel()
529       return self._cur_obj
530   
531   def leave(self):
532       self._data.append( self._cur_obj )
533       self._cur_obj = None
534
535   def getSizeOfFileRead(self):
536       return sum( [elt.getSizeOfFileRead() for elt in self._data] )
537       
538   def visitor(self):
539       return self
540
541   def setHDDMem(self, v):
542       pass
543   
544   def setFileName(self, fileName):
545       pass
546
547   @abstractmethod
548   def getRepr(self):
549       pass
550
551 class InOutputObjVisitorIter:
552   def __init__(self, visitor):
553       self._visitor = visitor
554       self._current = 0
555
556   def __next__(self):
557       if self._current >= len(self._visitor._data):
558             raise StopIteration
559       else:
560         ret = self._visitor._data[ self._current ]
561         self._current += 1
562         return ret
563
564 class InOutputObjVisitor(InOutputObjVisitorAbstract):
565   def __init__(self):
566       super().__init__()
567       
568   def getRepr(self):
569       return self.getSizeOfFileRead()
570   
571   def __iter__(self):
572      return InOutputObjVisitorIter(self)
573
574 class ObjMemModel(InOutputObjVisitorAbstract):
575   def __init__(self):
576       super().__init__()
577       self._hdd_mem = 0
578       self._file_name = None
579       
580   def setHDDMem(self, v):
581       self._hdd_mem = v
582       del self._data
583
584   def setFileName(self, fileName):
585       self._file_name = fileName
586       pass
587       
588   def getSizeOfFileRead(self):
589       if hasattr(self,"_data"):
590         return super().getSizeOfFileRead()
591       else:
592         return self._hdd_mem
593   
594   def getRepr(self):
595       return self.getSizeOfFileRead()
596
597 class FakeObjVisitor:
598   def setHDDMem(self, v):
599       pass
600   
601   def setFileName(self, fileName):
602       pass
603     
604   def visitor(self):
605       return None
606
607 class InOutputObjVisitorCM:
608   def __init__(self, visitor):
609      self._visitor = visitor
610   def __enter__(self):
611       if self._visitor:
612         r = self._visitor.enter()
613         return r
614       else:
615         return FakeObjVisitor()
616   def __exit__(self,exctype, exc, tb):
617       if self._visitor:
618         self._visitor.leave()
619       pass
620   
621 class OffsetType:
622   def __init__(self,i):
623     self._i = i
624   def __int__(self):
625     return self._i
626   def __iadd__(self,delta):
627     self._i += delta
628     return self
629
630 def unserializeInt(structData, offset):
631     from ctypes import c_int
632     sz_of_cint = 4
633     sz = c_int.from_buffer_copy( structData[int(offset):int(offset)+sz_of_cint] ).value
634     offset += sz_of_cint
635     return sz
636
637 def unserializeString(structData,offset):
638     sz = unserializeInt(structData,offset)
639     ret = structData[int(offset):int(offset)+sz].decode()
640     offset += sz
641     return ret
642
643 def unserializeContainerScriptExecPerfLog(structData, offset):
644     import pickle
645     sz = unserializeInt(structData,offset)
646     inst = None
647     if sz > 0:
648         inst = pickle.loads( structData[int(offset):int(offset)+sz] )
649     offset += sz
650     return inst
651
652 def unserializeContainerScriptPerfLog(structData, offset):
653     name = unserializeString(structData,offset)
654     code = unserializeString(structData,offset)
655     numberOfSessions = unserializeInt(structData,offset)
656     sessions = []
657     for _ in range(numberOfSessions):
658         session = unserializeContainerScriptExecPerfLog(structData,offset)
659         sessions.append( session )
660     return ScriptInfo(name,code,sessions)
661
662 def unserializeContainerPerfLog(structData, offset):
663     nsEntry = unserializeString(structData,offset)
664     logFile = unserializeString(structData,offset)
665     scripts = []
666     nbScripts = unserializeInt(structData,offset)
667     for _ in range(nbScripts):
668         script = unserializeContainerScriptPerfLog(structData,offset)
669         scripts.append( script )
670     return ContainerLogInfo(nsEntry,logFile,scripts)
671
672 def unserializeLogManager(structData):
673     offset = OffsetType(0)
674     numberOfScripts = unserializeInt(structData,offset)
675     logManagerInst = []
676     for _ in range(numberOfScripts):
677         containerPerfLogInst = unserializeContainerPerfLog(structData,offset)
678         logManagerInst.append( containerPerfLogInst )
679     if int(offset) != len(structData):
680         raise RuntimeError("Something went wrong during unserialization phase.")
681     return logManagerInst
682
683 def ListAllExecContainIn( listOfContainerLogInfo ):
684     """
685     For all ContainerLogInfo contained in listOfContainerLogInfo extract all ScriptExecInfo contained recursively
686     in it. This method filters all "side" executions like those positionning environment for exemple.
687
688     See also : ListAllExecFinishedContainIn
689
690     Args:
691     -----
692
693     listOfContainerLogInfo (list<ContainerLogInfo>) : instance typically returned by salome.LogManagerLoadFromFile
694
695     Returns
696     -------
697
698     list<ScriptExecInfoDeco> : all ScriptExecInfoDeco instance contained recursively in all input ContainerLogInfo instances
699
700     """
701     allexecs = sum( [sum( [[myexec for myexec in ps] for ps in cont],[] ) for cont in listOfContainerLogInfo], [] )
702     return [elt for elt in allexecs if elt.get() is not None]
703
704 def ListAllExecFinishedContainIn( listOfContainerLogInfo ):
705     """
706     For all ContainerLogInfo contained in listOfContainerLogInfo extract all ScriptExecInfo contained recursively
707     in it. This method filters all "side" executions like those positionning environment for exemple and those not finished.
708
709     See also : ListAllExecContainIn
710
711     Args:
712     -----
713
714     listOfContainerLogInfo (list<ContainerLogInfo>) : instance typically returned by salome.LogManagerLoadFromFile
715
716     Returns
717     -------
718
719     list<ScriptExecInfoDeco> : all ScriptExecInfoDeco instance contained recursively in all input ContainerLogInfo instances
720
721     """
722     beforeFiltering = ListAllExecContainIn( listOfContainerLogInfo )
723     return [elt for elt in beforeFiltering if elt.get().execTime is not None]
724
725 def IsExecTimeHigherThan( execInstDeco, limitDuration ):
726     """
727     Example of Usage :
728
729     [elt for elt in allexecs if IsExecTimeHigherThan(elt,datetime.timedelta(hours=1))]
730     
731     Args:
732     -----
733
734     execInstDeco (ScriptExecInfoDeco)
735     limitDuration (datetime.timedelta)  Ex (datetime.timedelta(hours=1))
736
737     """
738     if execInstDeco.get() is not None:
739         return execInstDeco.get().execTime > limitDuration
740     else:
741         return False
742     
743 def GetMaxTimeExec( listOfFinishedExecs ):
744     """
745     Returns the instance among listOfFinishedExecs that spends the max time to be executed
746
747     Args:
748     -----
749
750     listOfFinishedExecs ( list<ScriptExecInfoDeco> ) : instance of ScriptExecInfoDeco that have finished to be executed
751     Typically returned by ListAllExecFinishedContainIn
752     
753     Returns
754     -------
755
756     ScriptExecInfoDeco :
757     """
758     return listOfFinishedExecs[ max([(i,elt.execTime) for i,elt in enumerate( listOfFinishedExecs) ],key = lambda x : x[1])[0] ]
759
760 def GetMinTimeExec( listOfFinishedExecs ):
761     """
762     Returns the instance among listOfFinishedExecs that spends the min time to be executed
763
764     Args:
765     -----
766
767     listOfFinishedExecs ( list<ScriptExecInfoDeco> ) : instance of ScriptExecInfoDeco that have finished to be executed
768     Typically returned by ListAllExecFinishedContainIn
769     
770     Returns
771     -------
772
773     ScriptExecInfoDeco :
774     """
775     return listOfFinishedExecs[ min([(i,elt.execTime) for i,elt in enumerate( listOfFinishedExecs) ],key = lambda x : x[1])[0] ]
776
777 class DistriutionClass:
778     def __init__(self, begin, end, listOfExecs):
779         self._begin = begin
780         self._end = end
781         self._list_of_execs = sorted( listOfExecs, key = lambda x : x.execTime)
782     def __getitem__(self, *args):
783         return self._list_of_execs.__getitem__( *args )
784     @property
785     def begin(self):
786         return self._begin
787     @property
788     def end(self):
789         return self._end
790     @property
791     def listOfExecs(self):
792         return self._list_of_execs
793     @property
794     def size(self):
795         return len( self.listOfExecs )
796     @property
797     def reprGlobal(self):
798         return f"[{self.begin}->{self.end}] : {self.size} execs"
799
800 class DistributionOfExecs:
801     """
802     Class in charge to distribute execution log instance into equi-classes
803     """
804     def __init__(self, listOfFinishedExecs, nbOfClasses):
805         self._list_of_finished_execs = listOfFinishedExecs
806         self._nb_of_classes = nbOfClasses
807         self._classes = DistributionOfExecs.ComputeDistributionOfExecTime(self._list_of_finished_execs,self._nb_of_classes)
808     
809     def __getitem__(self, *args):
810         return self._classes.__getitem__( *args )
811     def reprOfExecs(self):
812         import numpy as np
813         cs = np.cumsum( [elt.size for elt in self._classes] )
814         ret = []
815         for i,(elt,cum_nb) in enumerate( zip(self._classes,cs) ):
816             ratio = (cum_nb / cs[-1])*100.0
817             ret.append( f"- For class {i} - {elt.reprGlobal} ( {ratio:.1f}% )" )
818         return "\n".join( ret )
819     @classmethod
820     def ComputeDistributionOfExecTime( cls, listOfFinishedExecs, nbOfClasses ):
821         maxt = GetMaxTimeExec( listOfFinishedExecs )
822         mint = GetMinTimeExec( listOfFinishedExecs )
823         deltaTime = ( maxt.execTime - mint.execTime ) / nbOfClasses
824         res = []
825         for i in range( nbOfClasses ):
826             begin = mint.execTime + i * deltaTime
827             end = mint.execTime + (i+1) * deltaTime
828             res.append( DistriutionClass(begin,end,[elt for elt in listOfFinishedExecs if elt.execTime >=begin and elt.execTime <= end]) )
829         return res