Coverage Report

Created: 2026-04-13 11:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/runtime/runtime_profile.h
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
// This file is copied from
18
// https://github.com/apache/impala/blob/branch-2.9.0/be/src/util/runtime-profile.h
19
// and modified by Doris
20
21
#pragma once
22
23
#include <gen_cpp/Metrics_types.h>
24
#include <gen_cpp/RuntimeProfile_types.h>
25
#include <gen_cpp/runtime_profile.pb.h>
26
#include <glog/logging.h>
27
#include <stdint.h>
28
29
#include <algorithm>
30
#include <atomic>
31
#include <cstdint>
32
#include <functional>
33
#include <iostream>
34
#include <map>
35
#include <memory>
36
#include <mutex>
37
#include <set>
38
#include <string>
39
#include <utility>
40
#include <vector>
41
42
#include "common/compiler_util.h" // IWYU pragma: keep
43
#include "common/logging.h"
44
#include "core/binary_cast.hpp"
45
#include "util/pretty_printer.h"
46
#include "util/stopwatch.hpp"
47
48
namespace doris {
49
class TRuntimeProfileNode;
50
class TRuntimeProfileTree;
51
class RuntimeProfileCounterTreeNode;
52
53
// Some macro magic to generate unique ids using __COUNTER__
54
310M
#define CONCAT_IMPL(x, y) x##y
55
310M
#define MACRO_CONCAT(x, y) CONCAT_IMPL(x, y)
56
57
#define ADD_LABEL_COUNTER(profile, name) (profile)->add_counter(name, TUnit::NONE)
58
#define ADD_LABEL_COUNTER_WITH_LEVEL(profile, name, level) \
59
    (profile)->add_counter_with_level(name, TUnit::NONE, level)
60
62.9M
#define ADD_COUNTER(profile, name, type) (profile)->add_counter(name, type)
61
#define ADD_COUNTER_WITH_LEVEL(profile, name, type, level) \
62
13.8M
    (profile)->add_counter_with_level(name, type, level)
63
48.8M
#define ADD_TIMER(profile, name) (profile)->add_counter(name, TUnit::TIME_NS)
64
#define ADD_TIMER_WITH_LEVEL(profile, name, level) \
65
33.2M
    (profile)->add_counter_with_level(name, TUnit::TIME_NS, level)
66
2.40M
#define ADD_CHILD_COUNTER(profile, name, type, parent) (profile)->add_counter(name, type, parent)
67
#define ADD_CHILD_COUNTER_WITH_LEVEL(profile, name, type, parent, level) \
68
15.2M
    (profile)->add_counter(name, type, parent, level)
69
17.4M
#define ADD_CHILD_TIMER(profile, name, parent) (profile)->add_counter(name, TUnit::TIME_NS, parent)
70
#define ADD_CHILD_TIMER_WITH_LEVEL(profile, name, parent, level) \
71
15.9M
    (profile)->add_counter(name, TUnit::TIME_NS, parent, level)
72
104M
#define SCOPED_TIMER(c) ScopedTimer<MonotonicStopWatch> MACRO_CONCAT(SCOPED_TIMER, __COUNTER__)(c)
73
#define SCOPED_TIMER_ATOMIC(c) \
74
    ScopedTimer<MonotonicStopWatch, std::atomic_bool> MACRO_CONCAT(SCOPED_TIMER, __COUNTER__)(c)
75
#define SCOPED_CPU_TIMER(c) \
76
16.2M
    ScopedTimer<ThreadCpuStopWatch> MACRO_CONCAT(SCOPED_TIMER, __COUNTER__)(c)
77
#define CANCEL_SAFE_SCOPED_TIMER(c, is_cancelled) \
78
    ScopedTimer<MonotonicStopWatch> MACRO_CONCAT(SCOPED_TIMER, __COUNTER__)(c, is_cancelled)
79
#define SCOPED_RAW_TIMER(c)                                                                  \
80
189M
    doris::ScopedRawTimer<doris::MonotonicStopWatch, int64_t> MACRO_CONCAT(SCOPED_RAW_TIMER, \
81
189M
                                                                           __COUNTER__)(c)
82
#define SCOPED_ATOMIC_TIMER(c)                                                                 \
83
90.6k
    ScopedRawTimer<MonotonicStopWatch, std::atomic<int64_t>> MACRO_CONCAT(SCOPED_ATOMIC_TIMER, \
84
90.6k
                                                                          __COUNTER__)(c)
85
236M
#define COUNTER_UPDATE(c, v) (c)->update(v)
86
35.2M
#define COUNTER_SET(c, v) (c)->set(v)
87
88
class ObjectPool;
89
90
// Runtime profile is a group of profiling counters.  It supports adding named counters
91
// and being able to serialize and deserialize them.
92
// The profiles support a tree structure to form a hierarchy of counters.
93
// Runtime profiles supports measuring wall clock rate based counters.  There is a
94
// single thread per process that will convert an amount (i.e. bytes) counter to a
95
// corresponding rate based counter.  This thread wakes up at fixed intervals and updates
96
// all of the rate counters.
97
// Thread-safe.
98
class RuntimeProfile {
99
public:
100
    static std::unique_ptr<RuntimeProfile> from_thrift(const TRuntimeProfileTree& node);
101
102
    static std::unique_ptr<RuntimeProfile> from_proto(const PRuntimeProfileTree& tree);
103
104
14
    static PProfileUnit unit_to_proto(const TUnit::type& type) {
105
14
        switch (type) {
106
11
        case TUnit::UNIT: {
107
11
            return PProfileUnit::UNIT;
108
0
        }
109
0
        case TUnit::UNIT_PER_SECOND: {
110
0
            return PProfileUnit::UNIT_PER_SECOND;
111
0
        }
112
0
        case TUnit::CPU_TICKS: {
113
0
            return PProfileUnit::CPU_TICKS;
114
0
        }
115
3
        case TUnit::BYTES: {
116
3
            return PProfileUnit::BYTES;
117
0
        }
118
0
        case TUnit::BYTES_PER_SECOND: {
119
0
            return PProfileUnit::BYTES_PER_SECOND;
120
0
        }
121
0
        case TUnit::TIME_NS: {
122
0
            return PProfileUnit::TIME_NS;
123
0
        }
124
0
        case TUnit::DOUBLE_VALUE: {
125
0
            return PProfileUnit::DOUBLE_VALUE;
126
0
        }
127
0
        case TUnit::NONE: {
128
0
            return PProfileUnit::NONE;
129
0
        }
130
0
        case TUnit::TIME_MS: {
131
0
            return PProfileUnit::TIME_MS;
132
0
        }
133
0
        case TUnit::TIME_S: {
134
0
            return PProfileUnit::TIME_S;
135
0
        }
136
0
        default: {
137
0
            DCHECK(false);
138
0
            return PProfileUnit::NONE;
139
0
        }
140
14
        }
141
14
    }
142
143
14
    static TUnit::type unit_to_thrift(const PProfileUnit& unit) {
144
14
        switch (unit) {
145
12
        case PProfileUnit::UNIT: {
146
12
            return TUnit::UNIT;
147
0
        }
148
0
        case PProfileUnit::UNIT_PER_SECOND: {
149
0
            return TUnit::UNIT_PER_SECOND;
150
0
        }
151
0
        case PProfileUnit::CPU_TICKS: {
152
0
            return TUnit::CPU_TICKS;
153
0
        }
154
2
        case PProfileUnit::BYTES: {
155
2
            return TUnit::BYTES;
156
0
        }
157
0
        case PProfileUnit::BYTES_PER_SECOND: {
158
0
            return TUnit::BYTES_PER_SECOND;
159
0
        }
160
0
        case PProfileUnit::TIME_NS: {
161
0
            return TUnit::TIME_NS;
162
0
        }
163
0
        case PProfileUnit::DOUBLE_VALUE: {
164
0
            return TUnit::DOUBLE_VALUE;
165
0
        }
166
0
        case PProfileUnit::NONE: {
167
0
            return TUnit::NONE;
168
0
        }
169
0
        case PProfileUnit::TIME_MS: {
170
0
            return TUnit::TIME_MS;
171
0
        }
172
0
        case PProfileUnit::TIME_S: {
173
0
            return TUnit::TIME_S;
174
0
        }
175
0
        default: {
176
0
            DCHECK(false);
177
0
            return TUnit::NONE;
178
0
        }
179
14
        }
180
14
    }
181
182
    // The root counter name for all top level counters.
183
    static const std::string ROOT_COUNTER;
184
    class Counter {
185
    public:
186
        Counter(TUnit::type type, int64_t value = 0, int64_t level = 3)
187
244M
                : _value(value), _type(type), _level(level) {}
188
248M
        virtual ~Counter() = default;
189
190
6.31k
        virtual Counter* clone() const { return new Counter(type(), value(), _level); }
191
192
380M
        virtual void update(int64_t delta) { _value.fetch_add(delta, std::memory_order_relaxed); }
193
194
0
        void bit_or(int64_t delta) { _value.fetch_or(delta, std::memory_order_relaxed); }
195
196
17.1M
        virtual void set(int64_t value) { _value.store(value, std::memory_order_relaxed); }
197
198
0
        virtual void set(double value) {
199
0
            DCHECK_EQ(sizeof(value), sizeof(int64_t));
200
0
            _value.store(binary_cast<double, int64_t>(value), std::memory_order_relaxed);
201
0
        }
202
203
12.7M
        virtual int64_t value() const { return _value.load(std::memory_order_relaxed); }
204
205
0
        virtual double double_value() const {
206
0
            return binary_cast<int64_t, double>(_value.load(std::memory_order_relaxed));
207
0
        }
208
209
369k
        virtual TCounter to_thrift(const std::string& name) const {
210
369k
            TCounter counter;
211
369k
            counter.name = name;
212
369k
            counter.value = this->value();
213
369k
            counter.type = this->type();
214
369k
            counter.__set_level(this->_level);
215
369k
            return counter;
216
369k
        }
217
218
8
        virtual PProfileCounter to_proto(const std::string& name) const {
219
8
            PProfileCounter counter;
220
8
            counter.set_name(name);
221
8
            counter.set_value(this->value());
222
8
            counter.set_type(unit_to_proto(this->type()));
223
8
            counter.set_level(this->value());
224
8
            return counter;
225
8
        }
226
227
        virtual void pretty_print(std::ostream* s, const std::string& prefix,
228
650
                                  const std::string& name) const {
229
650
            std::ostream& stream = *s;
230
650
            stream << prefix << "   - " << name << ": "
231
650
                   << PrettyPrinter::print(_value.load(std::memory_order_relaxed), type())
232
650
                   << std::endl;
233
650
        }
234
235
120M
        TUnit::type type() const { return _type; }
236
237
1.13M
        virtual int64_t level() const { return _level; }
238
239
        void set_level(int64_t level) { _level = level; }
240
241
        bool operator==(const Counter& other) const;
242
243
    private:
244
        friend class RuntimeProfile;
245
        friend class RuntimeProfileCounterTreeNode;
246
247
        std::atomic<int64_t> _value;
248
        TUnit::type _type;
249
        int64_t _level;
250
    };
251
252
    /// A counter that keeps track of the highest value seen (reporting that
253
    /// as value()) and the current value.
254
    class HighWaterMarkCounter : public Counter {
255
    public:
256
        HighWaterMarkCounter(TUnit::type unit, int64_t level, const std::string& parent_name,
257
                             int64_t value = 0, int64_t current_value = 0)
258
14.7M
                : Counter(unit, value, level),
259
14.7M
                  current_value_(current_value),
260
14.7M
                  _parent_name(parent_name) {}
261
262
24.7k
        virtual Counter* clone() const override {
263
24.7k
            return new HighWaterMarkCounter(type(), level(), parent_name(), value(),
264
24.7k
                                            current_value());
265
24.7k
        }
266
267
6.87M
        void add(int64_t delta) {
268
6.87M
            current_value_.fetch_add(delta, std::memory_order_relaxed);
269
6.87M
            if (delta > 0) {
270
2.08M
                UpdateMax(current_value_);
271
2.08M
            }
272
6.87M
        }
273
4.12M
        virtual void update(int64_t delta) override { add(delta); }
274
275
29.5k
        TCounter to_thrift(const std::string& name) const override {
276
29.5k
            TCounter counter;
277
29.5k
            counter.name = std::move(name);
278
29.5k
            counter.value = current_value();
279
29.5k
            counter.type = type();
280
29.5k
            counter.__set_level(level());
281
29.5k
            return counter;
282
29.5k
        }
283
284
0
        PProfileCounter to_proto(const std::string& name) const override {
285
0
            PProfileCounter counter;
286
0
            counter.set_name(name);
287
0
            counter.set_value(current_value());
288
0
            counter.set_type(unit_to_proto(this->type()));
289
0
            counter.set_level(this->value());
290
0
            return counter;
291
0
        }
292
293
29.5k
        TCounter to_thrift_peak(std::string name) {
294
29.5k
            TCounter counter;
295
29.5k
            counter.name = std::move(name);
296
29.5k
            counter.value = value();
297
29.5k
            counter.type = type();
298
29.5k
            counter.__set_level(level());
299
29.5k
            return counter;
300
29.5k
        }
301
302
0
        PProfileCounter to_proto_peak(const std::string& name) const {
303
0
            return Counter::to_proto(name);
304
0
        }
305
306
        virtual void pretty_print(std::ostream* s, const std::string& prefix,
307
354
                                  const std::string& name) const override {
308
354
            std::ostream& stream = *s;
309
354
            stream << prefix << "   - " << name
310
354
                   << " Current: " << PrettyPrinter::print(current_value(), type()) << " (Peak: "
311
354
                   << PrettyPrinter::print(_value.load(std::memory_order_relaxed), type()) << ")"
312
354
                   << std::endl;
313
354
        }
314
315
        /// Tries to increase the current value by delta. If current_value() + delta
316
        /// exceeds max, return false and current_value is not changed.
317
0
        bool try_add(int64_t delta, int64_t max) {
318
0
            while (true) {
319
0
                int64_t old_val = current_value_.load(std::memory_order_relaxed);
320
0
                int64_t new_val = old_val + delta;
321
0
                if (UNLIKELY(new_val > max)) return false;
322
0
                if (LIKELY(current_value_.compare_exchange_weak(old_val, new_val,
323
0
                                                                std::memory_order_relaxed))) {
324
0
                    UpdateMax(new_val);
325
0
                    return true;
326
0
                }
327
0
            }
328
0
        }
329
330
21.6M
        void set(int64_t v) override {
331
21.6M
            current_value_.store(v, std::memory_order_relaxed);
332
21.6M
            UpdateMax(v);
333
21.6M
        }
334
335
58.5k
        int64_t current_value() const { return current_value_.load(std::memory_order_relaxed); }
336
337
54.3k
        std::string parent_name() const { return _parent_name; }
338
339
    private:
340
        /// Set '_value' to 'v' if 'v' is larger than '_value'. The entire operation is
341
        /// atomic.
342
23.7M
        void UpdateMax(int64_t v) {
343
23.7M
            while (true) {
344
23.7M
                int64_t old_max = _value.load(std::memory_order_relaxed);
345
23.7M
                int64_t new_max = std::max(old_max, v);
346
23.7M
                if (new_max == old_max) {
347
22.1M
                    break; // Avoid atomic update.
348
22.1M
                }
349
1.59M
                if (LIKELY(_value.compare_exchange_weak(old_max, new_max,
350
1.59M
                                                        std::memory_order_relaxed))) {
351
1.59M
                    break;
352
1.59M
                }
353
1.59M
            }
354
23.7M
        }
355
356
        /// The current value of the counter. _value in the super class represents
357
        /// the high water mark.
358
        std::atomic<int64_t> current_value_;
359
360
        const std::string _parent_name;
361
    };
362
363
    using DerivedCounterFunction = std::function<int64_t()>;
364
365
    // A DerivedCounter also has a name and type, but the value is computed.
366
    // Do not call Set() and Update().
367
    class DerivedCounter : public Counter {
368
    public:
369
        DerivedCounter(TUnit::type type, const DerivedCounterFunction& counter_fn,
370
                       int64_t value = 0, int64_t level = 1)
371
653k
                : Counter(type, value, level), _counter_fn(counter_fn) {}
372
373
0
        virtual Counter* clone() const override {
374
0
            return new DerivedCounter(type(), _counter_fn, value(), level());
375
0
        }
376
377
5.69k
        int64_t value() const override { return _counter_fn(); }
378
379
    private:
380
        DerivedCounterFunction _counter_fn;
381
    };
382
383
    using ConditionCounterFunction = std::function<bool(int64_t, int64_t)>;
384
385
    // ConditionCounter is a specialized counter that only updates its value when a specific condition is met.
386
    // It uses a condition function (condition_func) to determine when the counter's value should be updated.
387
    // This type of counter is particularly useful for tracking maximum values, minimum values, or other metrics
388
    // that should only be updated when they meet certain criteria.
389
    // For example, it can be used to record the maximum value of a specific metric during query execution,
390
    // or to update the counter only when a new value exceeds some threshold.
391
    class ConditionCounter : public Counter {
392
    public:
393
        ConditionCounter(TUnit::type type, const ConditionCounterFunction& condition_func,
394
                         int64_t level = 2, int64_t condition = 0, int64_t value = 0)
395
4.22k
                : Counter(type, value, level),
396
4.22k
                  _condition(condition),
397
4.22k
                  _stored_value(value),
398
4.22k
                  _condition_func(condition_func) {}
399
400
0
        Counter* clone() const override {
401
0
            std::lock_guard<std::mutex> l(_mutex);
402
0
            return new ConditionCounter(type(), _condition_func, _condition, value(), level());
403
0
        }
404
405
7
        int64_t value() const override {
406
7
            std::lock_guard<std::mutex> l(_mutex);
407
7
            return _stored_value;
408
7
        }
409
410
5.68k
        void conditional_update(int64_t c, int64_t v) {
411
5.68k
            std::lock_guard<std::mutex> l(_mutex);
412
5.68k
            if (_condition_func(_condition, c)) {
413
5.28k
                _stored_value = v;
414
5.28k
                _condition = c;
415
5.28k
            }
416
5.68k
        }
417
418
    private:
419
        mutable std::mutex _mutex;
420
        int64_t _condition;
421
        int64_t _stored_value;
422
        ConditionCounterFunction _condition_func;
423
    };
424
425
    // NonZeroCounter will not be converted to Thrift if the value is 0.
426
    class NonZeroCounter : public Counter {
427
    public:
428
        NonZeroCounter(TUnit::type type, int64_t level, const std::string& parent_name,
429
                       int64_t value = 0)
430
2.37M
                : Counter(type, value, level), _parent_name(parent_name) {}
431
432
0
        virtual Counter* clone() const override {
433
0
            return new NonZeroCounter(type(), level(), parent_name(), value());
434
0
        }
435
436
7.69k
        std::string parent_name() const { return _parent_name; }
437
438
    private:
439
        const std::string _parent_name;
440
    };
441
442
    class DescriptionEntry : public Counter {
443
    public:
444
        DescriptionEntry(const std::string& name, const std::string& description)
445
197k
                : Counter(TUnit::NONE, 0, 2), _description(description), _name(name) {}
446
447
0
        virtual Counter* clone() const override {
448
0
            return new DescriptionEntry(_name, _description);
449
0
        }
450
451
0
        void set(int64_t value) override {
452
            // Do nothing
453
0
        }
454
0
        void set(double value) override {
455
            // Do nothing
456
0
        }
457
0
        void update(int64_t delta) override {
458
            // Do nothing
459
0
        }
460
461
129
        TCounter to_thrift(const std::string& name) const override {
462
129
            TCounter counter;
463
129
            counter.name = name;
464
129
            counter.__set_level(2);
465
129
            counter.__set_description(_description);
466
129
            return counter;
467
129
        }
468
469
0
        PProfileCounter to_proto(const std::string& name) const override {
470
0
            PProfileCounter counter;
471
0
            counter.set_name(name);
472
0
            counter.set_level(2);
473
0
            counter.set_description(_description);
474
0
            return counter;
475
0
        }
476
477
    private:
478
        const std::string _description;
479
        const std::string _name;
480
    };
481
482
    // Create a runtime profile object with 'name'.
483
    RuntimeProfile(const std::string& name, bool is_averaged_profile = false);
484
485
    ~RuntimeProfile();
486
487
    // Adds a child profile.  This is thread safe.
488
    // 'indent' indicates whether the child will be printed w/ extra indentation
489
    // relative to the parent.
490
    // If location is non-null, child will be inserted after location.  Location must
491
    // already be added to the profile.
492
    void add_child(RuntimeProfile* child, bool indent, RuntimeProfile* location = nullptr);
493
494
    void add_child_unlock(RuntimeProfile* child, bool indent, RuntimeProfile* loc);
495
496
    /// Creates a new child profile with the given 'name'. A child profile with that name
497
    /// must not already exist. If 'prepend' is true, prepended before other child profiles,
498
    /// otherwise appended after other child profiles.
499
    RuntimeProfile* create_child(const std::string& name, bool indent = true, bool prepend = false);
500
501
    // Merges the src profile into this one, combining counters that have an identical
502
    // path. Info strings from profiles are not merged. 'src' would be a const if it
503
    // weren't for locking.
504
    // Calling this concurrently on two RuntimeProfiles in reverse order results in
505
    // undefined behavior.
506
    void merge(const RuntimeProfile* src);
507
508
    // Updates this profile w/ the thrift profile: behaves like Merge(), except
509
    // that existing counters are updated rather than added up.
510
    // Info strings matched up by key and are updated or added, depending on whether
511
    // the key has already been registered.
512
    void update(const TRuntimeProfileTree& thrift_profile);
513
514
    //Similar to `void update(const TRuntimeProfileTree& thrift_profile)`
515
    void update(const PRuntimeProfileTree& proto_profile);
516
517
    // Add a counter with 'name'/'type'.  Returns a counter object that the caller can
518
    // update.  The counter is owned by the RuntimeProfile object.
519
    // If parent_counter_name is a non-empty string, the counter is added as a child of
520
    // parent_counter_name.
521
    // If the counter already exists, the existing counter object is returned.
522
    Counter* add_counter(const std::string& name, TUnit::type type,
523
                         const std::string& parent_counter_name, int64_t level = 2);
524
525
110M
    Counter* add_counter(const std::string& name, TUnit::type type) {
526
110M
        return add_counter(name, type, RuntimeProfile::ROOT_COUNTER);
527
110M
    }
528
529
46.7M
    Counter* add_counter_with_level(const std::string& name, TUnit::type type, int64_t level) {
530
46.7M
        return add_counter(name, type, RuntimeProfile::ROOT_COUNTER, level);
531
46.7M
    }
532
533
    NonZeroCounter* add_nonzero_counter(
534
            const std::string& name, TUnit::type type,
535
            const std::string& parent_counter_name = RuntimeProfile::ROOT_COUNTER,
536
            int64_t level = 2);
537
538
    // Add a description entry under target counter.
539
    void add_description(const std::string& name, const std::string& description,
540
                         std::string parent_counter_name);
541
    // Add a derived counter with 'name'/'type'. The counter is owned by the
542
    // RuntimeProfile object.
543
    // If parent_counter_name is a non-empty string, the counter is added as a child of
544
    // parent_counter_name.
545
    // Returns nullptr if the counter already exists.
546
    DerivedCounter* add_derived_counter(const std::string& name, TUnit::type type,
547
                                        const DerivedCounterFunction& counter_fn,
548
                                        const std::string& parent_counter_name);
549
550
    ConditionCounter* add_conditition_counter(const std::string& name, TUnit::type type,
551
                                              const ConditionCounterFunction& counter_fn,
552
                                              const std::string& parent_counter_name,
553
                                              int64_t level = 2);
554
555
    // Gets the counter object with 'name'.  Returns nullptr if there is no counter with
556
    // that name.
557
    Counter* get_counter(const std::string& name);
558
559
    // Adds all counters with 'name' that are registered either in this or
560
    // in any of the child profiles to 'counters'.
561
    void get_counters(const std::string& name, std::vector<Counter*>* counters);
562
563
    // Helper to append to the "ExecOption" info string.
564
0
    void append_exec_option(const std::string& option) { add_info_string("ExecOption", option); }
565
566
    // Adds a string to the runtime profile.  If a value already exists for 'key',
567
    // the value will be updated.
568
    void add_info_string(const std::string& key, const std::string& value);
569
570
    // Returns a pointer to the info string value for 'key'.  Returns nullptr if
571
    // the key does not exist.
572
    const std::string* get_info_string(const std::string& key);
573
574
    // Returns the counter for the total elapsed time.
575
28.0M
    Counter* total_time_counter() { return &_counter_total_time; }
576
577
    // Prints the counters in a name: value format.
578
    // Does not hold locks when it makes any function calls.
579
    void pretty_print(std::ostream* s, const std::string& prefix = "",
580
                      int64_t profile_level = 2) const;
581
46
    std::string pretty_print() const {
582
46
        std::stringstream ss;
583
46
        pretty_print(&ss);
584
46
        return ss.str();
585
46
    };
586
587
    // Serializes profile to thrift.
588
    // Does not hold locks when it makes any function calls.
589
    void to_thrift(TRuntimeProfileTree* tree, int64_t profile_level = 2);
590
    void to_thrift(std::vector<TRuntimeProfileNode>* nodes, int64_t profile_level = 2);
591
592
    // Similar to `to_thrift`.
593
    void to_proto(PRuntimeProfileTree* tree, int64_t profile_level = 2);
594
    void to_proto(google::protobuf::RepeatedPtrField<PRuntimeProfileNode>* nodes,
595
                  int64_t profile_level = 2);
596
597
    // Divides all counters by n
598
    void divide(int n);
599
600
    RuntimeProfile* get_child(std::string name);
601
602
    void get_children(std::vector<RuntimeProfile*>* children) const;
603
604
    // Gets all profiles in tree, including this one.
605
    void get_all_children(std::vector<RuntimeProfile*>* children);
606
607
    // Returns the number of counters in this profile
608
    int num_counters() const { return cast_set<int>(_counter_map.size()); }
609
610
    // Returns name of this profile
611
19.4k
    const std::string& name() const { return _name; }
612
613
    // *only call this on top-level profiles*
614
    // (because it doesn't re-file child profiles)
615
570
    void set_name(const std::string& name) { _name = name; }
616
617
10.4k
    int64_t metadata() const { return _metadata; }
618
4.67M
    void set_metadata(int64_t md) {
619
4.67M
        _is_set_metadata = true;
620
4.67M
        _metadata = md;
621
4.67M
    }
622
623
10.2M
    bool is_set_metadata() const { return _is_set_metadata; }
624
625
0
    time_t timestamp() const { return _timestamp; }
626
10
    void set_timestamp(time_t ss) { _timestamp = ss; }
627
628
    // Derived counter function: return measured throughput as input_value/second.
629
    static int64_t units_per_second(const Counter* total_counter, const Counter* timer);
630
631
    // Derived counter function: return aggregated value
632
    static int64_t counter_sum(const std::vector<Counter*>* counters);
633
634
    /// Adds a high water mark counter to the runtime profile. Otherwise, same behavior
635
    /// as AddCounter().
636
    HighWaterMarkCounter* AddHighWaterMarkCounter(
637
            const std::string& name, TUnit::type unit,
638
            const std::string& parent_counter_name = RuntimeProfile::ROOT_COUNTER,
639
            int64_t profile_level = 2);
640
641
    // Recursively compute the fraction of the 'total_time' spent in this profile and
642
    // its children.
643
    // This function updates _local_time_percent for each profile.
644
    void compute_time_in_profile();
645
646
    void clear_children();
647
648
private:
649
    // RuntimeProfileCounterTreeNode needs to access the counter map and child counter map
650
    friend class RuntimeProfileCounterTreeNode;
651
    // Pool for allocated counters. Usually owned by the creator of this
652
    // object, but occasionally allocated in the constructor.
653
    std::unique_ptr<ObjectPool> _pool;
654
655
    // Pool for allocated counters. These counters are shared with some other objects.
656
    std::map<std::string, std::shared_ptr<HighWaterMarkCounter>> _shared_counter_pool;
657
658
    // Name for this runtime profile.
659
    std::string _name;
660
661
    // user-supplied, uninterpreted metadata.
662
    int64_t _metadata;
663
    bool _is_set_metadata = false;
664
665
    bool _is_sink = false;
666
    bool _is_set_sink = false;
667
668
    // The timestamp when the profile was modified, make sure the update is up to date.
669
    time_t _timestamp;
670
671
    /// True if this profile is an average derived from other profiles.
672
    /// All counters in this profile must be of unit AveragedCounter.
673
    bool _is_averaged_profile;
674
675
    // Map from counter names to counters.  The profile owns the memory for the
676
    // counters.
677
    using CounterMap = std::map<std::string, Counter*>;
678
    CounterMap _counter_map;
679
680
    // Map from parent counter name to a set of child counter name.
681
    // All top level counters are the child of RuntimeProfile::ROOT_COUNTER (root).
682
    using ChildCounterMap = std::map<std::string, std::set<std::string>>;
683
    ChildCounterMap _child_counter_map;
684
685
    // protects _counter_map, _counter_child_map and _bucketing_counters
686
    mutable std::mutex _counter_map_lock;
687
688
    // Child profiles.  Does not own memory.
689
    // We record children in both a map (to facilitate updates) and a vector
690
    // (to print things in the order they were registered)
691
    using ChildMap = std::map<std::string, RuntimeProfile*>;
692
    ChildMap _child_map;
693
    // vector of (profile, indentation flag)
694
    using ChildVector = std::vector<std::pair<RuntimeProfile*, bool>>;
695
    ChildVector _children;
696
    mutable std::mutex _children_lock; // protects _child_map and _children
697
698
    using InfoStrings = std::map<std::string, std::string>;
699
    InfoStrings _info_strings;
700
701
    // Keeps track of the order in which InfoStrings are displayed when printed
702
    using InfoStringsDisplayOrder = std::vector<std::string>;
703
    InfoStringsDisplayOrder _info_strings_display_order;
704
705
    // Protects _info_strings and _info_strings_display_order
706
    mutable std::mutex _info_strings_lock;
707
708
    Counter _counter_total_time;
709
    // Time spent in just in this profile (i.e. not the children) as a fraction
710
    // of the total time in the entire profile tree.
711
    double _local_time_percent;
712
713
    // update a subtree of profiles from nodes, rooted at *idx.
714
    // On return, *idx points to the node immediately following this subtree.
715
    void update(const std::vector<TRuntimeProfileNode>& nodes, int* idx);
716
717
    // Similar to `void update(const std::vector<TRuntimeProfileNode>& nodes, int* idx)`
718
    void update(const google::protobuf::RepeatedPtrField<PRuntimeProfileNode>& nodes, int* idx);
719
720
    // Helper function to compute compute the fraction of the total time spent in
721
    // this profile and its children.
722
    // Called recursively.
723
    void compute_time_in_profile(int64_t total_time);
724
725
    // Print the child counters of the given counter name
726
    static void print_child_counters(const std::string& prefix, const std::string& counter_name,
727
                                     const CounterMap& counter_map,
728
                                     const ChildCounterMap& child_counter_map, std::ostream* s);
729
};
730
731
// Utility class to update the counter at object construction and destruction.
732
// When the object is constructed, decrement the counter by val.
733
// When the object goes out of scope, increment the counter by val.
734
class ScopedCounter {
735
public:
736
0
    ScopedCounter(RuntimeProfile::Counter* counter, int64_t val) : _val(val), _counter(counter) {
737
0
        if (counter == nullptr) {
738
0
            return;
739
0
        }
740
0
741
0
        _counter->update(-1L * _val);
742
0
    }
743
744
    // Increment the counter when object is destroyed
745
0
    ~ScopedCounter() {
746
0
        if (_counter != nullptr) {
747
0
            _counter->update(_val);
748
0
        }
749
0
    }
750
751
    // Disable copy constructor and assignment
752
    ScopedCounter(const ScopedCounter& counter) = delete;
753
    ScopedCounter& operator=(const ScopedCounter& counter) = delete;
754
755
private:
756
    int64_t _val;
757
    RuntimeProfile::Counter* _counter = nullptr;
758
};
759
760
// Utility class to update time elapsed when the object goes out of scope.
761
// 'T' must implement the stopWatch "interface" (start,stop,elapsed_time) but
762
// we use templates not to pay for virtual function overhead.
763
template <class T, typename Bool = bool>
764
class ScopedTimer {
765
public:
766
    ScopedTimer(RuntimeProfile::Counter* counter, const Bool* is_cancelled = nullptr)
767
119M
            : _counter(counter), _is_cancelled(is_cancelled) {
768
119M
        if (counter == nullptr) {
769
96.2k
            return;
770
96.2k
        }
771
119M
        DCHECK_EQ(counter->type(), TUnit::TIME_NS);
772
119M
        _sw.start();
773
119M
    }
_ZN5doris11ScopedTimerINS_15CustomStopWatchILi1EEEbEC2EPNS_14RuntimeProfile7CounterEPKb
Line
Count
Source
767
103M
            : _counter(counter), _is_cancelled(is_cancelled) {
768
103M
        if (counter == nullptr) {
769
96.2k
            return;
770
96.2k
        }
771
103M
        DCHECK_EQ(counter->type(), TUnit::TIME_NS);
772
103M
        _sw.start();
773
103M
    }
_ZN5doris11ScopedTimerINS_15CustomStopWatchILi3EEEbEC2EPNS_14RuntimeProfile7CounterEPKb
Line
Count
Source
767
16.2M
            : _counter(counter), _is_cancelled(is_cancelled) {
768
16.2M
        if (counter == nullptr) {
769
0
            return;
770
0
        }
771
16.2M
        DCHECK_EQ(counter->type(), TUnit::TIME_NS);
772
16.2M
        _sw.start();
773
16.2M
    }
774
775
    void stop() { _sw.stop(); }
776
777
    void start() { _sw.start(); }
778
779
121M
    bool is_cancelled() { return _is_cancelled != nullptr && *_is_cancelled; }
_ZN5doris11ScopedTimerINS_15CustomStopWatchILi1EEEbE12is_cancelledEv
Line
Count
Source
779
104M
    bool is_cancelled() { return _is_cancelled != nullptr && *_is_cancelled; }
_ZN5doris11ScopedTimerINS_15CustomStopWatchILi3EEEbE12is_cancelledEv
Line
Count
Source
779
16.3M
    bool is_cancelled() { return _is_cancelled != nullptr && *_is_cancelled; }
780
781
121M
    void UpdateCounter() {
782
121M
        if (_counter != nullptr && !is_cancelled()) {
783
121M
            _counter->update(_sw.elapsed_time());
784
121M
        }
785
121M
    }
_ZN5doris11ScopedTimerINS_15CustomStopWatchILi1EEEbE13UpdateCounterEv
Line
Count
Source
781
104M
    void UpdateCounter() {
782
104M
        if (_counter != nullptr && !is_cancelled()) {
783
104M
            _counter->update(_sw.elapsed_time());
784
104M
        }
785
104M
    }
_ZN5doris11ScopedTimerINS_15CustomStopWatchILi3EEEbE13UpdateCounterEv
Line
Count
Source
781
16.3M
    void UpdateCounter() {
782
16.3M
        if (_counter != nullptr && !is_cancelled()) {
783
16.3M
            _counter->update(_sw.elapsed_time());
784
16.3M
        }
785
16.3M
    }
786
787
    // Update counter when object is destroyed
788
120M
    ~ScopedTimer() {
789
120M
        if (_counter == nullptr) {
790
96.3k
            return;
791
96.3k
        }
792
120M
        _sw.stop();
793
120M
        UpdateCounter();
794
120M
    }
_ZN5doris11ScopedTimerINS_15CustomStopWatchILi1EEEbED2Ev
Line
Count
Source
788
104M
    ~ScopedTimer() {
789
104M
        if (_counter == nullptr) {
790
96.3k
            return;
791
96.3k
        }
792
104M
        _sw.stop();
793
104M
        UpdateCounter();
794
104M
    }
_ZN5doris11ScopedTimerINS_15CustomStopWatchILi3EEEbED2Ev
Line
Count
Source
788
16.2M
    ~ScopedTimer() {
789
16.2M
        if (_counter == nullptr) {
790
0
            return;
791
0
        }
792
16.2M
        _sw.stop();
793
16.2M
        UpdateCounter();
794
16.2M
    }
795
796
    // Disable copy constructor and assignment
797
    ScopedTimer(const ScopedTimer& timer) = delete;
798
    ScopedTimer& operator=(const ScopedTimer& timer) = delete;
799
800
private:
801
    T _sw;
802
    RuntimeProfile::Counter* _counter = nullptr;
803
    const Bool* _is_cancelled = nullptr;
804
};
805
806
// Utility class to update time elapsed when the object goes out of scope.
807
// 'T' must implement the stopWatch "interface" (start,stop,elapsed_time) but
808
// we use templates not to pay for virtual function overhead.
809
template <class T, class C>
810
class ScopedRawTimer {
811
public:
812
187M
    ScopedRawTimer(C* counter) : _counter(counter) { _sw.start(); }
_ZN5doris14ScopedRawTimerINS_15CustomStopWatchILi1EEElEC2EPl
Line
Count
Source
812
187M
    ScopedRawTimer(C* counter) : _counter(counter) { _sw.start(); }
_ZN5doris14ScopedRawTimerINS_15CustomStopWatchILi1EEESt6atomicIlEEC2EPS4_
Line
Count
Source
812
90.5k
    ScopedRawTimer(C* counter) : _counter(counter) { _sw.start(); }
813
    // Update counter when object is destroyed
814
187M
    ~ScopedRawTimer() { *_counter += _sw.elapsed_time(); }
_ZN5doris14ScopedRawTimerINS_15CustomStopWatchILi1EEElED2Ev
Line
Count
Source
814
187M
    ~ScopedRawTimer() { *_counter += _sw.elapsed_time(); }
_ZN5doris14ScopedRawTimerINS_15CustomStopWatchILi1EEESt6atomicIlEED2Ev
Line
Count
Source
814
90.5k
    ~ScopedRawTimer() { *_counter += _sw.elapsed_time(); }
815
816
    // Disable copy constructor and assignment
817
    ScopedRawTimer(const ScopedRawTimer& timer) = delete;
818
    ScopedRawTimer& operator=(const ScopedRawTimer& timer) = delete;
819
820
private:
821
    T _sw;
822
    C* _counter = nullptr;
823
};
824
} // namespace doris