2016-05-20 5 views
5

J'utilise gcov pour la couverture des tests métriques sur une bibliothèque C++ à laquelle je contribue. Pour une raison quelconque, gcov ne reconnaît pas les lignes dans de nombreux fichiers comme exécutables. Sur 160 lignes dans un fichier donné, on dira que 40 d'entre elles sont exécutables. Par exemple:gcov ignorer les lignes dans le fichier source

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

Ici, gcov marque presque toutes les lignes dans le fichier comme non exécutable, mais les pistes 3 exécutions de la ligne 82: un support de fermeture.

Cela n'a aucun sens pour moi et je n'ai pas été en mesure de trouver quelque chose sur ce problème sur le web. Toute aide serait grandement appréciée.

Répondre

1

Voici un organigramme approximatif pour le comportement de gcov (et les logiciels connexes comme gcovr et lcov):

gcov data flow

Figure: données Gcov écoulement

Lorsque le compilateur (GCC) génère le code objet et a été invité à insérer la couverture/instrumentation de profilage, il fait deux choses supplémentaires:

  • Le code objet est instrumenté pour écrire des métriques de couverture dans un fichier .gcda lors de l'exécution.
  • Un fichier .gcno est généré, qui décrit la structure du code objet.

L'utilitaire gcov analyse ensuite les fichiers .gcda et .gcno pour calculer les métriques de couverture. Pour le rapport source annoté, il lit également le fichier source. Parce que c'est le compilateur qui détermine quelle partie du code objet correspond à une ligne particulière, le rapport que vous avez montré est correct: cette ligne n'existe pas. Plus précisément: aucun code objet n'a été généré pour ces lignes de code source. C'est généralement le comportement attendu, car de nombreuses lignes de code source sont juste des déclarations à la compilation.

Dans votre cas, vous avez une classe C++ avec inline functions (toutes les définitions de fonctions dans une définition de classe sont implicitement en ligne). Le compilateur n'a pas besoin de générer de code pour les fonctions inline qui ne sont pas utilisées. Cela serait différent si vous utilisiez des fonctions non intégrées, c'est-à-dire déclariez les fonctions dans un fichier d'en-tête et fournissiez des implémentations dans un fichier .cpp.

Alors, qu'en est-il des trois exécutions d'une accolade de fermeture? Le compilateur doit souvent émettre du code associé à l'initialisation et au nettoyage des objets statiques. Ce code n'est pas vraiment associé à une ligne spécifique et apparaît donc comme faisant partie de la dernière ligne de votre unité de compilation.