Coverage Report

Created: 2026-04-10 18:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/perf_counters.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
// This file is copied from
18
// https://github.com/apache/impala/blob/branch-2.9.0/be/src/util/perf-counters.cpp
19
// and modified by Doris
20
21
#include "util/perf_counters.h"
22
23
#include <linux/perf_event.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <sys/syscall.h>
27
#include <unistd.h>
28
29
#include <boost/algorithm/string/trim.hpp>
30
#include <fstream> // IWYU pragma: keep
31
#include <iomanip>
32
#include <iostream>
33
#include <unordered_map>
34
#include <utility>
35
36
#include "absl/strings/substitute.h"
37
#include "util/pretty_printer.h"
38
#include "util/string_parser.hpp"
39
#include "util/string_util.h"
40
41
namespace doris {
42
0
#define COUNTER_SIZE (sizeof(void*))
43
0
#define PRETTY_PRINT_WIDTH 13
44
45
static std::unordered_map<std::string, std::string> _process_state;
46
47
int64_t PerfCounters::_vm_rss = 0;
48
std::string PerfCounters::_vm_rss_str = "";
49
int64_t PerfCounters::_vm_hwm = 0;
50
int64_t PerfCounters::_vm_size = 0;
51
int64_t PerfCounters::_vm_peak = 0;
52
53
// This is the order of the counters in /proc/self/io
54
enum PERF_IO_IDX {
55
    PROC_IO_READ = 0,
56
    PROC_IO_WRITE,
57
    PROC_IO_SYS_RREAD,
58
    PROC_IO_SYS_WRITE,
59
    PROC_IO_DISK_READ,
60
    PROC_IO_DISK_WRITE,
61
    PROC_IO_CANCELLED_WRITE,
62
    PROC_IO_LAST_COUNTER,
63
};
64
65
// Wrapper around sys call.  This syscall is hard to use and this is how it is recommended
66
// to be used.
67
static inline auto sys_perf_event_open(struct perf_event_attr* attr, pid_t pid, int cpu,
68
0
                                       int64_t group_fd, unsigned long flags) {
69
0
    attr->size = sizeof(*attr);
70
0
    return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
71
0
}
72
73
// Remap PerfCounters::Counter to Linux kernel enums
74
0
static bool init_event_attr(perf_event_attr* attr, PerfCounters::Counter counter) {
75
0
    memset(attr, 0, sizeof(perf_event_attr));
76
77
0
    switch (counter) {
78
0
    case PerfCounters::PERF_COUNTER_SW_CPU_CLOCK:
79
0
        attr->type = PERF_TYPE_SOFTWARE;
80
0
        attr->config = PERF_COUNT_SW_CPU_CLOCK;
81
0
        break;
82
83
0
    case PerfCounters::PERF_COUNTER_SW_PAGE_FAULTS:
84
0
        attr->type = PERF_TYPE_SOFTWARE;
85
0
        attr->config = PERF_COUNT_SW_PAGE_FAULTS;
86
0
        break;
87
88
0
    case PerfCounters::PERF_COUNTER_SW_CONTEXT_SWITCHES:
89
0
        attr->type = PERF_TYPE_SOFTWARE;
90
0
        attr->config = PERF_COUNT_SW_PAGE_FAULTS;
91
0
        break;
92
93
0
    case PerfCounters::PERF_COUNTER_SW_CPU_MIGRATIONS:
94
0
        attr->type = PERF_TYPE_SOFTWARE;
95
0
        attr->config = PERF_COUNT_SW_CPU_MIGRATIONS;
96
0
        break;
97
98
0
    case PerfCounters::PERF_COUNTER_HW_CPU_CYCLES:
99
0
        attr->type = PERF_TYPE_HARDWARE;
100
0
        attr->config = PERF_COUNT_HW_CPU_CYCLES;
101
0
        break;
102
103
0
    case PerfCounters::PERF_COUNTER_HW_INSTRUCTIONS:
104
0
        attr->type = PERF_TYPE_HARDWARE;
105
0
        attr->config = PERF_COUNT_HW_INSTRUCTIONS;
106
0
        break;
107
108
0
    case PerfCounters::PERF_COUNTER_HW_CACHE_HIT:
109
0
        attr->type = PERF_TYPE_HARDWARE;
110
0
        attr->config = PERF_COUNT_HW_CACHE_REFERENCES;
111
0
        break;
112
113
0
    case PerfCounters::PERF_COUNTER_HW_CACHE_MISSES:
114
0
        attr->type = PERF_TYPE_HARDWARE;
115
0
        attr->config = PERF_COUNT_HW_CACHE_MISSES;
116
0
        break;
117
118
0
    case PerfCounters::PERF_COUNTER_HW_BRANCHES:
119
0
        attr->type = PERF_TYPE_HARDWARE;
120
0
        attr->config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
121
0
        break;
122
123
0
    case PerfCounters::PERF_COUNTER_HW_BRANCH_MISSES:
124
0
        attr->type = PERF_TYPE_HARDWARE;
125
0
        attr->config = PERF_COUNT_HW_BRANCH_MISSES;
126
0
        break;
127
128
0
    case PerfCounters::PERF_COUNTER_HW_BUS_CYCLES:
129
0
        attr->type = PERF_TYPE_HARDWARE;
130
0
        attr->config = PERF_COUNT_HW_BUS_CYCLES;
131
0
        break;
132
133
0
    default:
134
0
        return false;
135
0
    }
136
137
0
    return true;
138
0
}
139
140
0
static std::string get_counter_name(PerfCounters::Counter counter) {
141
0
    switch (counter) {
142
0
    case PerfCounters::PERF_COUNTER_SW_CPU_CLOCK:
143
0
        return "CPUTime";
144
145
0
    case PerfCounters::PERF_COUNTER_SW_PAGE_FAULTS:
146
0
        return "PageFaults";
147
148
0
    case PerfCounters::PERF_COUNTER_SW_CONTEXT_SWITCHES:
149
0
        return "ContextSwitches";
150
151
0
    case PerfCounters::PERF_COUNTER_SW_CPU_MIGRATIONS:
152
0
        return "CPUMigrations";
153
154
0
    case PerfCounters::PERF_COUNTER_HW_CPU_CYCLES:
155
0
        return "HWCycles";
156
157
0
    case PerfCounters::PERF_COUNTER_HW_INSTRUCTIONS:
158
0
        return "Instructions";
159
160
0
    case PerfCounters::PERF_COUNTER_HW_CACHE_HIT:
161
0
        return "CacheHit";
162
163
0
    case PerfCounters::PERF_COUNTER_HW_CACHE_MISSES:
164
0
        return "CacheMiss";
165
166
0
    case PerfCounters::PERF_COUNTER_HW_BRANCHES:
167
0
        return "Branches";
168
169
0
    case PerfCounters::PERF_COUNTER_HW_BRANCH_MISSES:
170
0
        return "BranchMiss";
171
172
0
    case PerfCounters::PERF_COUNTER_HW_BUS_CYCLES:
173
0
        return "BusCycles";
174
175
0
    case PerfCounters::PERF_COUNTER_VM_USAGE:
176
0
        return "VmUsage";
177
178
0
    case PerfCounters::PERF_COUNTER_VM_PEAK_USAGE:
179
0
        return "PeakVmUsage";
180
181
0
    case PerfCounters::PERF_COUNTER_RESIDENT_SET_SIZE:
182
0
        return "WorkingSet";
183
184
0
    case PerfCounters::PERF_COUNTER_BYTES_READ:
185
0
        return "BytesRead";
186
187
0
    case PerfCounters::PERF_COUNTER_BYTES_WRITE:
188
0
        return "BytesWritten";
189
190
0
    case PerfCounters::PERF_COUNTER_DISK_READ:
191
0
        return "DiskRead";
192
193
0
    case PerfCounters::PERF_COUNTER_DISK_WRITE:
194
0
        return "DiskWrite";
195
196
0
    default:
197
0
        return "";
198
0
    }
199
0
}
200
201
0
bool PerfCounters::init_sys_counter(Counter counter) {
202
0
    CounterData data;
203
0
    data.counter = counter;
204
0
    data.source = PerfCounters::SYS_PERF_COUNTER;
205
0
    data.fd = -1;
206
0
    perf_event_attr attr;
207
208
0
    if (!init_event_attr(&attr, counter)) {
209
0
        return false;
210
0
    }
211
212
0
    auto fd = sys_perf_event_open(&attr, getpid(), -1, _group_fd, 0);
213
214
0
    if (fd < 0) {
215
0
        return false;
216
0
    }
217
218
0
    if (_group_fd == -1) {
219
0
        _group_fd = fd;
220
0
    }
221
222
0
    data.fd = fd;
223
224
0
    if (counter == PERF_COUNTER_SW_CPU_CLOCK) {
225
0
        data.type = TUnit::TIME_NS;
226
0
    } else {
227
0
        data.type = TUnit::UNIT;
228
0
    }
229
230
0
    _counters.push_back(data);
231
0
    return true;
232
0
}
233
234
0
bool PerfCounters::init_proc_self_io_counter(Counter counter) {
235
0
    CounterData data;
236
0
    data.counter = counter;
237
0
    data.source = PerfCounters::PROC_SELF_IO;
238
0
    data.type = TUnit::BYTES;
239
240
0
    switch (counter) {
241
0
    case PerfCounters::PERF_COUNTER_BYTES_READ:
242
0
        data.proc_io_line_number = PROC_IO_READ;
243
0
        break;
244
245
0
    case PerfCounters::PERF_COUNTER_BYTES_WRITE:
246
0
        data.proc_io_line_number = PROC_IO_WRITE;
247
0
        break;
248
249
0
    case PerfCounters::PERF_COUNTER_DISK_READ:
250
0
        data.proc_io_line_number = PROC_IO_DISK_READ;
251
0
        break;
252
253
0
    case PerfCounters::PERF_COUNTER_DISK_WRITE:
254
0
        data.proc_io_line_number = PROC_IO_DISK_WRITE;
255
0
        break;
256
257
0
    default:
258
0
        return false;
259
0
    }
260
261
0
    _counters.push_back(data);
262
0
    return true;
263
0
}
264
265
0
bool PerfCounters::init_proc_self_status_counter(Counter counter) {
266
0
    CounterData data {};
267
0
    data.counter = counter;
268
0
    data.source = PerfCounters::PROC_SELF_STATUS;
269
0
    data.type = TUnit::BYTES;
270
271
0
    switch (counter) {
272
0
    case PerfCounters::PERF_COUNTER_VM_USAGE:
273
0
        data.proc_status_field = "VmSize";
274
0
        break;
275
276
0
    case PerfCounters::PERF_COUNTER_VM_PEAK_USAGE:
277
0
        data.proc_status_field = "VmPeak";
278
0
        break;
279
280
0
    case PerfCounters::PERF_COUNTER_RESIDENT_SET_SIZE:
281
0
        data.proc_status_field = "VmRS";
282
0
        break;
283
284
0
    default:
285
0
        return false;
286
0
    }
287
288
0
    _counters.push_back(data);
289
0
    return true;
290
0
}
291
292
0
bool PerfCounters::get_sys_counters(std::vector<int64_t>& buffer) {
293
0
    for (int i = 0; i < _counters.size(); i++) {
294
0
        if (_counters[i].source == SYS_PERF_COUNTER) {
295
0
            auto num_bytes = read((int)_counters[i].fd, &buffer[i], COUNTER_SIZE);
296
297
0
            if (num_bytes != COUNTER_SIZE) {
298
0
                return false;
299
0
            }
300
301
0
            if (_counters[i].type == TUnit::TIME_NS) {
302
0
                buffer[i] /= 1000000;
303
0
            }
304
0
        }
305
0
    }
306
307
0
    return true;
308
0
}
309
310
// Parse out IO counters from /proc/self/io.  The file contains a list of
311
// (name,byte) pairs.
312
// For example:
313
//    rchar: 210212
314
//    wchar: 94
315
//    syscr: 118
316
//    syscw: 3
317
//    read_bytes: 0
318
//    write_bytes: 0
319
//    cancelled_write_bytes: 0
320
0
bool PerfCounters::get_proc_self_io_counters(std::vector<int64_t>& buffer) {
321
0
    std::ifstream file("/proc/self/io", std::ios::in);
322
0
    std::string buf;
323
0
    int64_t values[PROC_IO_LAST_COUNTER];
324
0
    int ret = 0;
325
326
0
    for (int i = 0; i < PROC_IO_LAST_COUNTER; ++i) {
327
0
        if (!file) {
328
0
            ret = -1;
329
0
            break;
330
0
        }
331
332
0
        getline(file, buf);
333
0
        size_t colon = buf.find(':');
334
335
0
        if (colon == std::string::npos) {
336
0
            ret = -1;
337
0
            break;
338
0
        }
339
340
0
        buf = buf.substr(colon + 1);
341
0
        std::istringstream stream(buf);
342
0
        stream >> values[i];
343
0
    }
344
345
0
    if (ret == 0) {
346
0
        for (int i = 0; i < _counters.size(); ++i) {
347
0
            if (_counters[i].source == PROC_SELF_IO) {
348
0
                buffer[i] = values[_counters[i].proc_io_line_number];
349
0
            }
350
0
        }
351
0
    }
352
353
0
    if (file.is_open()) {
354
0
        file.close();
355
0
    }
356
357
0
    return true;
358
0
}
359
360
0
bool PerfCounters::get_proc_self_status_counters(std::vector<int64_t>& buffer) {
361
0
    std::ifstream file("/proc/self/status", std::ios::in);
362
0
    std::string buf;
363
364
0
    while (file) {
365
0
        getline(file, buf);
366
367
0
        for (int i = 0; i < _counters.size(); ++i) {
368
0
            if (_counters[i].source == PROC_SELF_STATUS) {
369
0
                size_t field = buf.find(_counters[i].proc_status_field);
370
371
0
                if (field == std::string::npos) {
372
0
                    continue;
373
0
                }
374
375
0
                size_t colon = field + _counters[i].proc_status_field.size() + 1;
376
0
                buf = buf.substr(colon + 1);
377
0
                std::istringstream stream(buf);
378
0
                int64_t value;
379
0
                stream >> value;
380
0
                buffer[i] = value * 1024; // values in file are in kb
381
0
            }
382
0
        }
383
0
    }
384
385
0
    if (file.is_open()) {
386
0
        file.close();
387
0
    }
388
389
0
    return true;
390
0
}
391
392
0
PerfCounters::PerfCounters() : _group_fd(-1) {}
393
394
// Close all fds for the counters
395
0
PerfCounters::~PerfCounters() {
396
0
    for (int i = 0; i < _counters.size(); ++i) {
397
0
        if (_counters[i].source == SYS_PERF_COUNTER) {
398
0
            close((int)_counters[i].fd);
399
0
        }
400
0
    }
401
0
}
402
403
// Add here the default ones that are most useful
404
0
bool PerfCounters::add_default_counters() {
405
0
    bool result = true;
406
0
    result &= add_counter(PERF_COUNTER_SW_CPU_CLOCK);
407
    // These hardware ones don't work on a vm, just ignore if they fail
408
    // TODO: these don't work reliably and aren't that useful.  Turn them off.
409
    //add_counter(PERF_COUNTER_HW_INSTRUCTIONS);
410
    //add_counter(PERF_COUNTER_HW_CPU_CYCLES);
411
    //add_counter(PERF_COUNTER_HW_BRANCHES);
412
    //add_counter(PERF_COUNTER_HW_BRANCH_MISSES);
413
    //add_counter(PERF_COUNTER_HW_CACHE_MISSES);
414
0
    add_counter(PERF_COUNTER_VM_USAGE);
415
0
    add_counter(PERF_COUNTER_VM_PEAK_USAGE);
416
0
    add_counter(PERF_COUNTER_RESIDENT_SET_SIZE);
417
0
    result &= add_counter(PERF_COUNTER_DISK_READ);
418
0
    return result;
419
0
}
420
421
// Add a specific counter
422
0
bool PerfCounters::add_counter(Counter counter) {
423
    // Ignore if it's already added.
424
0
    for (int i = 0; i < _counters.size(); ++i) {
425
0
        if (_counters[i].counter == counter) {
426
0
            return true;
427
0
        }
428
0
    }
429
430
0
    bool result = false;
431
432
0
    switch (counter) {
433
0
    case PerfCounters::PERF_COUNTER_SW_CPU_CLOCK:
434
0
    case PerfCounters::PERF_COUNTER_SW_PAGE_FAULTS:
435
0
    case PerfCounters::PERF_COUNTER_SW_CONTEXT_SWITCHES:
436
0
    case PerfCounters::PERF_COUNTER_SW_CPU_MIGRATIONS:
437
0
    case PerfCounters::PERF_COUNTER_HW_CPU_CYCLES:
438
0
    case PerfCounters::PERF_COUNTER_HW_INSTRUCTIONS:
439
0
    case PerfCounters::PERF_COUNTER_HW_CACHE_HIT:
440
0
    case PerfCounters::PERF_COUNTER_HW_CACHE_MISSES:
441
0
    case PerfCounters::PERF_COUNTER_HW_BRANCHES:
442
0
    case PerfCounters::PERF_COUNTER_HW_BRANCH_MISSES:
443
0
    case PerfCounters::PERF_COUNTER_HW_BUS_CYCLES:
444
0
        result = init_sys_counter(counter);
445
0
        break;
446
447
0
    case PerfCounters::PERF_COUNTER_BYTES_READ:
448
0
    case PerfCounters::PERF_COUNTER_BYTES_WRITE:
449
0
    case PerfCounters::PERF_COUNTER_DISK_READ:
450
0
    case PerfCounters::PERF_COUNTER_DISK_WRITE:
451
0
        result = init_proc_self_io_counter(counter);
452
0
        break;
453
454
0
    case PerfCounters::PERF_COUNTER_VM_USAGE:
455
0
    case PerfCounters::PERF_COUNTER_VM_PEAK_USAGE:
456
0
    case PerfCounters::PERF_COUNTER_RESIDENT_SET_SIZE:
457
0
        result = init_proc_self_status_counter(counter);
458
0
        break;
459
460
0
    default:
461
0
        return false;
462
0
    }
463
464
0
    if (result) {
465
0
        _counter_names.push_back(get_counter_name(counter));
466
0
    }
467
468
0
    return result;
469
0
}
470
471
// Query all the counters right now and store the values in results
472
0
void PerfCounters::snapshot(const std::string& name) {
473
0
    if (_counters.size() == 0) {
474
0
        return;
475
0
    }
476
477
0
    std::string fixed_name = name;
478
479
0
    if (fixed_name.size() == 0) {
480
0
        std::stringstream ss;
481
0
        ss << _snapshots.size() + 1;
482
0
        fixed_name = ss.str();
483
0
    }
484
485
0
    std::vector<int64_t> buffer(_counters.size());
486
487
0
    get_sys_counters(buffer);
488
0
    get_proc_self_io_counters(buffer);
489
0
    get_proc_self_status_counters(buffer);
490
491
0
    _snapshots.push_back(buffer);
492
0
    _snapshot_names.push_back(fixed_name);
493
0
}
494
495
0
const std::vector<int64_t>* PerfCounters::counters(int snapshot) const {
496
0
    if (snapshot < 0 || snapshot >= _snapshots.size()) {
497
0
        return nullptr;
498
0
    }
499
500
0
    return &_snapshots[snapshot];
501
0
}
502
503
0
void PerfCounters::pretty_print(std::ostream* s) const {
504
0
    std::ostream& stream = *s;
505
0
    stream << std::setw(8) << "snapshot";
506
507
0
    for (int i = 0; i < _counter_names.size(); ++i) {
508
0
        stream << std::setw(PRETTY_PRINT_WIDTH) << _counter_names[i];
509
0
    }
510
511
0
    stream << std::endl;
512
513
0
    for (int ss = 0; ss < _snapshots.size(); s++) {
514
0
        stream << std::setw(8) << _snapshot_names[ss];
515
0
        const std::vector<int64_t>& snapshot = _snapshots[ss];
516
517
0
        for (int i = 0; i < snapshot.size(); ++i) {
518
0
            stream << std::setw(PRETTY_PRINT_WIDTH)
519
0
                   << PrettyPrinter::print(snapshot[i], _counters[i].type);
520
0
        }
521
522
0
        stream << std::endl;
523
0
    }
524
525
0
    stream << std::endl;
526
0
}
527
528
// Refactor below
529
530
0
int PerfCounters::parse_int(const std::string& state_key) {
531
0
    auto it = _process_state.find(state_key);
532
0
    if (it != _process_state.end()) return atoi(it->second.c_str());
533
0
    return -1;
534
0
}
535
536
0
int64_t PerfCounters::parse_int64(const std::string& state_key) {
537
0
    auto it = _process_state.find(state_key);
538
0
    if (it != _process_state.end()) {
539
0
        StringParser::ParseResult result;
540
0
        int64_t state_value =
541
0
                StringParser::string_to_int<int64_t>(it->second.data(), it->second.size(), &result);
542
0
        if (result == StringParser::PARSE_SUCCESS) return state_value;
543
0
    }
544
0
    return -1;
545
0
}
546
547
0
std::string PerfCounters::parse_string(const std::string& state_key) {
548
0
    auto it = _process_state.find(state_key);
549
0
    if (it != _process_state.end()) return it->second;
550
0
    return "";
551
0
}
552
553
870k
int64_t PerfCounters::parse_bytes(const std::string& state_key) {
554
870k
    auto it = _process_state.find(state_key);
555
870k
    if (it != _process_state.end()) {
556
870k
        std::vector<std::string> fields = split(it->second, " ");
557
        // We expect state_value such as, e.g., '16129508', '16129508 kB', '16129508 mB'
558
870k
        StringParser::ParseResult result;
559
870k
        int64_t state_value =
560
870k
                StringParser::string_to_int<int64_t>(fields[0].data(), fields[0].size(), &result);
561
870k
        if (result == StringParser::PARSE_SUCCESS) {
562
870k
            if (fields.size() < 2) return state_value;
563
870k
            if (fields[1].compare("kB") == 0) return state_value * 1024L;
564
870k
        }
565
870k
    }
566
0
    return -1;
567
870k
}
568
569
217k
void PerfCounters::refresh_proc_status() {
570
217k
    std::ifstream statusinfo("/proc/self/status", std::ios::in);
571
217k
    std::string line;
572
12.4M
    while (statusinfo.good() && !statusinfo.eof()) {
573
12.1M
        getline(statusinfo, line);
574
12.1M
        std::vector<std::string> fields = split(line, "\t");
575
12.1M
        if (fields.size() < 2) continue;
576
11.9M
        boost::algorithm::trim(fields[1]);
577
11.9M
        std::string key = fields[0].substr(0, fields[0].size() - 1);
578
11.9M
        _process_state[absl::Substitute("status/$0", key)] = fields[1];
579
11.9M
    }
580
581
217k
    if (statusinfo.is_open()) statusinfo.close();
582
583
217k
    _vm_size = parse_bytes("status/VmSize");
584
217k
    _vm_peak = parse_bytes("status/VmPeak");
585
217k
    _vm_rss = parse_bytes("status/VmRSS");
586
217k
#ifdef ADDRESS_SANITIZER
587
217k
    _vm_rss_str = "[ASAN]" + PrettyPrinter::print(_vm_rss, TUnit::BYTES);
588
#else
589
    _vm_rss_str = PrettyPrinter::print(_vm_rss, TUnit::BYTES);
590
#endif
591
217k
    _vm_hwm = parse_bytes("status/VmHWM");
592
217k
}
593
594
0
void PerfCounters::get_proc_status(ProcStatus* out) {
595
0
    out->vm_size = parse_bytes("status/VmSize");
596
0
    out->vm_peak = parse_bytes("status/VmPeak");
597
0
    out->vm_rss = parse_bytes("status/VmRSS");
598
0
    out->vm_hwm = parse_bytes("status/VmHWM");
599
0
}
600
601
} // namespace doris