2016-05-20 40 views
5

Używam gcov do metrycznego zakresu testów w bibliotece C++, do której się przyczyniam. Z jakiegoś powodu, gcov nie rozpoznaje linii w wielu plikach jako wykonywalnych. Spośród 160-niektórych wierszy w danym pliku powie, że 40 z nich jest wykonalnych. Na przykład:linie ignorujące gcov w pliku źródłowym

  -: 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 

Tutaj gcov oznacza prawie wszystkie linie w pliku jako non-wykonywalnego, ale tory 3 egzekucje linii 82: pojedynczy wspornik zamknięcia.

To nie ma dla mnie sensu i nie mogłem znaleźć nic na temat tego problemu w sieci. Każda pomoc będzie bardzo ceniona.

Odpowiedz

1

Oto szorstki schemat blokowy dla zachowania gcov (i związane z nimi oprogramowanie jak gcovr i lcov):

gcov data flow

Figura: dane gcov płynąć

Gdy kompilator (GCC) generuje kod obiektowy i został poproszony o wstawienie oprzyrządowania/profilowania, robi dwie dodatkowe rzeczy:

  • Kod obiektowy jest przystosowany do zapisywania danych pokrycia w pliku .gcda po wykonaniu.
  • Generowany jest plik .gcno, który opisuje strukturę kodu obiektu.

Narzędzie gcov następnie analizuje pliki .gcda i .gcno w celu obliczenia wskaźników zasięgu. W przypadku adnotowanego raportu źródłowego odczytuje również plik źródłowy.

Ponieważ to kompilator określa, która część kodu obiektu odpowiada określonej linii, raport, który pokazałeś, jest poprawny: ta linia nie istnieje. Dokładniej: nie wygenerowano kodu obiektowego dla tych linii kodu źródłowego. Jest to zazwyczaj oczekiwane zachowanie, ponieważ wiele linii kodu źródłowego jest po prostu deklaracjami w czasie kompilacji.

W twoim przypadku masz klasę C++ z inline functions (dowolne definicje funkcji w definicji klasy są niejawnie wbudowane). Kompilator nie musi generować kodu dla funkcji wbudowanych, które nie są używane. Byłoby inaczej, gdybyś używał funkcji nieliniowych, tj. Deklarował funkcje w pliku nagłówkowym i dostarczał implementacje w pliku .cpp.

Co z trzema egzekucjami klamry zamykającej? Kompilator często musi emitować kod związany z inicjowaniem i czyszczeniem obiektów statycznych. Ten kod nie jest naprawdę związany z konkretną linią i dlatego pojawia się jako część ostatniego wiersza w jednostce kompilacji.