strange behavior of cmake ctest for bigger CTEST_PARALLEL_LEVEL - makefile

I am new to the SO.
I have a simple unit test code where I am doing following operations :
calculating square root of the number using mysqrt library .
Using the output of square root, adding this result with same number and display the result.
When I am running the code with CTEST_PARALLEL_LEVEL = 1 my all test cases are passing.
But when I do CTEST_PARALLEL_LEVEL = 8 then my test cases are failing some time for some input which is not fixed in every run.
99% the ALL results are passing but 1% its failing.
Error:
mysqrt.o: file not recognized: File truncated
I have deleted the object file explicitly by using rm *.o ,But still this error is coming after few runs .
I am not sure why this error is coming with CTEST_PARALLEL_LEVEL = 8
I am attaching my CMakeList only as some of Stack Overflow expert can understand the issue by checking these 3 CMakeLists.txt files.
NOTE: As per the Stack overflow guidelines I am not attaching my source code of sqrt and addition function to avoid the bigger length of the question .
My folder structure:
SAMPLE_TEST
├── CMakeLists.txt
├── MathFunctions
│   ├── CMakeLists.txt
│   ├── MathFunctions.h
│   └── mysqrt.cpp
└── unit_test
├── CMakeLists.txt
└── step2
├── CMakeLists.txt
├── execute.cpp
└── tutorial.cpp
SAMPLE_TEST
CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(Tutorial)
ENABLE_TESTING()
add_subdirectory(MathFunctions)
add_subdirectory(unit_test)
MathFunctions folder
CMakeLists.txt
add_library(MathFunctions mysqrt.cpp)
set(REF_FILES mysqrt.cpp)
add_definitions(-Wall -Wextra -pedantic -std=c++11)
add_custom_target(build_reference_library
DEPENDS sqrtlib
COMMENT "Generating sqrtlib")
ADD_LIBRARY(sqrtlib OBJECT ${REF_FILES})
unit_test folder
CMakeLists.txt
set(REF_MATHLIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../MathFunctions)
macro(GENERATION file input)
set(ip_generator ctest_input_${input})
add_executable(${ip_generator}
${file}
$<TARGET_OBJECTS:sqrtlib>
)
target_compile_options(${ip_generator} PUBLIC
-Wall -Wextra -g -std=c++11
-DCTEST_INPUT=${input})
target_link_libraries(${ip_generator} PUBLIC
dl pthread
)
target_include_directories(${ip_generator} PUBLIC
${REF_MATHLIB_DIR}
)
set(INPUT_FILE0 ip0_${input}.y)
set(INPUT_FILE0_TXT ip0_${input}.txt)
add_custom_command(
OUTPUT ${INPUT_FILE0} ${INPUT_FILE0_TXT}
COMMAND ${ip_generator} > ${INPUT_FILE0_TXT}
MAIN_DEPENDENCY ${sqrtlib}
COMMENT "Generating output files of for testcase")
add_custom_target(gen_input_${input}
DEPENDS ${INPUT_FILE0}
COMMENT "Generated output files")
endmacro()
####################
macro(EXECUTE file input)
get_filename_component(main_base_name ${file} NAME_WE)
set(main_base_name_mangled ${main_base_name}_${input})
set(exe_generator ctest_ref_${input})
add_executable(${exe_generator}
${file}
$<TARGET_OBJECTS:sqrtlib>
)
target_compile_options(${exe_generator} PUBLIC
-Wall -Wextra -g -std=c++11
-DCTEST_INPUT=${input})
target_link_libraries(${exe_generator} PUBLIC
dl pthread
)
target_include_directories(${exe_generator} PUBLIC
${REF_MATHLIB_DIR}
)
set(INPUT_FILE0 ip0_${input}.y)
set(EXE_FILE0 exeadd_${input}.y)
set(EXE_FILE_TXT exeadd_${input}.txt)
add_custom_command(
OUTPUT ${EXE_FILE0} ${EXE_FILE_TXT}
COMMAND ${exe_generator} > ${EXE_FILE_TXT}
MAIN_DEPENDENCY ${INPUT_FILE0} ${sqrtlib}
COMMENT "Generating output files of for testcase")
add_custom_target(gen_execute_${input}
DEPENDS ${EXE_FILE0}
COMMENT "Generated output files")
# add test to simulate
add_test(NAME ctest_execute_${input}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}
--target gen_execute_${input})
#add_dependencies(execute_${main_base_name_mangled}
#gen_input)
endmacro()
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
# add test directories
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
set(TEST_DIRECTORIES
step2
)
foreach(dir ${TEST_DIRECTORIES})
add_subdirectory(${dir})
endforeach()
step2 folder
CMakeLists.txt
set(UT_IPGEN_FILES tutorial.cpp)
set(UT_EXECUTE_FILES execute.cpp)
set(input_integer_range 1 4 9 16 25 36 49 64 81 100 121 144 )
foreach(ip_integer ${input_integer_range})
GENERATION(${UT_IPGEN_FILES} ${ip_integer})
EXECUTE(${UT_EXECUTE_FILES} ${ip_integer})
endforeach(ip_integer)
Result:
1st Run:
Start 1: ctest_execute_1
Start 2: ctest_execute_4
Start 3: ctest_execute_9
Start 4: ctest_execute_16
Start 5: ctest_execute_25
Start 6: ctest_execute_36
Start 7: ctest_execute_49
Start 8: ctest_execute_64
1/12 Test #4: ctest_execute_16 .................***Failed 1.14 sec
2/12 Test #6: ctest_execute_36 ................. Passed 1.27 sec
3/12 Test #7: ctest_execute_49 ................. Passed 1.32 sec
4/12 Test #8: ctest_execute_64 ................. Passed 1.32 sec
Start 9: ctest_execute_81
Start 10: ctest_execute_100
Start 11: ctest_execute_121
Start 12: ctest_execute_144
5/12 Test #1: ctest_execute_1 .................. Passed 1.33 sec
6/12 Test #2: ctest_execute_4 .................. Passed 1.33 sec
7/12 Test #3: ctest_execute_9 .................. Passed 1.33 sec
8/12 Test #5: ctest_execute_25 ................. Passed 1.33 sec
9/12 Test #10: ctest_execute_100 ................ Passed 0.54 sec
10/12 Test #11: ctest_execute_121 ................ Passed 0.55 sec
11/12 Test #9: ctest_execute_81 ................. Passed 0.55 sec
12/12 Test #12: ctest_execute_144 ................ Passed 0.55 sec
92% tests passed, 1 tests failed out of 12
Total Test time (real) = 1.88 sec
The following tests FAILED:
4 - ctest_execute_16 (Failed)
2nd Run:
Start 1: ctest_execute_1
Start 2: ctest_execute_4
Start 3: ctest_execute_9
Start 4: ctest_execute_16
Start 5: ctest_execute_25
Start 6: ctest_execute_36
Start 7: ctest_execute_49
Start 8: ctest_execute_64
1/12 Test #6: ctest_execute_36 ................. Passed 1.31 sec
2/12 Test #7: ctest_execute_49 ................. Passed 1.36 sec
3/12 Test #8: ctest_execute_64 ................. Passed 1.36 sec
Start 9: ctest_execute_81
Start 10: ctest_execute_100
Start 11: ctest_execute_121
4/12 Test #1: ctest_execute_1 .................. Passed 1.37 sec
5/12 Test #2: ctest_execute_4 .................. Passed 1.37 sec
6/12 Test #3: ctest_execute_9 .................. Passed 1.36 sec
7/12 Test #4: ctest_execute_16 ................. Passed 1.36 sec
8/12 Test #5: ctest_execute_25 ................. Passed 1.37 sec
Start 12: ctest_execute_144
9/12 Test #11: ctest_execute_121 ................ Passed 0.50 sec
10/12 Test #10: ctest_execute_100 ................ Passed 0.51 sec
11/12 Test #9: ctest_execute_81 ................. Passed 0.51 sec
12/12 Test #12: ctest_execute_144 ................ Passed 0.34 sec
100% tests passed, 0 tests failed out of 12
Total Test time (real) = 2.01 sec

