be/src/runtime/thread_context.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 | | |
18 | | #pragma once |
19 | | |
20 | | #include <bthread/bthread.h> |
21 | | #include <bthread/types.h> |
22 | | |
23 | | #include <memory> |
24 | | #include <string> |
25 | | #include <thread> |
26 | | |
27 | | #include "common/exception.h" |
28 | | #include "common/logging.h" |
29 | | #include "common/macros.h" |
30 | | #include "runtime/memory/mem_tracker_limiter.h" |
31 | | #include "runtime/memory/thread_mem_tracker_mgr.h" |
32 | | #include "util/defer_op.h" // IWYU pragma: keep |
33 | | |
34 | | // Used to tracking query/load/compaction/e.g. execution thread memory usage. |
35 | | // This series of methods saves some information to the thread local context of the current worker thread, |
36 | | // including MemTracker, QueryID, etc. Use CONSUME_THREAD_MEM_TRACKER/RELEASE_THREAD_MEM_TRACKER in the code segment where |
37 | | // the macro is located to record the memory into MemTracker. |
38 | | // Not use it in rpc done.run(), because bthread_setspecific may have errors when UBSAN compiles. |
39 | | |
40 | | // Attach to query/load/compaction/e.g. when thread starts. |
41 | | // This will save some info about a working thread in the thread context. |
42 | | // Looking forward to tracking memory during thread execution into MemTrackerLimiter. |
43 | 11.0M | #define SCOPED_ATTACH_TASK(arg1) auto VARNAME_LINENUM(attach_task) = AttachTask(arg1) |
44 | | |
45 | | // If the current thread is not executing a Task, such as a StorageEngine thread, |
46 | | // use SCOPED_INIT_THREAD_CONTEXT to initialize ThreadContext. |
47 | | #define SCOPED_INIT_THREAD_CONTEXT() \ |
48 | 466 | auto VARNAME_LINENUM(scoped_tls_itc) = doris::ScopedInitThreadContext() |
49 | | |
50 | | // Switch resource context in thread context, used after SCOPED_ATTACH_TASK. |
51 | | // If just want to switch mem tracker, use SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER first. |
52 | | #define SCOPED_SWITCH_RESOURCE_CONTEXT(arg1) \ |
53 | | auto VARNAME_LINENUM(switch_resource_context) = doris::SwitchResourceContext(arg1) |
54 | | |
55 | | // Switch MemTrackerLimiter for count memory during thread execution. |
56 | | // Used after SCOPED_ATTACH_TASK, in order to count the memory into another |
57 | | // MemTrackerLimiter instead of the MemTrackerLimiter added by the attach task. |
58 | | #define SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(arg1) \ |
59 | 18.7M | auto VARNAME_LINENUM(switch_mem_tracker) = doris::SwitchThreadMemTrackerLimiter(arg1) |
60 | | |
61 | | // Looking forward to tracking memory during thread execution into MemTracker. |
62 | | // Usually used to record query more detailed memory, including ExecNode operators. |
63 | | #define SCOPED_CONSUME_MEM_TRACKER(mem_tracker) \ |
64 | 1.43M | auto VARNAME_LINENUM(add_mem_consumer) = doris::AddThreadMemTrackerConsumer(mem_tracker) |
65 | | |
66 | | #define DEFER_RELEASE_RESERVED() \ |
67 | 8.77M | Defer VARNAME_LINENUM(defer) { \ |
68 | 8.77M | [&]() { doris::thread_context()->thread_mem_tracker_mgr->shrink_reserved(); }};unity_7_cxx.cxx:_ZZN5doris12PipelineTask7executeEPbENK3$_2clEv Line | Count | Source | 68 | 6.59M | [&]() { doris::thread_context()->thread_mem_tracker_mgr->shrink_reserved(); }}; |
unity_7_cxx.cxx:_ZZN5doris12PipelineTask7executeEPbENK3$_3clEv Line | Count | Source | 68 | 2.16M | [&]() { doris::thread_context()->thread_mem_tracker_mgr->shrink_reserved(); }}; |
|
69 | | |
70 | | // Count a code segment memory |
71 | | // Usage example: |
72 | | // int64_t peak_mem = 0; |
73 | | // { |
74 | | // SCOPED_PEAK_MEM(&peak_mem); |
75 | | // xxxx |
76 | | // } |
77 | | // LOG(INFO) << *peak_mem; |
78 | | #define SCOPED_PEAK_MEM(peak_mem) \ |
79 | 793k | auto VARNAME_LINENUM(scope_peak_mem) = doris::ScopedPeakMem(peak_mem) |
80 | | |
81 | | #define SCOPED_SKIP_MEMORY_CHECK() \ |
82 | 23.0M | auto VARNAME_LINENUM(scope_skip_memory_check) = doris::ScopeSkipMemoryCheck() |
83 | | |
84 | | #define SKIP_LARGE_MEMORY_CHECK(...) \ |
85 | | do { \ |
86 | | doris::ThreadLocalHandle::create_thread_local_if_not_exits(); \ |
87 | | doris::thread_context()->thread_mem_tracker_mgr->skip_large_memory_check++; \ |
88 | | DEFER({ \ |
89 | | doris::thread_context()->thread_mem_tracker_mgr->skip_large_memory_check--; \ |
90 | | doris::ThreadLocalHandle::del_thread_local_if_count_is_zero(); \ |
91 | | }); \ |
92 | | __VA_ARGS__; \ |
93 | | } while (0) |
94 | | |
95 | | #define LIMIT_LOCAL_SCAN_IO(data_dir, bytes_read) \ |
96 | 3.02M | std::shared_ptr<IOThrottle> iot = nullptr; \ |
97 | 3.02M | auto* t_ctx = doris::thread_context(); \ |
98 | 3.02M | if (t_ctx->is_attach_task() && t_ctx->resource_ctx()->workload_group() != nullptr) { \ |
99 | 2.18M | iot = t_ctx->resource_ctx()->workload_group()->get_local_scan_io_throttle(data_dir); \ |
100 | 2.18M | } \ |
101 | 3.02M | if (iot) { \ |
102 | 2.18M | iot->acquire(-1); \ |
103 | 2.18M | } \ |
104 | 3.02M | Defer defer { \ |
105 | 3.37M | [&]() { \ |
106 | 3.37M | if (iot) { \ |
107 | 2.17M | iot->update_next_io_time(*bytes_read); \ |
108 | 2.17M | t_ctx->resource_ctx()->workload_group()->update_local_scan_io(data_dir, \ |
109 | 2.17M | *bytes_read); \ |
110 | 2.17M | } \ |
111 | 3.37M | } \ unity_2_cxx.cxx:_ZZN5doris2io15LocalFileReader12read_at_implEmNS_5SliceEPmPKNS0_9IOContextEENK3$_0clEv Line | Count | Source | 105 | 3.37M | [&]() { \ | 106 | 3.37M | if (iot) { \ | 107 | 2.17M | iot->update_next_io_time(*bytes_read); \ | 108 | 2.17M | t_ctx->resource_ctx()->workload_group()->update_local_scan_io(data_dir, \ | 109 | 2.17M | *bytes_read); \ | 110 | 2.17M | } \ | 111 | 3.37M | } \ |
unity_2_cxx.cxx:_ZZN5doris2io15LocalFileReader18read_at_iobuf_implEmmPN5butil5IOBufEPmPKNS0_9IOContextEENK3$_0clEv Line | Count | Source | 105 | 7 | [&]() { \ | 106 | 7 | if (iot) { \ | 107 | 0 | iot->update_next_io_time(*bytes_read); \ | 108 | 0 | t_ctx->resource_ctx()->workload_group()->update_local_scan_io(data_dir, \ | 109 | 0 | *bytes_read); \ | 110 | 0 | } \ | 111 | 7 | } \ |
|
112 | 3.02M | } |
113 | | |
114 | | #define LIMIT_REMOTE_SCAN_IO(bytes_read) \ |
115 | 344k | std::shared_ptr<IOThrottle> iot = nullptr; \ |
116 | 344k | auto* t_ctx = doris::thread_context(); \ |
117 | 344k | if (t_ctx->is_attach_task() && t_ctx->resource_ctx()->workload_group() != nullptr) { \ |
118 | 269k | iot = t_ctx->resource_ctx()->workload_group()->get_remote_scan_io_throttle(); \ |
119 | 269k | } \ |
120 | 344k | if (iot) { \ |
121 | 269k | iot->acquire(-1); \ |
122 | 269k | } \ |
123 | 344k | Defer defer { \ |
124 | 344k | [&]() { \ |
125 | 343k | if (iot) { \ |
126 | 268k | iot->update_next_io_time(*bytes_read); \ |
127 | 268k | t_ctx->resource_ctx()->workload_group()->update_remote_scan_io(*bytes_read); \ |
128 | 268k | } \ |
129 | 343k | } \ Unexecuted instantiation: unity_2_cxx.cxx:_ZZN5doris2io14HdfsFileReader15do_read_at_implEmNS_5SliceEPmPKNS0_9IOContextEENK3$_0clEv unity_2_cxx.cxx:_ZZN5doris2io12S3FileReader12read_at_implEmNS_5SliceEPmPKNS0_9IOContextEENK3$_0clEv Line | Count | Source | 124 | 343k | [&]() { \ | 125 | 343k | if (iot) { \ | 126 | 268k | iot->update_next_io_time(*bytes_read); \ | 127 | 268k | t_ctx->resource_ctx()->workload_group()->update_remote_scan_io(*bytes_read); \ | 128 | 268k | } \ | 129 | 343k | } \ |
unity_1_cxx.cxx:_ZZN5doris2io19PeerFileCacheReader12fetch_blocksERKSt6vectorISt10shared_ptrINS0_9FileBlockEESaIS5_EEPNS0_15PeerFetchResultEmPKNS0_9IOContextEblNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENK3$_1clEv Line | Count | Source | 124 | 42 | [&]() { \ | 125 | 42 | if (iot) { \ | 126 | 3 | iot->update_next_io_time(*bytes_read); \ | 127 | 3 | t_ctx->resource_ctx()->workload_group()->update_remote_scan_io(*bytes_read); \ | 128 | 3 | } \ | 129 | 42 | } \ |
unity_1_cxx.cxx:_ZZN5doris2io14PrefetchBuffer11read_bufferEmPKcmPmENK3$_1clEv Line | Count | Source | 124 | 115 | [&]() { \ | 125 | 115 | if (iot) { \ | 126 | 84 | iot->update_next_io_time(*bytes_read); \ | 127 | 84 | t_ctx->resource_ctx()->workload_group()->update_remote_scan_io(*bytes_read); \ | 128 | 84 | } \ | 129 | 115 | } \ |
|
130 | 344k | } |
131 | | |
132 | | namespace doris { |
133 | | |
134 | | class ThreadContext; |
135 | | class MemTracker; |
136 | | class QueryContext; |
137 | | class ResourceContext; |
138 | | class RuntimeState; |
139 | | class SwitchResourceContext; |
140 | | |
141 | | extern bthread_key_t btls_key; |
142 | | |
143 | | // Initialize btls_key exactly once before it is used by any thread context. The key has |
144 | | // process lifetime so an existing bthread context never becomes invalid while the BE is running. |
145 | | void init_thread_context_btls_key(); |
146 | | |
147 | | static std::string NO_THREAD_CONTEXT_MSG = |
148 | | "Current thread not exist ThreadContext, usually after the thread is started, using " |
149 | | "SCOPED_ATTACH_TASK macro to create a ThreadContext and bind a Task."; |
150 | | |
151 | | // Is true after ThreadContext construction. |
152 | | inline thread_local bool pthread_context_ptr_init = false; |
153 | | inline thread_local constinit ThreadContext* thread_context_ptr = nullptr; |
154 | | |
155 | | // The thread context saves some info about a working thread. |
156 | | // 2 required info: |
157 | | // 1. thread_id: Current thread id, Auto generated. |
158 | | // 2. type(abolished): The type is a enum value indicating which type of task current thread is running. |
159 | | // For example: QUERY, LOAD, COMPACTION, ... |
160 | | // 3. task id: A unique id to identify this task. maybe query id, load job id, etc. |
161 | | // 4. ThreadMemTrackerMgr |
162 | | // |
163 | | // There may be other optional info to be added later. |
164 | | // |
165 | | // Note: Keep the class simple and only add properties. |
166 | | class ThreadContext { |
167 | | public: |
168 | 2.67M | ThreadContext() { thread_mem_tracker_mgr = std::make_unique<ThreadMemTrackerMgr>(); } |
169 | | |
170 | 2.66M | ~ThreadContext() = default; |
171 | | |
172 | | void attach_task(const std::shared_ptr<ResourceContext>& rc); |
173 | | |
174 | 11.0M | void detach_task() { |
175 | 11.0M | resource_ctx_.reset(); |
176 | 11.0M | thread_mem_tracker_mgr->detach_limiter_tracker(); |
177 | 11.0M | thread_mem_tracker_mgr->disable_wait_gc(); |
178 | 11.0M | } |
179 | | |
180 | 22.8M | bool is_attach_task() { return resource_ctx_ != nullptr; } |
181 | | |
182 | 9.55M | std::shared_ptr<ResourceContext> resource_ctx() { |
183 | 9.55M | #ifndef BE_TEST |
184 | 9.55M | DCHECK(is_attach_task()); |
185 | 9.55M | #endif |
186 | 9.55M | if (is_attach_task()) { |
187 | 9.55M | return resource_ctx_; |
188 | 9.55M | } |
189 | 90 | return _make_orphan_resource_ctx(); |
190 | 9.55M | } |
191 | | |
192 | 46.5k | static std::string get_thread_id() { |
193 | 46.5k | std::stringstream ss; |
194 | 46.5k | ss << std::this_thread::get_id(); |
195 | 46.5k | return ss.str(); |
196 | 46.5k | } |
197 | | // Note that if set global Memory Hook, After thread_mem_tracker_mgr is initialized, |
198 | | // the current thread Hook starts to consume/release mem_tracker. |
199 | | // the use of shared_ptr will cause a crash. The guess is that there is an |
200 | | // intermediate state during the copy construction of shared_ptr. Shared_ptr is not equal |
201 | | // to nullptr, but the object it points to is not initialized. At this time, when the memory |
202 | | // is released somewhere, the hook is triggered to cause the crash. |
203 | | std::unique_ptr<ThreadMemTrackerMgr> thread_mem_tracker_mgr; |
204 | | |
205 | | int thread_local_handle_count = 0; |
206 | | |
207 | | private: |
208 | | friend class SwitchResourceContext; |
209 | | |
210 | | // Cold fallback for threads without an attached task; defined in the .cpp |
211 | | // so this header does not need the full ResourceContext / ExecEnv types. |
212 | | static std::shared_ptr<ResourceContext> _make_orphan_resource_ctx(); |
213 | | |
214 | | std::shared_ptr<ResourceContext> resource_ctx_; |
215 | | }; |
216 | | |
217 | | class ThreadLocalHandle { |
218 | | public: |
219 | 55.0M | static void create_thread_local_if_not_exits() { |
220 | 55.0M | init_thread_context_btls_key(); |
221 | 55.0M | if (bthread_self() == 0) { |
222 | 53.4M | if (!pthread_context_ptr_init) { |
223 | 1.46M | thread_context_ptr = new ThreadContext(); |
224 | 1.46M | pthread_context_ptr_init = true; |
225 | 1.46M | } |
226 | 53.4M | DCHECK(thread_context_ptr != nullptr); |
227 | 53.4M | thread_context_ptr->thread_local_handle_count++; |
228 | 53.4M | } else { |
229 | | // Avoid calling bthread_getspecific frequently to get bthread local. |
230 | | // Very frequent bthread_getspecific will slow, but create_thread_local_if_not_exits is not expected to be much. |
231 | | // Cache the pointer of bthread local in pthead local. |
232 | 1.62M | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); |
233 | 1.62M | if (bthread_context == nullptr) { |
234 | | // If bthread_context == nullptr: |
235 | | // 1. First call to bthread_getspecific (and before any bthread_setspecific) returns NULL |
236 | | // 2. There are not enough reusable btls in btls pool. |
237 | | // else if bthread_context != nullptr: |
238 | | // 1. A new bthread starts, but get a reuses btls. |
239 | 1.21M | bthread_context = new ThreadContext; |
240 | | // The brpc server should respond as quickly as possible. |
241 | 1.21M | bthread_context->thread_mem_tracker_mgr->disable_wait_gc(); |
242 | | // set the data so that next time bthread_getspecific in the thread returns the data. |
243 | 1.21M | CHECK(0 == bthread_setspecific(btls_key, bthread_context) || doris::k_doris_exit); |
244 | 1.21M | } |
245 | 1.62M | DCHECK(bthread_context != nullptr); |
246 | 1.62M | bthread_context->thread_local_handle_count++; |
247 | 1.62M | } |
248 | 55.0M | } |
249 | | |
250 | | // `create_thread_local_if_not_exits` and `del_thread_local_if_count_is_zero` should be used in pairs, |
251 | | // `del_thread_local_if_count_is_zero` should only be called if `create_thread_local_if_not_exits` returns true |
252 | 55.0M | static void del_thread_local_if_count_is_zero() { |
253 | 55.0M | if (pthread_context_ptr_init) { |
254 | | // in pthread |
255 | 53.3M | thread_context_ptr->thread_local_handle_count--; |
256 | 53.3M | if (thread_context_ptr->thread_local_handle_count == 0) { |
257 | 1.45M | pthread_context_ptr_init = false; |
258 | 1.45M | delete doris::thread_context_ptr; |
259 | 1.45M | thread_context_ptr = nullptr; |
260 | 1.45M | } |
261 | 53.3M | } else if (bthread_self() != 0) { |
262 | | // in bthread |
263 | 1.77M | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); |
264 | 1.77M | DCHECK(bthread_context != nullptr); |
265 | 1.77M | bthread_context->thread_local_handle_count--; |
266 | 18.4E | } else { |
267 | 18.4E | throw Exception(Status::FatalError("__builtin_unreachable")); |
268 | 18.4E | } |
269 | 55.0M | } |
270 | | }; |
271 | | |
272 | | // must call create_thread_local_if_not_exits() before use thread_context(). |
273 | 541M | static ThreadContext* thread_context() { |
274 | 541M | if (pthread_context_ptr_init) { |
275 | | // in pthread |
276 | 537M | DCHECK(bthread_self() == 0); |
277 | 537M | DCHECK(thread_context_ptr != nullptr); |
278 | 537M | return thread_context_ptr; |
279 | 537M | } |
280 | 3.77M | if (bthread_self() != 0) { |
281 | | // in bthread |
282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. |
283 | 3.77M | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); |
284 | 3.77M | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); |
285 | 3.77M | return bthread_context; |
286 | 3.77M | } |
287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. |
288 | 18.4E | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); |
289 | 3.76M | } Unexecuted instantiation: doris_main.cpp:_ZN5dorisL14thread_contextEv unity_0_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 404M | static ThreadContext* thread_context() { | 274 | 404M | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 404M | DCHECK(bthread_self() == 0); | 277 | 404M | DCHECK(thread_context_ptr != nullptr); | 278 | 404M | return thread_context_ptr; | 279 | 404M | } | 280 | 152k | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 113k | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 113k | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 113k | return bthread_context; | 286 | 113k | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 39.2k | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 152k | } |
Unexecuted instantiation: config.cpp:_ZN5dorisL14thread_contextEv unity_2_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 3.71M | static ThreadContext* thread_context() { | 274 | 3.71M | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 3.71M | DCHECK(bthread_self() == 0); | 277 | 3.71M | DCHECK(thread_context_ptr != nullptr); | 278 | 3.71M | return thread_context_ptr; | 279 | 3.71M | } | 280 | 18.4E | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 0 | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 0 | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 0 | return bthread_context; | 286 | 0 | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 18.4E | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 18.4E | } |
unity_3_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 52.2M | static ThreadContext* thread_context() { | 274 | 52.2M | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 48.6M | DCHECK(bthread_self() == 0); | 277 | 48.6M | DCHECK(thread_context_ptr != nullptr); | 278 | 48.6M | return thread_context_ptr; | 279 | 48.6M | } | 280 | 3.60M | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 3.60M | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 3.60M | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 3.60M | return bthread_context; | 286 | 3.60M | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 18.4E | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 3.56M | } |
Unexecuted instantiation: unity_5_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_4_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_13_cxx.cxx:_ZN5dorisL14thread_contextEv unity_1_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 64.3M | static ThreadContext* thread_context() { | 274 | 64.3M | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 64.3M | DCHECK(bthread_self() == 0); | 277 | 64.3M | DCHECK(thread_context_ptr != nullptr); | 278 | 64.3M | return thread_context_ptr; | 279 | 64.3M | } | 280 | 56.5k | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 56.5k | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 56.5k | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 56.5k | return bthread_context; | 286 | 56.5k | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 18.4E | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 49.3k | } |
unity_7_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 14.5M | static ThreadContext* thread_context() { | 274 | 14.5M | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 14.5M | DCHECK(bthread_self() == 0); | 277 | 14.5M | DCHECK(thread_context_ptr != nullptr); | 278 | 14.5M | return thread_context_ptr; | 279 | 14.5M | } | 280 | 18.4E | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 0 | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 0 | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 0 | return bthread_context; | 286 | 0 | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 18.4E | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 18.4E | } |
Unexecuted instantiation: unity_6_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_12_cxx.cxx:_ZN5dorisL14thread_contextEv unity_11_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 185k | static ThreadContext* thread_context() { | 274 | 185k | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 185k | DCHECK(bthread_self() == 0); | 277 | 185k | DCHECK(thread_context_ptr != nullptr); | 278 | 185k | return thread_context_ptr; | 279 | 185k | } | 280 | 18.4E | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 0 | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 0 | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 0 | return bthread_context; | 286 | 0 | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 18.4E | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 18.4E | } |
Unexecuted instantiation: unity_10_cxx.cxx:_ZN5dorisL14thread_contextEv unity_9_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 1.85M | static ThreadContext* thread_context() { | 274 | 1.85M | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 1.85M | DCHECK(bthread_self() == 0); | 277 | 1.85M | DCHECK(thread_context_ptr != nullptr); | 278 | 1.85M | return thread_context_ptr; | 279 | 1.85M | } | 280 | 18.4E | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 0 | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 0 | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 0 | return bthread_context; | 286 | 0 | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 18.4E | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 18.4E | } |
Unexecuted instantiation: unity_8_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: hashjoin_build_sink.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: join_build_sink_operator.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: operator.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: partitioned_aggregation_sink_operator.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: scan_operator.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vfile_result_writer.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_31_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_30_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_29_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_28_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_27_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_26_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_25_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_24_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_22_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_21_cxx.cxx:_ZN5dorisL14thread_contextEv unity_20_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 22.3k | static ThreadContext* thread_context() { | 274 | 22.3k | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 22.3k | DCHECK(bthread_self() == 0); | 277 | 22.3k | DCHECK(thread_context_ptr != nullptr); | 278 | 22.3k | return thread_context_ptr; | 279 | 22.3k | } | 280 | 18.4E | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 0 | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 0 | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 0 | return bthread_context; | 286 | 0 | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 18.4E | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 18.4E | } |
Unexecuted instantiation: unity_19_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_18_cxx.cxx:_ZN5dorisL14thread_contextEv unity_17_cxx.cxx:_ZN5dorisL14thread_contextEv Line | Count | Source | 273 | 2 | static ThreadContext* thread_context() { | 274 | 2 | if (pthread_context_ptr_init) { | 275 | | // in pthread | 276 | 2 | DCHECK(bthread_self() == 0); | 277 | 2 | DCHECK(thread_context_ptr != nullptr); | 278 | 2 | return thread_context_ptr; | 279 | 2 | } | 280 | 0 | if (bthread_self() != 0) { | 281 | | // in bthread | 282 | | // bthread switching pthread may be very frequent, remember not to use lock or other time-consuming operations. | 283 | 0 | auto* bthread_context = static_cast<ThreadContext*>(bthread_getspecific(btls_key)); | 284 | 0 | DCHECK(bthread_context != nullptr && bthread_context->thread_local_handle_count > 0); | 285 | 0 | return bthread_context; | 286 | 0 | } | 287 | | // It means that use thread_context() but this thread not attached a query/load using SCOPED_ATTACH_TASK macro. | 288 | 0 | throw Exception(Status::FatalError("{}", doris::NO_THREAD_CONTEXT_MSG)); | 289 | 0 | } |
Unexecuted instantiation: unity_16_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_15_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_14_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: ai_functions.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: function_array_aggregation.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: function_date_or_datetime_computation.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: function_datetime_floor_ceil.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: in.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: uuid.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: arrow_row_batch.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: arrow_stream_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: csv_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: new_plain_binary_line_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: jni_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: new_json_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: native_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vorc_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: column_type_convert.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vparquet_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: schema_desc.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vparquet_group_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vparquet_column_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vparquet_column_chunk_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vparquet_page_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: parquet_column_convert.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vparquet_page_index.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: parquet_block_split_bloom_filter.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: deletion_vector_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: es_http_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: hive_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: hive_orc_nested_column_utils.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: hudi_jni_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: hudi_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: iceberg_delete_file_reader_helper.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: iceberg_position_delete_sys_table_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: iceberg_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: iceberg_orc_nested_column_utils.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: equality_delete.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: iceberg_sys_table_jni_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: jdbc_jni_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: max_compute_jni_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: paimon_jni_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: paimon_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: parquet_metadata_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: parquet_utils.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: remote_doris_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: table_format_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: table_schema_change_helper.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: transactional_hive_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: trino_connector_jni_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: text_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: merge_partitioner.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: iceberg_partition_function.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vcsv_transformer.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vfile_format_transformer_factory.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vjni_format_transformer.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vnative_transformer.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vorc_transformer.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vparquet_transformer.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: adbc_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: hdfs_file_system.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: s3_file_system.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: unity_23_cxx.cxx:_ZN5dorisL14thread_contextEv Unexecuted instantiation: inverted_index_compound_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: inverted_index_fs_directory.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: zone_map_index.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: vcollect_iterator.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: predicate_creator_comparison.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: predicate_creator_in_list_in.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: predicate_creator_in_list_not_in.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: tablet.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: engine_clone_task.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: descriptors.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: backend_service.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: point_query_executor.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: be_server_starter_factory.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: http_service.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: internal_service.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: arrow_flight_batch_reader.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: thrift_util.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: load_stream.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: routine_load_task_executor.cpp:_ZN5dorisL14thread_contextEv Unexecuted instantiation: cloud_compaction_action.cpp:_ZN5dorisL14thread_contextEv |
290 | | |
291 | | class ScopedPeakMem { |
292 | | public: |
293 | | explicit ScopedPeakMem(int64_t* peak_mem) |
294 | 794k | : _peak_mem(peak_mem), |
295 | 794k | _mem_tracker("ScopedPeakMem:" + UniqueId::gen_uid().to_string()) { |
296 | 794k | ThreadLocalHandle::create_thread_local_if_not_exits(); |
297 | 794k | thread_context()->thread_mem_tracker_mgr->push_consumer_tracker(&_mem_tracker); |
298 | 794k | } |
299 | | |
300 | 793k | ~ScopedPeakMem() { |
301 | 793k | thread_context()->thread_mem_tracker_mgr->pop_consumer_tracker(); |
302 | 793k | *_peak_mem += _mem_tracker.peak_consumption(); |
303 | 793k | ThreadLocalHandle::del_thread_local_if_count_is_zero(); |
304 | 793k | } |
305 | | |
306 | | private: |
307 | | int64_t* _peak_mem; |
308 | | MemTracker _mem_tracker; |
309 | | }; |
310 | | |
311 | | // only hold thread context in scope. |
312 | | class ScopedInitThreadContext { |
313 | | public: |
314 | 614 | explicit ScopedInitThreadContext() { ThreadLocalHandle::create_thread_local_if_not_exits(); } |
315 | | |
316 | 604 | ~ScopedInitThreadContext() { ThreadLocalHandle::del_thread_local_if_count_is_zero(); } |
317 | | }; |
318 | | |
319 | | class AttachTask { |
320 | | public: |
321 | | // you must use ResourceCtx or MemTracker initialization. |
322 | | explicit AttachTask() = delete; |
323 | | |
324 | | explicit AttachTask(const std::shared_ptr<ResourceContext>& rc); |
325 | | |
326 | | // Shortcut attach task, initialize an empty resource context, and set the memory tracker. |
327 | | explicit AttachTask(const std::shared_ptr<MemTrackerLimiter>& mem_tracker); |
328 | | |
329 | | // is query or load, initialize with memory tracker, query id and workload group wptr. |
330 | | explicit AttachTask(RuntimeState* runtime_state); |
331 | | |
332 | | explicit AttachTask(QueryContext* query_ctx); |
333 | | |
334 | | void init(const std::shared_ptr<ResourceContext>& rc); |
335 | | |
336 | | ~AttachTask(); |
337 | | }; |
338 | | |
339 | | class SwitchResourceContext { |
340 | | public: |
341 | | explicit SwitchResourceContext(const std::shared_ptr<ResourceContext>& rc); |
342 | | |
343 | | ~SwitchResourceContext(); |
344 | | |
345 | | private: |
346 | | std::shared_ptr<ResourceContext> old_resource_ctx_ {nullptr}; |
347 | | }; |
348 | | |
349 | | class SwitchThreadMemTrackerLimiter { |
350 | | public: |
351 | | explicit SwitchThreadMemTrackerLimiter( |
352 | | const std::shared_ptr<doris::MemTrackerLimiter>& mem_tracker); |
353 | | |
354 | | ~SwitchThreadMemTrackerLimiter(); |
355 | | |
356 | | private: |
357 | | bool is_switched_ {false}; |
358 | | }; |
359 | | |
360 | | class AddThreadMemTrackerConsumer { |
361 | | public: |
362 | | // The owner and user of MemTracker are in the same thread, and the raw pointer is faster. |
363 | | // If mem_tracker is nullptr, do nothing. |
364 | | explicit AddThreadMemTrackerConsumer(MemTracker* mem_tracker); |
365 | | |
366 | | // The owner and user of MemTracker are in different threads. If mem_tracker is nullptr, do nothing. |
367 | | explicit AddThreadMemTrackerConsumer(const std::shared_ptr<MemTracker>& mem_tracker); |
368 | | |
369 | | ~AddThreadMemTrackerConsumer(); |
370 | | |
371 | | private: |
372 | | std::shared_ptr<MemTracker> _mem_tracker; // Avoid mem_tracker being released midway. |
373 | | bool _need_pop = false; |
374 | | }; |
375 | | |
376 | | class ScopeSkipMemoryCheck { |
377 | | public: |
378 | 22.9M | explicit ScopeSkipMemoryCheck() { |
379 | 22.9M | ThreadLocalHandle::create_thread_local_if_not_exits(); |
380 | 22.9M | doris::thread_context()->thread_mem_tracker_mgr->skip_memory_check++; |
381 | 22.9M | } |
382 | | |
383 | 23.0M | ~ScopeSkipMemoryCheck() { |
384 | 23.0M | doris::thread_context()->thread_mem_tracker_mgr->skip_memory_check--; |
385 | 23.0M | ThreadLocalHandle::del_thread_local_if_count_is_zero(); |
386 | 23.0M | } |
387 | | }; |
388 | | |
389 | | // Basic macros for mem tracker, usually do not need to be modified and used. |
390 | | // must call create_thread_local_if_not_exits() before use thread_context(). |
391 | | #define CONSUME_THREAD_MEM_TRACKER(size) \ |
392 | 126M | do { \ |
393 | 126M | if (size == 0) { \ |
394 | 258k | break; \ |
395 | 258k | } \ |
396 | 126M | if (doris::pthread_context_ptr_init) { \ |
397 | 125M | DCHECK(bthread_self() == 0); \ |
398 | 125M | doris::thread_context_ptr->thread_mem_tracker_mgr->consume(size); \ |
399 | 125M | } else if (bthread_self() != 0) { \ |
400 | 334 | auto* bthread_context = \ |
401 | 334 | static_cast<doris::ThreadContext*>(bthread_getspecific(doris::btls_key)); \ |
402 | 334 | DCHECK(bthread_context != nullptr); \ |
403 | 334 | if (bthread_context != nullptr) { \ |
404 | 334 | bthread_context->thread_mem_tracker_mgr->consume(size); \ |
405 | 334 | } else { \ |
406 | 0 | doris::ExecEnv::GetInstance()->orphan_mem_tracker()->consume_no_update_peak(size); \ |
407 | 0 | } \ |
408 | 525k | } else if (doris::ExecEnv::ready()) { \ |
409 | 0 | DCHECK(doris::k_doris_exit || !doris::config::enable_memory_orphan_check) \ |
410 | 0 | << doris::NO_THREAD_CONTEXT_MSG; \ |
411 | 0 | doris::ExecEnv::GetInstance()->orphan_mem_tracker()->consume_no_update_peak(size); \ |
412 | 0 | } \ |
413 | 126M | } while (0) |
414 | 63.1M | #define RELEASE_THREAD_MEM_TRACKER(size) CONSUME_THREAD_MEM_TRACKER(-size) |
415 | | |
416 | | } // namespace doris |