mozilla / grcov

Rust tool to collect and aggregate code coverage data for multiple source files
Mozilla Public License 2.0
1.18k stars 149 forks source link

Why grcov count function more than once ? #451

Open redtankd opened 4 years ago

redtankd commented 4 years ago

For these codes, grcov count 8 functions in total and 3 functions hit. test_student() is excluded by me. Actually, only new() is hit. get_id() and get_grade() are not tested. I thought that there be 3 functions in total and 1 function hit.

Why?

pub struct Student {
    id: i32,
    grade: u8,
}

impl Student {
    pub fn new(id: i32, grade: u8) -> Student {
        Student {
            id: id,
            grade: grade,
        }
    }

    pub fn get_id(&self) -> i32 {
        self.id
    }

    pub fn get_grade(&self) -> u8 {
        self.grade
    }
}

#[test]
fn test_student() {
    let stud = Student::new(10i32, 200u8);
    assert_eq!(10i32, stud.id);
}
calixteman commented 4 years ago

I agree with you. Could you give us a way to reproduce please ? Anyway in inspecting the llvm ir for this code, I see 5 functions, new, get_id, get_grade, test_student and a closure for test_student. So I don't know how you can get 8 functions.

redtankd commented 4 years ago

The attachment is my crate. code-coverage.zip

My OS is macOS 10.15.5

My env is

CARGO_INCREMENTAL=0
RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests"

-Cpanic=abort doesn't work for dylib, so I remove it.

The steps are

cargo +nightly test
grcov . -o ./target/debug/lcov.info -s . -t lcov --llvm --branch --ignore-not-existing --ignore "$HOME/.cargo/*" --excl-start "#\[test\]" --excl-br-start "#\[test\]"
genhtml -o ./target/debug/coverage/ --show-details --branch-coverage --no-prefix --highlight --ignore-errors source --legend ./target/debug/lcov.info

From the report I find 8 functions for src/stud/student.rs.


_ZN13code_coverage4stud7student7Student3new17h1e31aa08edd8ed2dE | 0
-- | --
_ZN13code_coverage4stud7student7Student6get_id17h032a0defb68c635dE | 0
_ZN13code_coverage4stud7student7Student6get_id17hcd930dd96a635515E | 0
_ZN13code_coverage4stud7student7Student9get_grade17hbe4d057828c8491cE | 0
_ZN13code_coverage4stud7student7Student9get_grade17hcf71b6946d15f11bE | 0
_ZN13code_coverage4stud7student12test_student17hf23155a333cae1bdE | 1
_ZN13code_coverage4stud7student12test_student28_$u7b$$u7b$closure$u7d$$u7d$17h2ac7417fb8ab4f53E | 1
_ZN13code_coverage4stud7student7Student3new17hbd7550f0bd160415E
SWW13 commented 4 years ago

Demangling the functions clears this a bit up:

code_coverage::stud::student::Student::new | 0
code_coverage::stud::student::Student::get_id | 0
code_coverage::stud::student::Student::get_id | 0
code_coverage::stud::student::Student::get_grade | 0
code_coverage::stud::student::Student::get_grade | 0
code_coverage::stud::student::test_student | 1
code_coverage::stud::student::test_student::{{closure}} | 1
code_coverage::stud::student::Student::new | 1

The functions hit are test_student, a closure in test_student (which is most likely related to assert_eq!) and Student::new. My guess for the duplicate functions is a cargo build which generated another binary (without test code).

MaulingMonkey commented 2 years ago

I've noticed that e.g. the presence of a build.rs can cause duplicate functions like this when fed something like e.g. --binary-path target\debug... presumably because it's using a different profile to build said build script?

llvm-cov accepts a demangler ala: llvm-cov show -Xdemangler=rustfilt - it might be worth having grcov do so as well, and then merge hit counts from identical fns? Or perhaps such things should be handled upstream in llvm-cov itself? Or perhaps just improving display of "identical" fns so users can understand where "duplicate" functions are coming from?