Your tests executing
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ...
which effectively runs make (or whatever build tool you use) in the project's build directory.
But concurrent invocations of make in the same directory are never guarantee to work correctly. This is why you got weird errors when run tests in parallel (with CTEST_PARALLEL_LEVEL variable being set).
E.g. all these tests are trying to create the same object file mysqrt.o, and this creation is definitely not thread-safe.
By running
make sqrtlib
before
ctest
you may be sure that the object file is already created when tests are run, and tests wouldn't attempt to create it again.
But you still could get other conflicts in the parallel tests.
It depends on what actually you want to check by the testing, but usually a test checks behavior of some program or library, and it doesn't intend to check a compilation(building) of that program. Because of that, compilation(building) commands are performed before the testing.
Usually it is convenient to follow(implement) this workflow for testing:
# Configure the project
cmake <source-directory>
# Build the project.
# It builds both program/library intended, and the tests themselves.
make
# run tests
ctest <params>
In that case a test could have the following definition:
add_test(NAME ctest_execute_${input} COMMAND ${exe_generator})
(Unless you want to check output of the test by some automatic way, no need to explicitely save this output by redirecting into the file. ctest by itself would collect the output of the test, so you may read it if needed).

Related

Build Docker Images with Bazel targets Built

I have a (1) Dockerfile and a (2) C++ project with Bazel
I want to create a docker image that has Bazel targets pre-built within the image, so as to when I power up new containers the Bazel targets are pre-built and I just do Bazel run //hello:hello_world from the container bash.
Dockerfile
# Copy my project with Bazel files to a Docker image, and the
...
RUN bazel --output_user_root=/tmp/hello_project/bazel build //...
...
Within the execution of the Dockerfile, I get the following output which is expected
Loading:
Loading: 0 packages loaded
Analyzing: 2 targets (1 packages loaded, 0 targets configured)
Analyzing: 2 targets (11 packages loaded, 18 targets configured)
INFO: Analyzed 2 targets (15 packages loaded, 60 targets configured).
INFO: Found 2 targets...
[0 / 11] [Prepa] BazelWorkspaceStatusAction stable-status.txt
INFO: Elapsed time: 6.333s, Critical Path: 0.37s
INFO: 11 processes: 6 internal, 5 processwrapper-sandbox.
INFO: Build completed successfully, 11 total actions
INFO: Build completed successfully, 11 total actions
When I run a new container form the Docker Image built previously and then on the container I run
bazel run //hello:hello_world
Instead of using existing pre-built targets it re-builds the targets, which is not required.
Result I expect (not get): Everything is pre-built and just needs to run
INFO: Analyzed target //hello:hello_world (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //hello:hello_world up-to-date:
bazel-bin/hello/hello_world
INFO: Elapsed time: 0.163s, Critical Path: 0.01s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
Hello World!
Result I get: I re-builds the binaries
[root#4a6bdb57fd79 test-rc]# bazel run //hello:hello_world
Extracting Bazel installation...
Starting local Bazel server and connecting to it...
INFO: Analyzed target //hello:hello_world (15 packages loaded, 60 targets configured).
INFO: Found 1 target...
Target //hello:hello_world up-to-date:
bazel-bin/hello/hello_world
INFO: Elapsed time: 6.255s, Critical Path: 0.38s
INFO: 7 processes: 4 internal, 3 processwrapper-sandbox.
INFO: Build completed successfully, 7 total actions
INFO: Build completed successfully, 7 total actions
Hello World!
How can I make sure, the the bazel run uses same pre-built targets and not build them again before run.
This sounds like non-determinism - in the second execution of Bazel, something is different causing a cache miss.
Some things that can cause it:
different options passed to bazel build vs. bazel test - check your .bazelrc file
actions that include VCS info or a timestamp - make sure you have rules_docker 0.22.0 or later to pick up https://github.com/bazelbuild/rules_docker/commit/2b35b2dd56f0be6cc6b8df957332a31435f6b3ce
One step to diagnose is to use the --explain=log.txt and --verbose_explanations flags to Bazel, then the log file will say why it was rebuilt. However it doesn't have much detail, just something like "a source file has changed".
If you want the power tool for this, there is a way to find out exactly why Bazel didn't get a cache hit - read https://georgi.hristozov.net/til/2020/04/20/compare-bazel-execlogs-to-find-non-deterministic-parts-of-the-build

Golang Bazel empty coverage_report.dat

I am working on a small Golang monorepo and I am using Bazel + gazelle to manage deps along with tests, builds, coverage,...
I am having an issue when it comes to coverage. I have followed a few examples but for some reason the coverage_report.dat file (that then will be processed by genhtml) is always empty.
This is the command that I am running with relative output
$ bazel coverage --combined_report=lcov --cache_test_results=no --test_output=all //...
INFO: Using default value for --instrumentation_filter: "^//service/hello[/:],^//service/hellotwo[/:]".
INFO: Override the above default with --instrumentation_filter
INFO: Analyzed 4 targets (0 packages loaded, 0 targets configured).
INFO: Found 2 targets and 2 test targets...
INFO: From Testing //service/hello:hello_test:
==================== Test output for //service/hello:hello_test:
PASS
coverage: 100.0% of statements
================================================================================
INFO: From Testing //service/hellotwo:hellotwo_test:
==================== Test output for //service/hellotwo:hellotwo_test:
PASS
coverage: 100.0% of statements
================================================================================
INFO: LCOV coverage report is located at /private/var/tmp/_bazel_andrea/292e77b095155ea362773b482c2c4621/execroot/__main__/bazel-out/_coverage/_coverage_report.dat
and execpath is bazel-out/_coverage/_coverage_report.dat
INFO: Elapsed time: 0.217s, Critical Path: 0.09s
INFO: 3 processes: 1 internal, 2 darwin-sandbox.
INFO: Build completed successfully, 3 total actions
//service/hello:hello_test PASSED in 0.1s
/private/var/tmp/_bazel_andrea/292e77b095155ea362773b482c2c4621/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/service/hello/hello_test/coverage.dat
//service/hellotwo:hellotwo_test PASSED in 0.1s
/private/var/tmp/_bazel_andrea/292e77b095155ea362773b482c2c4621/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/service/hellotwo/hellotwo_test/coverage.dat
Executed 2 out of 2 tests: 2 tests pass.
INFO: Build completed successfully, 3 total actions
The coverage is calculated but bazel-out/_coverage/_coverage_report.dat is empty. I was wondering if anyone has had this issue before and managed to find a solution to it.
I am working on a MacBook Pro with Bazel (v4.1.0) installed via Homebrew.

"go test -cpuprofile" does not generate a full trace

Issue
I have a go package, with a test suite.
When I run the test suite for this package, the total runtime is ~ 7 seconds :
$ go test ./mydbpackage/ -count 1
ok mymodule/mydbpackage 7.253s
However, when I add a -cpuprofile=cpu.out option, the sampling does not cover the whole run :
$ go test ./mydbpackage/ -count 1 -cpuprofile=cpu.out
ok mymodule/mydbpackage 7.029s
$ go tool pprof -text -cum cpu.out
File: mydbpackage.test
Type: cpu
Time: Aug 6, 2020 at 9:42am (CEST)
Duration: 5.22s, Total samples = 780ms (14.95%) # <--- depending on the runs, I get 400ms to 1s
Showing nodes accounting for 780ms, 100% of 780ms total
flat flat% sum% cum cum%
0 0% 0% 440ms 56.41% testing.tRunner
10ms 1.28% 1.28% 220ms 28.21% database/sql.withLock
10ms 1.28% 2.56% 180ms 23.08% runtime.findrunnable
0 0% 2.56% 180ms 23.08% runtime.mcall
...
Looking at the collected samples :
# sample from another run :
$ go tool pprof -traces cpu.out | grep "ms " # get the first line of each sample
10ms runtime.nanotime
10ms fmt.(*readRune).ReadRune
30ms syscall.Syscall
10ms runtime.scanobject
10ms runtime.gentraceback
...
# 98 samples collected, for a total sum of 1.12s
The issue I see is : for some reason, the sampling profiler stops collecting samples, or is blocked/slowed down at some point.
Context
go version is 1.14.6, platform is linux/amd64
$ go version
go version go1.14.6 linux/amd64
This package contains code that interact with a database, and the tests are run against a live postgresql server.
One thing I tried : t.Skip() internally calls runtime.Goexit(), so I replaced calls to t.Skip and variants with a simple return ; but it didn't change the outcome.
Question
Why aren't more samples collected ? I there some known pattern that blocks/slows down the sampler, or terminates the sampler earlier than it should ?
#Volker guided me to the answer in his comments :
-cpuprofile creates a profile in which only goroutines actively using the CPU are sampled.
In my use case : my go code spends a lot of time waiting for the answers of the postgresql server.
Generating a trace using go test -trace=trace.out, and then extracting a network blocking profile using go tool trace -pprof=net trace.out > network.out yielded much more relevant information.
For reference, on top of opening the complete trace using go tool trace trace.out, here are the values you can pass to -pprof= :
from go tool trace docs :
net: network blocking profile
sync: synchronization blocking profile
syscall: syscall blocking profile
sched: scheduler latency profile

Errors in sdl install and use in perl on windows

i have tried:
in menu start: CPAN Client
install Alien::SDL SDL
i choose 64 bit and after a long while errors:
what is wrong? it seems simple, but it's not
so i tried: cpan -i --force SDL
no errors, but i can't run Padre anymore :/
i try perl name.pl (with sdl code program) and it gives:
in 'cmd' in Windows 7: cpan -i SDL and it gives me (last part):
<pre>
t\sdlx_controller_interface.t ... ok
t\sdlx_fps.t .................... ok
t\sdlx_layermanager.t ........... ok
t\sdlx_music.t .................. ok
t\sdlx_rect.t ................... ok
t\sdlx_sfont.t .................. ok
t\sdlx_sound.t .................. ok
t\sdlx_sprite.t ................. ok
t\sdlx_sprite_animated.t ........ ok
t\sdlx_surface.t ................ ok
t\sdlx_text.t ................... ok
t\sdlx_validate.t ............... ok
t\smpeg.t ....................... skipped: smpeg support not compiled
t\ttf.t ......................... ok
t\ttf_font.t .................... ok
Test Summary Report
-------------------
t\core.t (Wstat: 0 Tests: 28 Failed: 0)
TODO passed: 21-22
t\core_video.t (Wstat: 768 Tests: 71 Failed: 0)
TODO passed: 57, 59
Non-zero exit status: 3
Parse errors: No plan found in TAP output
Files=59, Tests=3788, 188 wallclock secs ( 0.56 usr + 0.08 sys = 0.64 CPU)
Result: FAIL
Failed 1/59 test programs. 0/3788 subtests failed.
FROGGS/SDL-2.546.tar.gz
E:\_win_7\Dwimperl\perl\bin\perl.exe ./Build test -- NOT OK
//hint// to see the cpan-testers results for installing this module, try:
reports FROGGS/SDL-2.546.tar.gz
Running Build install
make test had returned bad status, won't install without force
So... i have tried "cpan -i SDL --force"
gives:
Test Summary Report
-------------------
t\core.t (Wstat: 0 Tests: 28 Failed: 0)
TODO passed: 21-22
t\core_video.t (Wstat: 768 Tests: 71 Failed: 0)
TODO passed: 57, 59
Non-zero exit status: 3
Parse errors: No plan found in TAP output
Files=59, Tests=3788, 147 wallclock secs ( 0.47 usr + 0.13 sys = 0.59 CPU)
Result: FAIL
Failed 1/59 test programs. 0/3788 subtests failed.
FROGGS/SDL-2.546.tar.gz
E:\_win_7\Dwimperl\perl\bin\perl.exe ./Build test -- NOT OK
//hint// to see the cpan-testers results for installing this module, try:
reports FROGGS/SDL-2.546.tar.gz
Running Build install
make test had returned bad status, won't install without force
Warning: Cannot install --force, don't know what it is.
Try the command
i /--force/
to find objects with matching identifiers.
So I tried:
cpan -i --force SDL
No errors, but I can't run Padre anymore. I tried
perl name.pl
(with sdl code program) and it gives:

Sample firefox add-on "cfx test" fail, why?

I used the instructions from https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Installation
Initiated addition and run the test. Why, even in this example I have got an error as I can continue to develop?
C:\addon-sdk-1.17\bin>activate
Welcome to the Add-on SDK. For the docs, visit https://addons.mozilla.org/en-US/ developers/docs/sdk/latest/
(C:\addon-sdk-1.17) C:\addon-sdk-1.17\bin>cd ../examples
(C:\addon-sdk-1.17) C:\addon-sdk-1.17\examples>mkdir fe
(C:\addon-sdk-1.17) C:\addon-sdk-1.17\examples>cd fe
(C:\addon-sdk-1.17) C:\addon-sdk-1.17\examples\fe>cfx init
* lib directory created
* data directory created
* test directory created
* generated jID automatically: jid1-pNW6cN0dpaDyiQ
* package.json written
* test/test-main.js written
* lib/main.js written
Your sample add-on is now ready. Do "cfx test" to test it and "cfx run" to try it. Have fun!
(C:\addon-sdk-1.17) C:\addon-sdk-1.17\examples\fe>cfx test
Using binary at 'C:\Program Files (x86)\Mozilla Firefox\firefox.exe'.
Using profile at 'c:\users\artur\appdata\local\temp\tmpxescsx.mozrunner'.
Running tests on Firefox 34.0.5/Gecko 34.0.5 ({ec8030f7-c20a-464f-9b0e-13a3a9e97 384}) under winnt/x86. .console.error: fe: fail: There was an uncaught Promise rejection: JS frame :: resource://gre/modules/Pr omise.jsm -> resource://gre/modules/Promise-backend.js :: PendingErrors.register :: line 159 JS frame :: resource://gre/modules/Promise.jsm -> resource://gre/modules/Promise
-backend.js :: this.PromiseWalker.completePromise :: line 672 JS frame :: resource://gre/modules/Promise.jsm -> resource://gre/modules/Promise
-backend.js :: Handler.prototype.process :: line 868 JS frame :: resource://gre/modules/Promise.jsm -> resource://gre/modules/Promise
-backend.js :: this.PromiseWalker.walkerLoop :: line 744 native frame :: <unknown filename> :: <TOP_LEVEL> :: line 0 console.trace: fe:
_ecated/unit-test.js 96 fail
_ecated/unit-test.js 61 TestRunner.prototype._uncaughtErrorObserver
_/Promise-backend.js 197 PendingErrors.report
_/Promise-backend.js 209 PendingErrors.flush
_/Promise-backend.js 611 Promise.Debugging.flushUncaughtErrors
_ecated/unit-test.js 306 done
_ecated/unit-test.js 529 start
_ecated/unit-test.js 491 runNextTest
_ecated/unit-test.js 496 startMany
_ecated/unit-test.js 26 findAndRunTests/<
_/Promise-backend.js 865 Handler.prototype.process
_/Promise-backend.js 744 this.PromiseWalker.walkerLoop
0
. 2 of 3 tests passed. Total time: 2.550000 seconds Program terminated unsuccessfully.
(C:\addon-sdk-1.17) C:\addon-sdk-1.17\examples\fe>
I just had the same issue on Ubuntu.
According to this bugzilla entry, there won't be any new releases of cfx any more. Instead, the node-based jpm ("jetpack mechanic") is the tool to go. A current minor issue, on Ubuntu the firefox binary has to be specified explicitly, e.g.
jpm -b /usr/bin/firefox test

Resources