Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix identical gcov json file name problem #16527

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 88 additions & 51 deletions src/test/shell/bazel/bazel_cc_code_coverage_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ function set_up() {

# Create the CC sources.
mkdir -p "$ROOT_VAR/coverage_srcs/"
mkdir -p "$ROOT_VAR/coverage_srcs/different"
cat << EOF > "$ROOT_VAR/coverage_srcs/a.h"
int a(bool what);
EOF
Expand All @@ -85,6 +86,20 @@ int a(bool what) {
return b(-1);
}
}
EOF

cat << EOF > "$ROOT_VAR/coverage_srcs/different/a.h"
int different_a(bool what);
EOF

cat << EOF > "$ROOT_VAR/coverage_srcs/different/a.cc"
int different_a(bool what) {
if (what) {
return 1;
} else {
return 2;
}
}
EOF

cat << EOF > "$ROOT_VAR/coverage_srcs/b.h"
Expand All @@ -100,37 +115,24 @@ EOF
cat << EOF > "$ROOT_VAR/coverage_srcs/t.cc"
#include <stdio.h>
#include "a.h"
#include "different/a.h"

int main(void) {
a(true);
different_a(false);
}
EOF

generate_and_execute_instrumented_binary coverage_srcs/test \
coverage_srcs/a.h coverage_srcs/a.cc \
coverage_srcs/b.h \
coverage_srcs/t.cc

# Prior to version 11, g++ generates the notes files in the current directory
# instead of next to the object file despite the documentation indicating otherwise:
# https://gcc.gnu.org/onlinedocs/gcc/Gcov-Data-Files.html#Gcov-Data-Files
# This is fixed in g++ 11 so we have to handle both cases.

