Skip to content

Commit

Permalink
Switch from Bash to Python
Browse files Browse the repository at this point in the history
  • Loading branch information
mj-xmr committed Jan 8, 2021
1 parent 869ce0f commit b273a4c
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 90 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ release-test:
release-test-ci:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release -D BUILD_SHARED_LIBS=ON $(topdir) && $(MAKE) && MONERO_PARALLEL_TEST_JOBS=nproc $(topdir)/tests/run-tests-parallel.sh
cd $(builddir)/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release -D BUILD_SHARED_LIBS=ON $(topdir) && $(MAKE) && MONERO_PARALLEL_TEST_JOBS=nproc $(topdir)/tests/run-tests-parallel.py
release-all:
mkdir -p $(builddir)/release
Expand Down
120 changes: 120 additions & 0 deletions tests/run-tests-parallel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# Copyright (c) 2014-2021, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# The parallelism celing can be controlled with MONERO_PARALLEL_TEST_JOBS env variable,
# for example:
#
# MONERO_PARALLEL_TEST_JOBS=1 tests/run-tests-parallel.py
# MONERO_PARALLEL_TEST_JOBS=nproc tests/run-tests-parallel.py
#
# The minimum between the ceiling and a currently selected reasonable number of threads is used in the end.
# The reasonable number is selected as a number, that delivers the solution in the shortest time.
"""

import os
import sys
import subprocess
import multiprocessing
from timeit import default_timer as timer

NUM_PROC_MAX_REASONABLE=2 # This might be increased, once the core_tests are divided into many more independent pieces or simply sped up
TESTS_EXCLUDED_REGEX="unit_tests|functional_tests_rpc" # These tests collide with core_tests
ERR_CODE=1

def get_forced_ceiling():
key = 'MONERO_PARALLEL_TEST_JOBS'
if key not in os.environ:
job_ceiling = multiprocessing.cpu_count()
print("No parallelism ceiling selected. Defaulting to nproc, so", job_ceiling)
else:
val = os.environ[key]
if val == "nproc":
job_ceiling=multiprocessing.cpu_count()
else:
job_ceiling = int(val)

print("Parallelism ceiling selected. Using", job_ceiling, "jobs.")

return job_ceiling

def run_fail_fast(num_proc_final):
# Run the excluded tests first, then everything but excluded.
# In the current situation, the excluded tests are the most probable and quickest to fail, giving an early feedback.
ctest1 = get_ctest_command(num_proc_final, '-R')
ctest2 = get_ctest_command(num_proc_final, '-E')

ret1 = run_cmd(ctest1)
if ret1 != 0:
return ret # Fail fast here
ret2 = run_cmd(ctest2)
if ret2 != 0:
return ret

return 0

def run_all():
# Run all of the tests, no matter if the first part fails
ctest1 = get_ctest_command(num_proc_final, '-R')
ctest2 = get_ctest_command(num_proc_final, '-E')

successfull = True
if run_cmd(ctest1) != 0:
successfull = False
if run_cmd(ctest2) != 0: # Run anyway
successfull = False

if successfull:
return 0
else:
return ERR_CODE

def get_ctest_command(num_proc_final, option):
cmd = ['ctest', '-j{}'.format(num_proc_final), option, TESTS_EXCLUDED_REGEX]
return cmd

def run_cmd(cmd):
result = subprocess.run(cmd, stderr=sys.stderr, stdout=sys.stdout)
return result.returncode


job_ceiling = get_forced_ceiling()
num_proc_final=min(NUM_PROC_MAX_REASONABLE, job_ceiling)
print("Job number ceiling is" ,job_ceiling, "and the reasonable maximum is currently", NUM_PROC_MAX_REASONABLE, ".")
print("Using the minimum of the two, so", num_proc_final, "jobs.")

start = timer()
ret = run_all()
#ret = run_fail_fast() #TODO: Uncomment after mining / RPC random test failures are resolved
tdiff = timer() - start
print("Testing took:", round(tdiff / 60), "minutes.")
print("Status:", ret)

exit(ret)
89 changes: 0 additions & 89 deletions tests/run-tests-parallel.sh

This file was deleted.

0 comments on commit b273a4c

Please sign in to comment.