]>
Commit | Line | Data |
---|---|---|
1d506c26 | 1 | # Copyright (C) 2013-2024 Free Software Foundation, Inc. |
f27a1236 YQ |
2 | |
3 | # This program is free software; you can redistribute it and/or modify | |
4 | # it under the terms of the GNU General Public License as published by | |
5 | # the Free Software Foundation; either version 3 of the License, or | |
6 | # (at your option) any later version. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, | |
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | # GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License | |
14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | import time | |
17 | import os | |
18 | import gc | |
46f2c22e PA |
19 | import sys |
20 | ||
21 | # time.perf_counter() and time.process_time() were added in Python | |
22 | # 3.3, time.clock() was removed in Python 3.8. | |
23 | if sys.version_info < (3, 3, 0): | |
24 | time.perf_counter = time.clock | |
25 | time.process_time = time.clock | |
f27a1236 | 26 | |
13123da8 | 27 | |
f27a1236 YQ |
28 | class Measure(object): |
29 | """A class that measure and collect the interesting data for a given testcase. | |
30 | ||
31 | An instance of Measure has a collection of measurements, and each | |
32 | of them is to measure a given aspect, such as time and memory. | |
33 | """ | |
34 | ||
35 | def __init__(self, measurements): | |
36 | """Constructor of measure. | |
37 | ||
38 | measurements is a collection of Measurement objects. | |
39 | """ | |
40 | ||
41 | self.measurements = measurements | |
42 | ||
43 | def measure(self, func, id): | |
44 | """Measure the operations done by func with a collection of measurements.""" | |
45 | # Enable GC, force GC and disable GC before running test in order to reduce | |
46 | # the interference from GC. | |
47 | gc.enable() | |
48 | gc.collect() | |
49 | gc.disable() | |
50 | ||
51 | for m in self.measurements: | |
52 | m.start(id) | |
53 | ||
54 | func() | |
55 | ||
56 | for m in self.measurements: | |
57 | m.stop(id) | |
58 | ||
59 | gc.enable() | |
60 | ||
61 | def report(self, reporter, name): | |
62 | """Report the measured results.""" | |
63 | for m in self.measurements: | |
64 | m.report(reporter, name) | |
65 | ||
13123da8 | 66 | |
f27a1236 YQ |
67 | class Measurement(object): |
68 | """A measurement for a certain aspect.""" | |
69 | ||
70 | def __init__(self, name, result): | |
71 | """Constructor of Measurement. | |
72 | ||
73 | Attribute result is the TestResult associated with measurement. | |
74 | """ | |
13123da8 | 75 | self.name = name |
f27a1236 YQ |
76 | self.result = result |
77 | ||
78 | def start(self, id): | |
79 | """Abstract method to start the measurement.""" | |
80 | raise NotImplementedError("Abstract Method:start") | |
81 | ||
82 | def stop(self, id): | |
83 | """Abstract method to stop the measurement. | |
84 | ||
85 | When the measurement is stopped, we've got something, and | |
86 | record them in result. | |
87 | """ | |
88 | raise NotImplementedError("Abstract Method:stop.") | |
89 | ||
90 | def report(self, reporter, name): | |
91 | """Report the measured data by argument reporter.""" | |
92 | self.result.report(reporter, name + " " + self.name) | |
93 | ||
13123da8 | 94 | |
46f2c22e PA |
95 | class MeasurementPerfCounter(Measurement): |
96 | """Measurement on performance counter.""" | |
97 | ||
98 | # Measures time in fractional seconds, using a performance | |
99 | # counter, i.e. a clock with the highest available resolution to | |
100 | # measure a short duration. It includes time elapsed during sleep | |
101 | # and is system-wide. | |
102 | ||
103 | def __init__(self, result): | |
104 | super(MeasurementPerfCounter, self).__init__("perf_counter", result) | |
105 | self.start_time = 0 | |
106 | ||
107 | def start(self, id): | |
108 | self.start_time = time.perf_counter() | |
109 | ||
110 | def stop(self, id): | |
111 | perf_counter = time.perf_counter() - self.start_time | |
112 | self.result.record(id, perf_counter) | |
113 | ||
114 | ||
115 | class MeasurementProcessTime(Measurement): | |
116 | """Measurement on process time.""" | |
13123da8 | 117 | |
46f2c22e PA |
118 | # Measures the sum of the system and user CPU time of the current |
119 | # process. Does not include time elapsed during sleep. It is | |
120 | # process-wide by definition. | |
f27a1236 YQ |
121 | |
122 | def __init__(self, result): | |
46f2c22e | 123 | super(MeasurementProcessTime, self).__init__("process_time", result) |
f27a1236 YQ |
124 | self.start_time = 0 |
125 | ||
126 | def start(self, id): | |
46f2c22e | 127 | self.start_time = time.process_time() |
f27a1236 YQ |
128 | |
129 | def stop(self, id): | |
46f2c22e PA |
130 | process_time = time.process_time() - self.start_time |
131 | self.result.record(id, process_time) | |
13123da8 | 132 | |
f27a1236 YQ |
133 | |
134 | class MeasurementWallTime(Measurement): | |
135 | """Measurement on Wall time.""" | |
136 | ||
137 | def __init__(self, result): | |
138 | super(MeasurementWallTime, self).__init__("wall_time", result) | |
139 | self.start_time = 0 | |
140 | ||
141 | def start(self, id): | |
142 | self.start_time = time.time() | |
143 | ||
144 | def stop(self, id): | |
145 | wall_time = time.time() - self.start_time | |
13123da8 SM |
146 | self.result.record(id, wall_time) |
147 | ||
f27a1236 YQ |
148 | |
149 | class MeasurementVmSize(Measurement): | |
150 | """Measurement on memory usage represented by VmSize.""" | |
151 | ||
152 | def __init__(self, result): | |
153 | super(MeasurementVmSize, self).__init__("vmsize", result) | |
154 | ||
155 | def _compute_process_memory_usage(self, key): | |
156 | file_path = "/proc/%d/status" % os.getpid() | |
157 | try: | |
158 | t = open(file_path) | |
159 | v = t.read() | |
160 | t.close() | |
161 | except: | |
162 | return 0 | |
163 | i = v.index(key) | |
164 | v = v[i:].split(None, 3) | |
165 | if len(v) < 3: | |
166 | return 0 | |
167 | return int(v[1]) | |
168 | ||
169 | def start(self, id): | |
170 | pass | |
171 | ||
172 | def stop(self, id): | |
173 | memory_used = self._compute_process_memory_usage("VmSize:") | |
13123da8 | 174 | self.result.record(id, memory_used) |