local not_found=0
ls coverage_srcs/*a.gcno > /dev/null 2>&1 || not_found=$?
if [[ $not_found -ne 0 ]]; then
agcno=$(ls *a.gcno)
tgcno=$(ls *t.gcno)
agcda=$(ls *a.gcda)
tgcda=$(ls *t.gcda)
mv $agcno coverage_srcs/$agcno
mv $tgcno coverage_srcs/$tgcno
mv $agcda coverage_srcs/$agcda
mv $tgcda coverage_srcs/$tgcda
fi
c-mita marked this conversation as resolved.
Show resolved Hide resolved
coverage_srcs/a.cc coverage_srcs/a.o \
coverage_srcs/different/a.cc coverage_srcs/different/a.o \
coverage_srcs/t.cc coverage_srcs/t.o

agcno=$(ls coverage_srcs/*a.gcno)
dagcno=$(ls coverage_srcs/different/*a.gcno)
tgcno=$(ls coverage_srcs/*t.gcno)
agcda=$(ls coverage_srcs/*a.gcda)
dagcda=$(ls coverage_srcs/different/*a.gcda)
tgcda=$(ls coverage_srcs/*t.gcda)
# Even though gcov expects the gcda files to be next to the gcno files,
# during Bazel execution this will not be the case. collect_cc_coverage.sh
Expand All @@ -140,32 +142,41 @@ EOF
# https://github.com/bazelbuild/bazel/issues/16229
mv $agcda "$COVERAGE_DIR_VAR/$agcda"
mv $tgcda "$COVERAGE_DIR_VAR/$tgcda"
mkdir "$COVERAGE_DIR_VAR/$(dirname ${dagcda})"
mv $dagcda "$COVERAGE_DIR_VAR/$dagcda"

# All generated .gcno files need to be in the manifest otherwise
# the coverage report will be incomplete.
echo "$tgcno" >> "$COVERAGE_MANIFEST_VAR"
echo "$agcno" >> "$COVERAGE_MANIFEST_VAR"
echo "$dagcno" >> "$COVERAGE_MANIFEST_VAR"
}

# Generates and executes an instrumented binary:
#
# Reads the list of arguments provided by the caller (using $@) and uses them
# to produce an instrumented binary using g++. This step also generates
# the notes (.gcno) files.
# Reads the list of source files along with object files paths. Uses them
# to produce object files and link them to an instrumented binary using g++.
# This step also generates the notes (.gcno) files.
#
# Executes the instrumented binary. This step also generates the
# profile data (.gcda) files.
#
# - [(source_file, object_file),...] - source files and object file paths
# - path_to_binary destination of the binary produced by g++
function generate_and_execute_instrumented_binary() {
local path_to_binary="${1}"; shift
g++ -coverage \
"$@" -o "$path_to_binary" \
|| fail "Couldn't produce the instrumented binary for $@ \
with path_to_binary $path_to_binary"

# Execute the instrumented binary and generates the profile data (.gcda)
# file.
# The profile data file is placed in $gcda_directory.
local src_file=""
local obj_file=""
local obj_files=""
while [[ $# -ge 2 ]]; do
src_file=$1; shift
obj_file=$1; shift
obj_files="${obj_files} $obj_file"
g++ -coverage -fprofile-arcs -ftest-coverage -lgcov -c \
"$src_file" -o "$obj_file"
done

g++ -coverage -fprofile-arcs -ftest-coverage -lgcov -o "$path_to_binary" $obj_files
"$path_to_binary" || fail "Couldn't execute the instrumented binary \
$path_to_binary"
}
Expand Down Expand Up @@ -223,11 +234,12 @@ function assert_gcov_coverage_srcs_t_cc() {
local output_file="${1}"; shift

# The expected coverage result for coverage_srcs/t.cc in gcov format.
local expected_gcov_result_t_cc="file:coverage_srcs/t.cc
function:4,1,main
lcount:4,1
local expected_gcov_result_t_cc="coverage_srcs/t.cc
function:5,1,main
lcount:5,1
lcount:6,1"
lcount:6,1
lcount:7,1
lcount:8,1"
assert_coverage_entry_in_file "$expected_gcov_result_t_cc" "$output_file"
}

Expand All @@ -244,6 +256,19 @@ lcount:5,0"
assert_coverage_entry_in_file "$expected_gcov_result" "$output_file"
}

function assert_gcov_coverage_srcs_d_a_cc() {
local output_file="${1}"; shift

# The expected coverage result for coverage_srcs/different/a.cc in gcov format.
local expected_gcov_result_d_a_cc="file:coverage_srcs/different/a.cc
function:1,1,_Z11different_ab
lcount:1,1
lcount:2,1
lcount:3,0
lcount:5,1"
assert_coverage_entry_in_file "$expected_gcov_result_d_a_cc" "$output_file"
}

function assert_gcov_coverage_srcs_a_cc_json() {
local output_file="${1}"; shift

Expand All @@ -265,7 +290,7 @@ function assert_gcov_coverage_srcs_t_cc_json() {

# The expected coverage result for coverage_srcs/t.cc in gcov format.
cat > expected_gcov_result_t_cc <<EOF
{"lines": [{"branches": [], "count": 1, "line_number": 4, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 5, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 6, "unexecuted_block": false, "function_name": "main"}], "functions": [{"blocks": 3, "end_column": 1, "start_line": 4, "name": "main", "blocks_executed": 3, "execution_count": 1, "demangled_name": "main", "start_column": 5, "end_line": 6}], "file": "coverage_srcs/t.cc"}
{"lines": [{"branches": [], "count": 1, "line_number": 5, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 6, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 7, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 8, "unexecuted_block": false, "function_name": "main"}], "functions": [{"blocks": 4, "end_column": 1, "start_line": 5, "name": "main", "blocks_executed": 4, "execution_count": 1, "demangled_name": "main", "start_column": 5, "end_line": 8}], "file": "coverage_srcs/t.cc"}
EOF
local expected_gcov_result_t_cc=$(cat expected_gcov_result_t_cc | tr -d '\n')
assert_coverage_entry_in_file "$expected_gcov_result_t_cc" "$output_file"
Expand All @@ -274,14 +299,24 @@ EOF
function assert_gcov_coverage_srcs_b_h_json() {
local output_file="${1}"; shift

# The expected coverage result for coverage_srcs/t.cc in gcov format.
# The expected coverage result for coverage_srcs/b.h in gcov format.
cat > expected_gcov_result_b_h <<EOF
{"lines": [{"branches": [], "count": 1, "line_number": 1, "unexecuted_block": false, "function_name": "_Z1bi"}, {"branches": [], "count": 1, "line_number": 2, "unexecuted_block": false, "function_name": "_Z1bi"}, {"branches": [], "count": 1, "line_number": 3, "unexecuted_block": false, "function_name": "_Z1bi"}, {"branches": [], "count": 0, "line_number": 5, "unexecuted_block": true, "function_name": "_Z1bi"}], "functions": [{"blocks": 4, "end_column": 1, "start_line": 1, "name": "_Z1bi", "blocks_executed": 3, "execution_count": 1, "demangled_name": "b(int)", "start_column": 5, "end_line": 7}], "file": "coverage_srcs/b.h"}
EOF
local expected_gcov_result_b_h=$(cat expected_gcov_result_b_h | tr -d '\n')
assert_coverage_entry_in_file "$expected_gcov_result_b_h" "$output_file"
}

function assert_gcov_coverage_srcs_d_a_cc_json() {
local output_file="${1}"; shift

# The expected coverage result for coverage_srcs/different/a.cc in gcov format.
cat > expected_gcov_result_d_a_cc <<EOF
{"lines": [{"branches": [], "count": 1, "line_number": 1, "unexecuted_block": false, "function_name": "_Z11different_ab"}, {"branches": [], "count": 1, "line_number": 2, "unexecuted_block": false, "function_name": "_Z11different_ab"}, {"branches": [], "count": 0, "line_number": 3, "unexecuted_block": true, "function_name": "_Z11different_ab"}, {"branches": [], "count": 1, "line_number": 5, "unexecuted_block": false, "function_name": "_Z11different_ab"}], "functions": [{"blocks": 4, "end_column": 1, "start_line": 1, "name": "_Z11different_ab", "blocks_executed": 3, "execution_count": 1, "demangled_name": "different_a(bool)", "start_column": 5, "end_line": 7}], "file": "coverage_srcs/different/a.cc"}
EOF
local expected_gcov_result_d_a_cc=$(cat expected_gcov_result_d_a_cc | tr -d '\n')
assert_coverage_entry_in_file "$expected_gcov_result_d_a_cc" "$output_file"
}

function test_cc_test_coverage_gcov() {
local -r gcov_location=$(which gcov)
Expand All @@ -303,9 +338,6 @@ function test_cc_test_coverage_gcov() {
# Location of the output file of the C++ coverage script when gcov is used.
local output_file="$COVERAGE_DIR_VAR/_cc_coverage.gcov"

# Location of the output file of the C++ coverage script when gcov is used.
local output_file="$COVERAGE_DIR_VAR/_cc_coverage.gcov"

# If the file _cc_coverge.gcov does not exist, it means we are using gcc 9
# or higher which uses json.gz files as intermediate format. We will keep
# testing gcc 7 and 8 until most users have migrated.
Expand All @@ -319,35 +351,40 @@ function test_cc_test_coverage_gcov() {
assert_gcov_coverage_srcs_a_cc "$output_file"
assert_gcov_coverage_srcs_t_cc "$output_file"
assert_gcov_coverage_srcs_b_h "$output_file"
assert_gcov_coverage_srcs_d_a_cc "$output_file"

# This assertion is needed to make sure no other source files are included
# in the output file.
local nr_lines="$(wc -l < "$output_file")"
[[ "$nr_lines" == 17 ]] || \
[[ "$nr_lines" == 24 ]] || \
fail "Number of lines in C++ gcov coverage output file is "\
"$nr_lines and different than 17"
"$nr_lines and different than 24"
else

# There may or may not be "gcda" in the extension.
local not_found=0
ls $COVERAGE_DIR_VAR/*.gcda.gcov.json.gz > /dev/null 2>&1 || not_found=$?
ls $COVERAGE_DIR_VAR/coverage_srcs/*.gcda.gcov.json.gz > /dev/null 2>&1 || not_found=$?
if [[ $not_found -ne 0 ]]; then
agcda=$(ls $COVERAGE_DIR_VAR/*a.gcov.json.gz)
tgcda=$(ls $COVERAGE_DIR_VAR/*t.gcov.json.gz)
agcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/*a.gcov.json.gz)
tgcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/*t.gcov.json.gz)
dagcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/different/*a.gcov.json.gz)
else
agcda=$(ls $COVERAGE_DIR_VAR/*a.gcda.gcov.json.gz)
tgcda=$(ls $COVERAGE_DIR_VAR/*t.gcda.gcov.json.gz)
agcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/*a.gcda.gcov.json.gz)
tgcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/*t.gcda.gcov.json.gz)
dagcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/different/*a.gcda.gcov.json.gz)
fi
output_file_json="output_file.json"
zcat $agcda $tgcda > $output_file_json
zcat $agcda $tgcda $dagcda > $output_file_json

assert_gcov_coverage_srcs_a_cc_json "$output_file_json"
assert_gcov_coverage_srcs_t_cc_json "$output_file_json"
assert_gcov_coverage_srcs_b_h_json "$output_file_json"
assert_gcov_coverage_srcs_d_a_cc_json "$output_file_json"

local nr_files="$(grep -o -i "\"file\":" "$output_file_json" | wc -l)"
[[ "$nr_files" == 3 ]] || \
[[ "$nr_files" == 4 ]] || \
fail "Number of files in C++ gcov coverage output file is "\
"$nr_files and different than 3"
"$nr_files and different than 4"
fi
}

Expand Down
2 changes: 1 addition & 1 deletion tools/test/collect_cc_coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function gcov_coverage() {
# gcov 9 or higher use a JSON based format for their coverage reports.
# The output is generated into multiple files: "$(basename ${gcda}).gcov.json.gz"
# Concatenating JSON documents does not yield a valid document, so they are moved individually
mv -- *.gcov.json.gz "$(dirname "$output_file")"
mv -- *.gcov.json.gz "$(dirname "$output_file")/$(dirname ${gcno_path})"
else
# Append all .gcov files in the current directory to the output file.
cat -- *.gcov >> "$output_file"
Expand Down