gcov игнорирует строки в исходном файле
Я использую gcov для покрытия метрических тестов в библиотеке C++, в которую я внес вклад. По какой-то причине gcov не распознает строки во многих файлах как исполняемые. Из 160 строк в данном файле будет сказано, что 40 из них являются исполняемыми. Например:
-: 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
Здесь gcov отмечает почти все строки в файле как неисполняемые, но отслеживает 3 выполнения строки 82: одну закрывающую скобку.
Это не имеет смысла для меня, и я не смог найти что-либо об этой проблеме в Интернете. Любая помощь будет принята с благодарностью.
1 ответ
Вот приблизительная блок-схема поведения gcov (и связанных программ, таких как gcovr и lcov):
Рисунок: поток данных gcov
Когда компилятор (GCC) генерирует объектный код и получает запрос на вставку инструментария покрытия / профилирования, он делает две дополнительные вещи:
- Объектный код предназначен для записи метрик покрытия в файл.gcda после выполнения.
- Создается файл.gcno, который описывает структуру объектного кода.
Затем утилита gcov анализирует файлы.gcda и.gcno для расчета метрик покрытия. Для аннотированного исходного отчета он также читает исходный файл.
Поскольку именно компилятор определяет, какая часть объектного кода соответствует конкретной строке, показанный вами отчет верен: эта строка не существует. Точнее: для этих строк исходного кода не было сгенерировано объектного кода. Как правило, это ожидаемое поведение, поскольку многие строки исходного кода являются просто объявлениями времени компиляции.
В вашем случае у вас есть класс C++ со встроенными функциями (любые определения функций в определении класса неявно встроены). Компилятору не нужно генерировать код для встроенных функций, которые не используются. Это было бы иначе, если вы используете не встроенные функции, то есть объявляете функции в заголовочном файле и предоставляете реализации в файле.cpp.
Так что случилось с тремя исполнениями закрывающей скобки? Компилятору часто требуется испускать некоторый код, связанный с инициализацией и очисткой статических объектов. Этот код на самом деле не связан с конкретной строкой и поэтому отображается как часть последней строки в вашем модуле компиляции.