summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAryaman Gupta <aryaman.gupta@windriver.com>2022-06-22 15:21:05 -0400
committerRichard Purdie <richard.purdie@linuxfoundation.org>2022-06-29 16:16:56 +0100
commit1125adc33b3696ffd351ffec9445f0c09b178fde (patch)
tree779280e529cc33d44d40bbe3db524069c0a41b80
parent45f1e9d95320a45d7c38a0db34a643272e3add23 (diff)
downloadpoky-1125adc33b3696ffd351ffec9445f0c09b178fde.tar.gz
buildstats.bbclass: correct sampling of system stats
The last time of sampling would be updated within the SystemStats class but not re-recorded into the datastore, leading to multiple samples being collected in the same second in the sample function of buildstats.py. Fix this to collect and store only one sample per second within a certain tolerance to deal with variation in the arrival time. This fix elimates the spikiness of sampled data, in cases where the difference between the current and the last sample is taken. Previously, since many samples per second were recorded, certain types of data would result in a very small elapsed time and hence a small numerical difference. For example, the CPU usage from /proc/stat is a running total of usage and taking the difference between data collected 0.1 seconds apart would result in usage appearing lower than it actually was. (From OE-Core rev: 0e2df45ab066bb4ad2c4f8622ee9c1a8ecdea9cb) Signed-off-by: Aryaman Gupta <aryaman.gupta@windriver.com> Signed-off-by: Randy MacLeod <randy.macleod@windriver.com> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/classes/buildstats.bbclass3
-rw-r--r--meta/lib/buildstats.py23
2 files changed, 21 insertions, 5 deletions
diff --git a/meta/classes/buildstats.bbclass b/meta/classes/buildstats.bbclass
index 0de605200a..132ecaa98b 100644
--- a/meta/classes/buildstats.bbclass
+++ b/meta/classes/buildstats.bbclass
@@ -285,7 +285,8 @@ python runqueue_stats () {
285 if system_stats: 285 if system_stats:
286 # Ensure that we sample at important events. 286 # Ensure that we sample at important events.
287 done = isinstance(e, bb.event.BuildCompleted) 287 done = isinstance(e, bb.event.BuildCompleted)
288 system_stats.sample(e, force=done) 288 if system_stats.sample(e, force=done):
289 d.setVar('_buildstats_system_stats', system_stats)
289 if done: 290 if done:
290 system_stats.close() 291 system_stats.close()
291 d.delVar('_buildstats_system_stats') 292 d.delVar('_buildstats_system_stats')
diff --git a/meta/lib/buildstats.py b/meta/lib/buildstats.py
index 64ad3ef40e..5d32a81906 100644
--- a/meta/lib/buildstats.py
+++ b/meta/lib/buildstats.py
@@ -51,11 +51,17 @@ class SystemStats:
51 # Last time that we sampled /proc data resp. recorded disk monitoring data. 51 # Last time that we sampled /proc data resp. recorded disk monitoring data.
52 self.last_proc = 0 52 self.last_proc = 0
53 self.last_disk_monitor = 0 53 self.last_disk_monitor = 0
54 # Minimum number of seconds between recording a sample. This 54 # Minimum number of seconds between recording a sample. This becames relevant when we get
55 # becames relevant when we get called very often while many 55 # called very often while many short tasks get started. Sampling during quiet periods
56 # short tasks get started. Sampling during quiet periods
57 # depends on the heartbeat event, which fires less often. 56 # depends on the heartbeat event, which fires less often.
58 self.min_seconds = 1 57 # By default, the Heartbeat events occur roughly once every second but the actual time
58 # between these events deviates by a few milliseconds, in most cases. Hence
59 # pick a somewhat arbitary tolerance such that we sample a large majority
60 # of the Heartbeat events. This ignores rare events that fall outside the minimum
61 # and may lead an extra sample in a given second every so often. However, it allows for fairly
62 # consistent intervals between samples without missing many events.
63 self.tolerance = 0.01
64 self.min_seconds = 1.0 - self.tolerance
59 65
60 self.meminfo_regex = re.compile(rb'^(MemTotal|MemFree|Buffers|Cached|SwapTotal|SwapFree):\s*(\d+)') 66 self.meminfo_regex = re.compile(rb'^(MemTotal|MemFree|Buffers|Cached|SwapTotal|SwapFree):\s*(\d+)')
61 self.diskstats_regex = re.compile(rb'^([hsv]d.|mtdblock\d|mmcblk\d|cciss/c\d+d\d+.*)$') 67 self.diskstats_regex = re.compile(rb'^([hsv]d.|mtdblock\d|mmcblk\d|cciss/c\d+d\d+.*)$')
@@ -164,6 +170,12 @@ class SystemStats:
164 return reduced 170 return reduced
165 171
166 def sample(self, event, force): 172 def sample(self, event, force):
173 """
174 Collect and log proc or disk_monitor stats periodically.
175 Return True if a new sample is collected and hence the value last_proc or last_disk_monitor
176 is changed.
177 """
178 retval = False
167 now = time.time() 179 now = time.time()
168 if (now - self.last_proc > self.min_seconds) or force: 180 if (now - self.last_proc > self.min_seconds) or force:
169 for filename, output, handler in self.proc_files: 181 for filename, output, handler in self.proc_files:
@@ -187,6 +199,7 @@ class SystemStats:
187 data + 199 data +
188 b'\n') 200 b'\n')
189 self.last_proc = now 201 self.last_proc = now
202 retval = True
190 203
191 if isinstance(event, bb.event.MonitorDiskEvent) and \ 204 if isinstance(event, bb.event.MonitorDiskEvent) and \
192 ((now - self.last_disk_monitor > self.min_seconds) or force): 205 ((now - self.last_disk_monitor > self.min_seconds) or force):
@@ -196,3 +209,5 @@ class SystemStats:
196 for dev, sample in event.disk_usage.items()]).encode('ascii') + 209 for dev, sample in event.disk_usage.items()]).encode('ascii') +
197 b'\n') 210 b'\n')
198 self.last_disk_monitor = now 211 self.last_disk_monitor = now
212 retval = True
213 return retval \ No newline at end of file