| 223 | |
| 224 | |
| 225 | std::vector<CovCounter> getCurrentCoveredNameRefs() |
| 226 | { |
| 227 | const LLVMProfileData * begin = __llvm_profile_begin_data(); // NOLINT |
| 228 | const LLVMProfileData * end = __llvm_profile_end_data(); // NOLINT |
| 229 | |
| 230 | const uint64_t * const cnts_begin = __llvm_profile_begin_counters(); // NOLINT |
| 231 | const uint64_t * const cnts_end = __llvm_profile_end_counters(); // NOLINT |
| 232 | |
| 233 | const std::size_t total = static_cast<std::size_t>(end - begin); |
| 234 | |
| 235 | std::vector<CovCounter> result; |
| 236 | /// Reserve assuming ~4 non-zero counters per function on average. |
| 237 | result.reserve(std::min(total * 4, std::size_t{1 << 20})); |
| 238 | |
| 239 | const uint32_t n_profile = static_cast<uint32_t>(end - begin); |
| 240 | |
| 241 | for (uint32_t idx = 0; idx < n_profile; ++idx) |
| 242 | { |
| 243 | const LLVMProfileData * data = begin + idx; |
| 244 | |
| 245 | if (!data->NumCounters) |
| 246 | continue; |
| 247 | |
| 248 | /// CounterPtr is a relative signed offset from the address of the data record. |
| 249 | const uint64_t * const entry_counter = reinterpret_cast<const uint64_t *>( |
| 250 | reinterpret_cast<const char *>(data) + reinterpret_cast<intptr_t>(data->CounterPtr)); |
| 251 | |
| 252 | /// Validate the entire counter array fits within the counters section. |
| 253 | if (entry_counter < cnts_begin || entry_counter + data->NumCounters > cnts_end) |
| 254 | continue; |
| 255 | |
| 256 | /// Skip functions that were never entered — branch counters inside them |
| 257 | /// would be false positives. |
| 258 | if (*entry_counter == 0) |
| 259 | continue; |
| 260 | |
| 261 | /// min_depth: prefer XRay call depth (exact, built via text_addr→profile mapping) |
| 262 | /// over the call-count proxy. XRay depth is populated only when the binary is |
| 263 | /// built with -DCLICKHOUSE_XRAY_INSTRUMENT_COVERAGE=1 and XRay is activated. |
| 264 | uint8_t min_depth; |
| 265 | #ifdef CLICKHOUSE_XRAY_INSTRUMENT_COVERAGE |
| 266 | if (g_xray_min_depth && idx < g_xray_depth_size) |
| 267 | { |
| 268 | const uint32_t xray_d = g_xray_min_depth[idx].load(std::memory_order_relaxed); |
| 269 | min_depth = (xray_d < 255u) ? static_cast<uint8_t>(xray_d) : 255u; |
| 270 | } |
| 271 | else |
| 272 | #endif |
| 273 | { |
| 274 | /// Fallback: raw entry-counter call count (lower = more specific). |
| 275 | min_depth = static_cast<uint8_t>(std::min<uint64_t>(*entry_counter, 254u)); |
| 276 | } |
| 277 | |
| 278 | /// Emit one entry per non-zero counter. Counter 0 is the function entry; |
| 279 | /// counters 1…N are individual basic-block/branch counters that map to |
| 280 | /// specific statement-level regions in the LLVM coverage mapping. |
| 281 | for (uint32_t i = 0; i < data->NumCounters; ++i) |
| 282 | { |
no test coverage detected