Gcov ignores lines in source file

I use gcov to cover metric testing in the C ++ library, to which I contribute. For some reason, gcov does not recognize lines in many files as executable. From 160-some lines in this file it will be said that 40 of them are executed. For instance:

-: 0:Source:../evo/NK.h -: 0:Graph:test_driver.gcno -: 0:Data:test_driver.gcda -: 0:Runs:1 -: 0:Programs:1 -: 1:// This file is part of Empirical, https://github.com/devosoft/Empirical -: 2:// Copyright (C) Michigan State University, 2016. -: 3:// Released under the MIT Software license; see doc/LICENSE -: 4:// -: 5:// -: 6:// This file provides code to build NK-based algorithms. -: 7: -: 8:#ifndef EMP_EVO_NK_H -: 9:#define EMP_EVO_NK_H -: 10: -: 11:#include <array> -: 12: -: 13:#include "../tools/BitVector.h" -: 14:#include "../tools/const_utils.h" -: 15:#include "../tools/Random.h" -: 16:#include "../tools/vector.h" -: 17: -: 18:namespace emp { -: 19:namespace evo { -: 20: -: 21: class NKLandscape { -: 22: private: -: 23: const uint32_t N; -: 24: const uint32_t K; -: 25: const uint32_t state_count; -: 26: const uint32_t total_count; -: 27: emp::vector< emp::vector<double> > landscape; -: 28: -: 29: public: -: 30: NKLandscape() = delete; -: 31: NKLandscape(const NKLandscape &) = delete; -: 32: NKLandscape(int _N, int _K, emp::Random & random) -: 33: : N(_N), K(_K) -: 34: , state_count(emp::constant::IntPow<uint32_t>(2,K+1)) -: 35: , total_count(N * state_count) -: 36: , landscape(N) -: 37: { -: 38: for ( auto & ltable : landscape) { -: 39: ltable.resize(state_count); -: 40: for (double & pos : ltable) { -: 41: pos = random.GetDouble(); -: 42: } -: 43: } -: 44: } -: 45: ~NKLandscape() { ; } -: 46: NKLandscape & operator=(const NKLandscape &) = delete; -: 47: -: 48: int GetN() const { return N; } -: 49: int GetK() const { return K; } -: 50: int GetStateCount() const { return state_count; } -: 51: int GetTotalCount() const { return total_count; } -: 52: -: 53: double GetFitness(int n, uint32_t state) const { -: 54: emp_assert(state < state_count, state, state_count); -: 55: return landscape[n][state]; -: 56: } -: 57: double GetFitness( std::vector<uint32_t> states ) const { -: 58: emp_assert(states.size() == N); -: 59: double total = landscape[0][states[0]]; -: 60: for (int i = 1; i < N; i++) total += GetFitness(i,states[i]); -: 61: return total; -: 62: } -: 63: double GetFitness(BitVector genome) const { -: 64: emp_assert(genome.GetSize() == N); -: 65: -: 66: // Use a double-length genome to easily handle wrap-around. -: 67: genome.Resize(N*2); -: 68: genome |= (genome << N); -: 69: -: 70: double total = 0.0; -: 71: uint32_t mask = emp::constant::MaskLow<uint32_t>(K+1); -: 72: for (int i = 0; i < N; i++) { -: 73: const uint32_t cur_val = (genome >> i).GetUInt(0) & mask; -: 74: const double cur_fit = GetFitness(i, cur_val); -: 75: total += cur_fit; -: 76: } -: 77: return total; -: 78: } -: 79: }; -: 80: -: 81:} 3: 82:} -: 83: -: 84:#endif 

Here gcov marks almost all lines in the file as unexecutable, but tracks 3 of line 82 execution: one closing bracket.

This makes no sense to me, and I could not find anything about this issue on the Internet. Any help would be greatly appreciated.

+5
source share
1 answer

Here's a rough block diagram of the behavior of gcov (and related software such as gcovr and lcov):

gcov data stream

Figure: gcov data stream

When the compiler (GCC) generates object code and was asked to insert equipment for coverage / profiling, it performs two additional functions:

  • The object code is for writing coverage metrics to a .gcda file after execution.
  • A .gcno file is created that describes the structure of the object code.

The gcov utility then analyzes the .gcda and .gcno files to calculate coverage rates. For annotated source report, it also reads the source file.

Since it is the compiler that determines which part of the object code corresponds to a particular line, the report you showed is correct: this line does not exist. More precisely: no object code was created for these lines of source code. This is usually the expected behavior, since many lines of source code are only compile-time declarations.

In your case, you have a C ++ class with built-in functions (any function definitions in the class definition are implicitly built-in). The compiler does not need to generate code for built-in functions that are not used. This would be different if you use non-built-in functions, i.e. Declare functions in the header file and provide implementations in the .cpp file.

So what happened to the three executions of the closing brace? The compiler often needs to emit some code related to initializing and cleaning static objects. This code is not actually associated with a particular line and therefore appears as part of the last line in your compiler.

+1
source

All Articles