Coverage Report

Created: 2025-06-24 21:35

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