Skip to content

Commit c94f7f9

Browse files
authored
feat: log testing docker resource usage statistics [ci fw-only Fortran/fortran.io] (#9238)
1 parent 1b2161a commit c94f7f9

File tree

3 files changed

+53
-29
lines changed

3 files changed

+53
-29
lines changed

toolset/benchmark/benchmarker.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import threading
2+
3+
from docker.models.containers import Container
14
from toolset.utils.output_helper import log, FNULL
25
from toolset.utils.docker_helper import DockerHelper
36
from toolset.utils.time_logger import TimeLogger
@@ -263,12 +266,6 @@ def benchmark_type(test_type):
263266
log("BENCHMARKING %s ... " % test_type.upper(), file=benchmark_log)
264267

265268
test = framework_test.runTests[test_type]
266-
raw_file = self.results.get_raw_file(framework_test.name,
267-
test_type)
268-
if not os.path.exists(raw_file):
269-
# Open to create the empty file
270-
with open(raw_file, 'w'):
271-
pass
272269

273270
if not test.failed:
274271
# Begin resource usage metrics collection
@@ -281,8 +278,8 @@ def benchmark_type(test_type):
281278
framework_test.port,
282279
test.get_url()))
283280

284-
self.docker_helper.benchmark(script, script_variables,
285-
raw_file)
281+
benchmark_container = self.docker_helper.benchmark(script, script_variables)
282+
self.__log_container_output(benchmark_container, framework_test, test_type)
286283

287284
# End resource usage metrics collection
288285
self.__end_logging()
@@ -323,3 +320,31 @@ def __end_logging(self):
323320
self.subprocess_handle.terminate()
324321
self.subprocess_handle.communicate()
325322

323+
def __log_container_output(self, container: Container, framework_test, test_type) -> None:
324+
def save_docker_logs(stream):
325+
raw_file_path = self.results.get_raw_file(framework_test.name, test_type)
326+
with open(raw_file_path, 'w') as file:
327+
for line in stream:
328+
log(line.decode(), file=file)
329+
330+
def save_docker_stats(stream):
331+
docker_file_path = self.results.get_docker_stats_file(framework_test.name, test_type)
332+
with open(docker_file_path, 'w') as file:
333+
file.write('[\n')
334+
is_first_line = True
335+
for line in stream:
336+
if is_first_line:
337+
is_first_line = False
338+
else:
339+
file.write(',')
340+
file.write(line.decode())
341+
file.write(']')
342+
343+
threads = [
344+
threading.Thread(target=lambda: save_docker_logs(container.logs(stream=True))),
345+
threading.Thread(target=lambda: save_docker_stats(container.stats(stream=True)))
346+
]
347+
348+
[thread.start() for thread in threads]
349+
[thread.join() for thread in threads]
350+

toolset/utils/docker_helper.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -420,16 +420,11 @@ def server_container_exists(self, container_id_or_name):
420420
except:
421421
return False
422422

423-
def benchmark(self, script, variables, raw_file):
423+
def benchmark(self, script, variables):
424424
'''
425425
Runs the given remote_script on the wrk container on the client machine.
426426
'''
427427

428-
def watch_container(container):
429-
with open(raw_file, 'w') as benchmark_file:
430-
for line in container.logs(stream=True):
431-
log(line.decode(), file=benchmark_file)
432-
433428
if self.benchmarker.config.network_mode is None:
434429
sysctl = {'net.core.somaxconn': 65535}
435430
else:
@@ -438,8 +433,7 @@ def watch_container(container):
438433

439434
ulimit = [{'name': 'nofile', 'hard': 65535, 'soft': 65535}]
440435

441-
watch_container(
442-
self.client.containers.run(
436+
return self.client.containers.run(
443437
"techempower/tfb.wrk",
444438
"/bin/bash /%s" % script,
445439
environment=variables,
@@ -450,4 +444,4 @@ def watch_container(container):
450444
ulimits=ulimit,
451445
sysctls=sysctl,
452446
remove=True,
453-
log_config={'type': None}))
447+
log_config={'type': None})

toolset/utils/results.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -212,29 +212,34 @@ def load(self):
212212
except (ValueError, IOError):
213213
pass
214214

215+
def __make_dir_for_file(self, test_name: str, test_type: str, file_name: str):
216+
path = os.path.join(self.directory, test_name, test_type, file_name)
217+
try:
218+
os.makedirs(os.path.dirname(path), exist_ok=True)
219+
except OSError:
220+
pass
221+
return path
222+
223+
def get_docker_stats_file(self, test_name, test_type):
224+
'''
225+
Returns the stats file name for this test_name and
226+
Example: fw_root/results/timestamp/test_type/test_name/stats.txt
227+
'''
228+
return self.__make_dir_for_file(test_name, test_type, "docker_stats.json")
229+
215230
def get_raw_file(self, test_name, test_type):
216231
'''
217232
Returns the output file for this test_name and test_type
218233
Example: fw_root/results/timestamp/test_type/test_name/raw.txt
219234
'''
220-
path = os.path.join(self.directory, test_name, test_type, "raw.txt")
221-
try:
222-
os.makedirs(os.path.dirname(path))
223-
except OSError:
224-
pass
225-
return path
235+
return self.__make_dir_for_file(test_name, test_type, "raw.txt")
226236

227237
def get_stats_file(self, test_name, test_type):
228238
'''
229239
Returns the stats file name for this test_name and
230240
Example: fw_root/results/timestamp/test_type/test_name/stats.txt
231241
'''
232-
path = os.path.join(self.directory, test_name, test_type, "stats.txt")
233-
try:
234-
os.makedirs(os.path.dirname(path))
235-
except OSError:
236-
pass
237-
return path
242+
return self.__make_dir_for_file(test_name, test_type, "stats.txt")
238243

239244
def report_verify_results(self, framework_test, test_type, result):
240245
'''

0 commit comments

Comments
 (0)