ClickHouse

Форк
0
/
coverage.cpp 
163 строки · 5.1 Кб
1
#if defined(SANITIZE_COVERAGE)
2

3
#include <DataTypes/DataTypeArray.h>
4
#include <DataTypes/DataTypesNumber.h>
5
#include <Columns/ColumnArray.h>
6
#include <Columns/ColumnVector.h>
7
#include <Columns/ColumnsNumber.h>
8
#include <Columns/ColumnConst.h>
9
#include <Columns/ColumnsNumber.h>
10
#include <Functions/FunctionFactory.h>
11
#include <Functions/IFunction.h>
12
#include <Interpreters/Context.h>
13

14
#include <base/coverage.h>
15

16

17
namespace DB
18
{
19

20
namespace
21
{
22

23
enum class Kind
24
{
25
    Current,
26
    Cumulative,
27
    All
28
};
29

30
/** If ClickHouse is build with coverage instrumentation, returns an array
31
  * of currently accumulated (`coverageCurrent`)
32
  * or accumulated since the startup (`coverageCumulative`)
33
  * or all possible (`coverageAll`) unique code addresses.
34
  */
35
class FunctionCoverage : public IFunction
36
{
37
private:
38
    Kind kind;
39

40
public:
41
    String getName() const override
42
    {
43
        return kind == Kind::Current ? "coverage" : "coverageAll";
44
    }
45

46
    explicit FunctionCoverage(Kind kind_) : kind(kind_)
47
    {
48
    }
49

50
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override
51
    {
52
        return false;
53
    }
54

55
    size_t getNumberOfArguments() const override
56
    {
57
        return 0;
58
    }
59

60
    bool isDeterministic() const override
61
    {
62
        return false;
63
    }
64

65
    DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override
66
    {
67
        return std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt64>());
68
    }
69

70
    ColumnPtr executeImpl(const ColumnsWithTypeAndName &, const DataTypePtr &, size_t input_rows_count) const override
71
    {
72
        auto coverage_table = kind == Kind::Current
73
            ? getCurrentCoverage()
74
            : (kind == Kind::Cumulative
75
                ? getCumulativeCoverage()
76
                : getAllInstrumentedAddresses());
77

78
        auto column_addresses = ColumnUInt64::create();
79
        auto & data = column_addresses->getData();
80

81
        for (auto ptr : coverage_table)
82
            if (ptr)
83
                data.push_back(ptr);
84

85
        auto column_array = ColumnArray::create(
86
            std::move(column_addresses),
87
            ColumnArray::ColumnOffsets::create(1, data.size()));
88

89
        return ColumnConst::create(std::move(column_array), input_rows_count);
90
    }
91
};
92

93
}
94

95
REGISTER_FUNCTION(Coverage)
96
{
97
    factory.registerFunction("coverageCurrent", [](ContextPtr){ return std::make_shared<FunctionCoverage>(Kind::Current); },
98
        FunctionDocumentation
99
        {
100
            .description=R"(
101
This function is only available if ClickHouse was built with the SANITIZE_COVERAGE=1 option.
102

103
It returns an array of unique addresses (a subset of the instrumented points in code) in the code
104
encountered at runtime after the previous coverage reset (with the `SYSTEM RESET COVERAGE` query) or after server startup.
105

106
[example:functions]
107

108
The order of array elements is undetermined.
109

110
You can use another function, `coverageAll` to find all instrumented addresses in the code to compare and calculate the percentage.
111

112
You can process the addresses with the `addressToSymbol` (possibly with `demangle`) and `addressToLine` functions
113
to calculate symbol-level, file-level, or line-level coverage.
114

115
If you run multiple tests sequentially and reset the coverage with the `SYSTEM RESET COVERAGE` query between the tests,
116
you can obtain a coverage information for every test in isolation, to find which functions are covered by which tests and vise-versa.
117

118
By default, every *basic block* in the code is covered, which roughly means - a sequence of instructions without jumps,
119
e.g. a body of for loop without ifs, or a single branch of if.
120

121
See https://clang.llvm.org/docs/SanitizerCoverage.html for more information.
122
)",
123
            .examples{
124
                {"functions", "SELECT DISTINCT demangle(addressToSymbol(arrayJoin(coverageCurrent())))", ""}},
125
            .categories{"Introspection"}
126
        });
127

128
    factory.registerFunction("coverageCumulative", [](ContextPtr){ return std::make_shared<FunctionCoverage>(Kind::Cumulative); },
129
        FunctionDocumentation
130
        {
131
            .description=R"(
132
This function is only available if ClickHouse was built with the SANITIZE_COVERAGE=1 option.
133

134
It returns an array of unique addresses (a subset of the instrumented points in code) in the code
135
encountered at runtime after server startup.
136

137
In contrast to `coverageCurrent` it cannot be reset with the `SYSTEM RESET COVERAGE`.
138

139
See the `coverageCurrent` function for the details.
140
)",
141
            .categories{"Introspection"}
142
        });
143

144
    factory.registerFunction("coverageAll", [](ContextPtr){ return std::make_shared<FunctionCoverage>(Kind::All); },
145
        FunctionDocumentation
146
        {
147
            .description=R"(
148
This function is only available if ClickHouse was built with the SANITIZE_COVERAGE=1 option.
149

150
It returns an array of all unique addresses in the code instrumented for coverage
151
- all possible addresses that can appear in the result of the `coverage` function.
152

153
You can use this function, and the `coverage` function to compare and calculate the coverage percentage.
154

155
See the `coverageCurrent` function for the details.
156
)",
157
            .categories{"Introspection"}
158
        });
159
}
160

161
}
162

163
#endif
164

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.