Coverage Report

Created: 2026-03-16 19:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/runtime/runtime_profile_counter_tree_node.cpp
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "runtime/runtime_profile_counter_tree_node.h"
19
20
#include <gen_cpp/RuntimeProfile_types.h>
21
22
#include <string>
23
24
#include "runtime/runtime_profile.h"
25
26
namespace doris {
27
28
RuntimeProfileCounterTreeNode RuntimeProfileCounterTreeNode::from_map(
29
        const CounterMap& counterMap, const ChildCounterMap& childCounterMap,
30
42.5k
        const std::string& rootName) {
31
42.5k
    RuntimeProfileCounterTreeNode rootNode;
32
42.5k
    rootNode.name = rootName;
33
42.5k
    if (childCounterMap.empty() || childCounterMap.empty()) {
34
15
        return rootNode;
35
15
    }
36
    // ROOT_COUNTER is a special case, it does not have any counter.
37
42.4k
    if (rootName == RuntimeProfile::ROOT_COUNTER) {
38
252
        rootNode.counter = nullptr;
39
42.2k
    } else {
40
42.2k
        rootNode.counter = counterMap.at(rootName);
41
42.2k
    }
42
43
42.4k
    auto it = childCounterMap.find(rootName);
44
42.4k
    if (it != childCounterMap.end()) {
45
42.2k
        for (const auto& childName : it->second) {
46
42.2k
            rootNode.children.emplace_back(from_map(counterMap, childCounterMap, childName));
47
42.2k
        }
48
263
    }
49
50
42.4k
    return rootNode;
51
42.5k
}
52
53
// Prune the tree by:
54
// 1. Remove all leaf nodes whose level is greater than the given level.
55
// 2. Remove all nodes whose children are all pruned.
56
RuntimeProfileCounterTreeNode RuntimeProfileCounterTreeNode::prune_the_tree(
57
42.4k
        RuntimeProfileCounterTreeNode node, int64_t level) {
58
    // Iterate through the children and prune them recursively
59
84.7k
    for (auto it = node.children.begin(); it != node.children.end();) {
60
42.2k
        *it = prune_the_tree(*it, level);
61
42.2k
        if (it->children.empty() && it->counter->level() > level) {
62
7
            it = node.children.erase(it);
63
42.2k
        } else {
64
42.2k
            ++it;
65
42.2k
        }
66
42.2k
    }
67
42.4k
    return node;
68
42.4k
}
69
70
void RuntimeProfileCounterTreeNode::to_thrift(
71
        std::vector<TCounter>& tcounter,
72
42.4k
        std::map<std::string, std::set<std::string>>& child_counter_map) const {
73
42.4k
    if (name != RuntimeProfile::ROOT_COUNTER && counter != nullptr) {
74
42.2k
        if (auto* highWaterMarkCounter =
75
42.2k
                    dynamic_cast<RuntimeProfile::HighWaterMarkCounter*>(counter)) {
76
            // HighWaterMarkCounter will convert itself to two counters, one is current, the other is peak.
77
2
            tcounter.push_back(highWaterMarkCounter->to_thrift(name));
78
2
            tcounter.push_back(highWaterMarkCounter->to_thrift_peak(name + "Peak"));
79
2
            child_counter_map[highWaterMarkCounter->parent_name()].insert(name + "Peak");
80
42.2k
        } else if (auto* nonZeroCounter = dynamic_cast<RuntimeProfile::NonZeroCounter*>(counter)) {
81
1
            if (nonZeroCounter->value() > 0) {
82
0
                tcounter.push_back(to_thrift());
83
1
            } else {
84
                // Erase non-zero counter from its parent's child counter map.
85
1
                child_counter_map[nonZeroCounter->parent_name()].erase(name);
86
                // Adn skipping all child conter of this counter.
87
1
                return;
88
1
            }
89
42.2k
        } else {
90
42.2k
            tcounter.push_back(to_thrift());
91
42.2k
        }
92
42.2k
    }
93
94
42.4k
    for (const auto& child : children) {
95
        // insert before child doing to_thrift, so that we can remove it if it is zero.
96
42.2k
        (child_counter_map)[name].insert(child.name);
97
42.2k
        child.to_thrift(tcounter, child_counter_map);
98
42.2k
    }
99
42.4k
}
100
101
void RuntimeProfileCounterTreeNode::to_proto(
102
        google::protobuf::RepeatedPtrField<PProfileCounter>* proto_counters,
103
19
        google::protobuf::Map<std::string, PProfileChildCounterSet>* child_counter_map) const {
104
19
    if (name != RuntimeProfile::ROOT_COUNTER && counter != nullptr) {
105
8
        if (auto* highWaterMarkCounter =
106
8
                    dynamic_cast<RuntimeProfile::HighWaterMarkCounter*>(counter)) {
107
            // Convert both current and peak values
108
0
            *proto_counters->Add() = highWaterMarkCounter->to_proto(name);
109
0
            *proto_counters->Add() = highWaterMarkCounter->to_proto_peak(name + "Peak");
110
111
0
            (*(*child_counter_map)[highWaterMarkCounter->parent_name()].mutable_child_counters())
112
0
                    .Add(name + "Peak");
113
114
8
        } else if (auto* nonZeroCounter = dynamic_cast<RuntimeProfile::NonZeroCounter*>(counter)) {
115
0
            if (nonZeroCounter->value() > 0) {
116
0
                *proto_counters->Add() = to_proto();
117
0
            } else {
118
                // Skip zero-valued counter and remove from parent's child map
119
0
                auto it = child_counter_map->find(nonZeroCounter->parent_name());
120
0
                if (it != child_counter_map->end()) {
121
0
                    auto* set = it->second.mutable_child_counters();
122
0
                    auto remove_it = std::find(set->begin(), set->end(), name);
123
0
                    if (remove_it != set->end()) set->erase(remove_it);
124
0
                }
125
0
                return;
126
0
            }
127
8
        } else {
128
8
            *proto_counters->Add() = to_proto();
129
8
        }
130
8
    }
131
132
19
    for (const auto& child : children) {
133
8
        (*child_counter_map)[name].add_child_counters(child.name);
134
8
        child.to_proto(proto_counters, child_counter_map);
135
8
    }
136
19
}
137
138
42.2k
TCounter RuntimeProfileCounterTreeNode::to_thrift() const {
139
42.2k
    TCounter tcounter;
140
42.2k
    if (counter != nullptr) {
141
42.2k
        tcounter = counter->to_thrift(name);
142
42.2k
    } else {
143
0
        tcounter.name = name;
144
0
    }
145
42.2k
    return tcounter;
146
42.2k
}
147
148
8
PProfileCounter RuntimeProfileCounterTreeNode::to_proto() const {
149
8
    PProfileCounter pcounter;
150
151
8
    if (counter != nullptr) {
152
8
        pcounter = counter->to_proto(name);
153
8
    } else {
154
0
        pcounter.set_name(name);
155
0
    }
156
157
8
    return pcounter;
158
8
}
159
160
} // namespace doris