• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tudasc / TypeART / 25177145272

30 Apr 2026 04:30PM UTC coverage: 84.647% (-5.6%) from 90.246%
25177145272

Pull #188

github

web-flow
Merge 88918912c into 278119205
Pull Request #188: GPU memory allocation support

127 of 259 new or added lines in 19 files covered. (49.03%)

200 existing lines in 18 files now uncovered.

4510 of 5328 relevant lines covered (84.65%)

27776.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.93
/lib/runtime/AccessCounter.h
1
// TypeART library
2
//
3
// Copyright (c) 2017-2026 TypeART Authors
4
// Distributed under the BSD 3-Clause license.
5
// (See accompanying file LICENSE.txt or copy at
6
// https://opensource.org/licenses/BSD-3-Clause)
7
//
8
// Project home: https://github.com/tudasc/TypeART
9
//
10
// SPDX-License-Identifier: BSD-3-Clause
11
//
12

13
#ifndef TYPEART_ACCESSCOUNTER_H
14
#define TYPEART_ACCESSCOUNTER_H
15

16
#include "RuntimeData.h"
17

18
#include <algorithm>
19
#include <atomic>
20
#include <cmath>
21
#include <mutex>
22
#include <numeric>
23
#include <shared_mutex>
24
#include <string>
25
#include <thread>
26
#include <unordered_map>
27
#include <unordered_set>
28

29
namespace typeart {
30

31
namespace softcounter {
32

33
using Counter       = long long int;
34
using AtomicCounter = std::atomic<Counter>;
35

36
namespace detail {
37
/**
38
 * Updates an atomic maximum value.
39
 * Based on https://stackoverflow.com/questions/16190078/how-to-atomically-update-a-maximum-value.
40
 * @param maxVal The maximum value.
41
 * @param newVal The new value.
42
 */
43
template <typename T>
44
inline void updateMax(std::atomic<T>& maxVal, T newVal) noexcept {
217,646✔
45
  T prevMax = maxVal;
217,646✔
46
  while (prevMax < newVal && !maxVal.compare_exchange_weak(prevMax, newVal)) {
217,653✔
47
  };
48
}
217,646✔
49

50
struct CounterStats {
51
 private:
52
  CounterStats(double sum, double min, double max, double mean, double std)
5,050✔
53
      : sum_value(sum), min_value(min), max_value(max), mean_value(mean), std_value(std) {
5,050✔
54
  }
5,050✔
55

56
  CounterStats() = default;
75✔
57

58
 public:
59
  static CounterStats create(const std::vector<Counter>& vals) {
5,125✔
60
    if (vals.empty()) {
5,125✔
61
      return CounterStats{};
75✔
62
    }
63
    unsigned n   = vals.size();
5,050✔
64
    double sum   = std::accumulate(vals.begin(), vals.end(), 0.0);
5,050✔
65
    double mean  = sum / n;
5,050✔
66
    double sqSum = std::inner_product(vals.begin(), vals.end(), vals.begin(), 0.0);
5,050✔
67
    double std   = std::sqrt(sqSum / n - mean * mean);
5,050✔
68
    Counter min  = *std::min_element(vals.begin(), vals.end());
5,050✔
69
    Counter max  = *std::max_element(vals.begin(), vals.end());
5,050✔
70
    return CounterStats(sum, min, max, mean, std);
5,050✔
71
  }
5,125✔
72

73
  const double sum_value{};
75✔
74
  const double min_value{};
75✔
75
  const double max_value{};
75✔
76
  const double mean_value{};
75✔
77
  const double std_value{};
75✔
78
};
79
}  // namespace detail
80

81
namespace thread {
82
class ThreadRecorder {
1,370✔
83
  friend class AccessRecorder;
84

85
 public:
86
  inline void incHeapAlloc(size_t count) {
195,645✔
87
    ++heapAllocs;
195,645✔
88
    if (count > 1) {
195,645✔
89
      heapArray++;
192,865✔
90
    }
192,865✔
91
  }
195,645✔
92

93
  inline void incHeapFree(size_t count) {
188,375✔
94
    ++heapAllocsFree;
188,375✔
95
    if (count > 1) {
188,375✔
96
      ++heapArrayFree;
186,850✔
97
    }
186,850✔
98
  }
188,375✔
99

100
  inline void incStackAlloc(size_t count) {
79,499✔
101
    ++curStackAllocs;
79,499✔
102
    ++stackAllocs;
79,499✔
103
    if (count > 1) {
79,499✔
104
      ++stackArray;
8,840✔
105
    }
8,840✔
106
  }
79,499✔
107

108
  inline void incStackFree(size_t count) {
73,394✔
109
    ++stackAllocsFree;
73,394✔
110
    if (count > 1) {
73,394✔
111
      ++stackArrayFree;
8,840✔
112
    }
8,840✔
113
  }
73,394✔
114

115
  inline void decStackAlloc(size_t amount) {
22,002✔
116
    detail::updateMax(maxStackAllocs, curStackAllocs.load());
22,002✔
117
    curStackAllocs -= amount;
22,002✔
118
  }
22,002✔
119

120
  Counter getHeapAllocs() const {
530✔
121
    return heapAllocs;
530✔
122
  }
123
  Counter getHeapArray() const {
530✔
124
    return heapArray;
530✔
125
  }
126
  Counter getHeapAllocsFree() const {
530✔
127
    return heapAllocsFree;
530✔
128
  }
129
  Counter getHeapArrayFree() const {
530✔
130
    return heapArrayFree;
530✔
131
  }
132
  Counter getStackAllocs() const {
1,900✔
133
    return stackAllocs;
1,900✔
134
  }
135
  Counter getMaxStackAllocs() const {
1,900✔
136
    return maxStackAllocs;
1,900✔
137
  }
138
  Counter getCurStackAllocs() const {
139
    return curStackAllocs;
140
  }
141
  Counter getStackArray() const {
1,900✔
142
    return stackArray;
1,900✔
143
  }
144
  Counter getStackAllocsFree() const {
1,900✔
145
    return stackAllocsFree;
1,900✔
146
  }
147
  Counter getStackArrayFree() const {
1,900✔
148
    return stackArrayFree;
1,900✔
149
  }
150

151
  std::unordered_map<std::string, Counter> getValuesAsMap() const {
152
    std::unordered_map<std::string, Counter> vals;
153
    vals["heapAllocs"]      = heapAllocs;
154
    vals["heapArray"]       = heapArray;
155
    vals["heapAllocsFree"]  = heapAllocsFree;
156
    vals["heapArrayFree"]   = heapArrayFree;
157
    vals["stackAllocs"]     = stackAllocs;
158
    vals["curStackAllocs"]  = curStackAllocs;
159
    vals["maxStackAllocs"]  = maxStackAllocs;
160
    vals["stackArray"]      = stackArray;
161
    vals["stackAllocsFree"] = stackAllocsFree;
162
    vals["stackArrayFree"]  = stackArrayFree;
163
    return vals;
164
  }
165

166
 private:
167
  AtomicCounter heapAllocs      = 0;
1,370✔
168
  AtomicCounter heapArray       = 0;
1,370✔
169
  AtomicCounter heapAllocsFree  = 0;
1,370✔
170
  AtomicCounter heapArrayFree   = 0;
1,370✔
171
  AtomicCounter stackAllocs     = 0;
1,370✔
172
  AtomicCounter curStackAllocs  = 0;
1,370✔
173
  AtomicCounter maxStackAllocs  = 0;
1,370✔
174
  AtomicCounter stackArray      = 0;
1,370✔
175
  AtomicCounter stackAllocsFree = 0;
1,370✔
176
  AtomicCounter stackArrayFree  = 0;
1,370✔
177
};
178

179
}  // namespace thread
180

181
class AccessRecorder {
1,025✔
182
 public:
183
  using TypeCountMap      = std::unordered_map<int, Counter>;
184
  using AddressSet        = std::unordered_set<MemAddr>;
185
  using MutexT            = std::shared_mutex;
186
  using ThreadRecorderMap = std::unordered_map<std::thread::id, thread::ThreadRecorder>;
187

188
  ~AccessRecorder() = default;
1,025✔
189

190
  inline void incTypeQuery(int type_id) {
10,060✔
191
    std::lock_guard lock(typeQueryMutex);
10,060✔
192
    ++typeQuery[type_id];
10,060✔
193
  }
10,060✔
194

195
  inline void incHeapAlloc(int typeId, size_t count) {
195,643✔
196
    ++curHeapAllocs;
195,643✔
197

198
    // Always check here for max
199
    // A program without free would otherwise never update maxHeap (see test 20_softcounter_max)
200
    detail::updateMax(maxHeapAllocs, curHeapAllocs.load());
195,643✔
201

202
    ++heapAllocs;
195,643✔
203
    if (count > 1) {
195,643✔
204
      ++heapArray;
192,865✔
205
    }
192,865✔
206

207
    {
208
      std::lock_guard threadRecorderGuard(threadRecorderMutex);
195,643✔
209
      getCurrentThreadRecorder().incHeapAlloc(count);
195,643✔
210
    }
195,647✔
211

212
    std::lock_guard lock(heapAllocMutex);
195,643✔
213
    ++heapAlloc[typeId];
195,643✔
214
  }
195,647✔
215

216
  inline void incStackAlloc(int typeId, size_t count) {
79,499✔
217
    {
218
      std::lock_guard threadRecorderGuard(threadRecorderMutex);
79,499✔
219
      getCurrentThreadRecorder().incStackAlloc(count);
79,499✔
220
    }
79,499✔
221

222
    std::lock_guard lock(stackAllocMutex);
79,499✔
223
    ++stackAlloc[typeId];
79,499✔
224
  }
79,499✔
225

226
  inline void incGlobalAlloc(int typeId, size_t count) {
2,905✔
227
    ++globalAllocs;
2,905✔
228
    if (count > 1) {
2,905✔
229
      ++globalArray;
2,795✔
230
    }
2,795✔
231

232
    std::lock_guard lock(globalAllocMutex);
2,905✔
233
    ++globalAlloc[typeId];
2,905✔
234
  }
2,905✔
235

236
  inline void incStackFree(int typeId, size_t count) {
73,394✔
237
    {
238
      std::lock_guard threadRecorderGuard(threadRecorderMutex);
73,394✔
239
      getCurrentThreadRecorder().incStackFree(count);
73,394✔
240
    }
73,394✔
241

242
    std::lock_guard lock(stackFreeMutex);
73,394✔
243
    ++stackFree[typeId];
73,394✔
244
  }
73,394✔
245

246
  inline void incHeapFree(int typeId, size_t count) {
188,365✔
247
    ++heapAllocsFree;
188,365✔
248
    if (count > 1) {
188,365✔
249
      ++heapArrayFree;
186,844✔
250
    }
186,844✔
251

252
    {
253
      std::lock_guard threadRecorderGuard(threadRecorderMutex);
188,365✔
254
      getCurrentThreadRecorder().incHeapFree(count);
188,365✔
255
    }
188,385✔
256

257
    std::lock_guard lock(heapFreeMutex);
188,365✔
258
    ++heapFree[typeId];
188,365✔
259
  }
188,385✔
260

261
  inline void decHeapAlloc() {
188,375✔
262
    // Removed, since we already increment maxHeapAllocs just in time:
263
    //    if (curHeapAllocs > maxHeapAllocs) {
264
    //      maxHeapAllocs = curHeapAllocs;
265
    //    }
266
    --curHeapAllocs;
188,375✔
267
  }
188,375✔
268

269
  inline void decStackAlloc(size_t amount) {
22,002✔
270
    {
271
      std::lock_guard threadRecorderGuard(threadRecorderMutex);
22,002✔
272
      getCurrentThreadRecorder().decStackAlloc(amount);
22,002✔
273
    }
22,002✔
274
  }
22,002✔
275

276
  inline void incUsedInRequest(MemAddr addr) {
10,203✔
277
    ++addrChecked;
10,203✔
278

279
    std::lock_guard lock(seenMutex);
10,203✔
280
    seen.insert(addr);
10,203✔
281
  }
10,203✔
282

283
  inline void incAddrReuse() {
10,105✔
284
    ++addrReuses;
10,105✔
285
  }
10,105✔
286

287
  inline void incAddrMissing(MemAddr addr) {
783✔
288
    ++addrMissing;
783✔
289

290
    std::lock_guard lock(missingMutex);
783✔
291
    missing.insert(addr);
783✔
292
  }
783✔
293

294
  inline void incNullAddr() {
15✔
295
    ++nullAlloc;
15✔
296
  }
15✔
297

298
  inline void incZeroLengthAddr() {
45✔
299
    ++zeroAlloc;
45✔
300
  }
45✔
301

302
  inline void incZeroLengthAndNullAddr() {
15✔
303
    ++nullAndZeroAlloc;
15✔
304
  }
15✔
305

306
  inline void incUDefTypes(size_t count) {
1,025✔
307
    numUDefTypes += count;
1,025✔
308
  }
1,025✔
309

UNCOV
310
  inline void incOmpContextStack() {
×
UNCOV
311
    ++omp_stack;
×
UNCOV
312
  }
×
313

UNCOV
314
  inline void incOmpContextHeap() {
×
UNCOV
315
    ++omp_heap;
×
UNCOV
316
  }
×
317

UNCOV
318
  inline void incOmpContextFree() {
×
UNCOV
319
    ++omp_heap_free;
×
UNCOV
320
  }
×
321

322
  Counter getHeapAllocs() const {
1,025✔
323
    return heapAllocs;
1,025✔
324
  }
325
  Counter getStackAllocs() const {
1,025✔
326
    return getStackAllocsThreadStats().sum_value;
1,025✔
327
  }
328
  Counter getGlobalAllocs() const {
1,025✔
329
    return globalAllocs;
1,025✔
330
  }
331
  Counter getMaxHeapAllocs() const {
1,025✔
332
    return maxHeapAllocs;
1,025✔
333
  }
334
  Counter getMaxStackAllocs() const {
1,025✔
335
    return getMaxStackAllocsThreadStats().max_value;
1,025✔
336
  }
337
  Counter getCurHeapAllocs() const {
338
    return curHeapAllocs;
339
  }
340
  Counter getAddrReuses() const {
1,025✔
341
    return addrReuses;
1,025✔
342
  }
343
  Counter getAddrMissing() const {
1,025✔
344
    return addrMissing;
1,025✔
345
  }
346
  Counter getAddrChecked() const {
1,025✔
347
    return addrChecked;
1,025✔
348
  }
349
  Counter getStackArray() const {
1,025✔
350
    return getStackArrayThreadStats().sum_value;
1,025✔
351
  }
352
  Counter getHeapArray() const {
1,025✔
353
    return heapArray;
1,025✔
354
  }
355
  Counter getGlobalArray() const {
1,025✔
356
    return globalArray;
1,025✔
357
  }
358
  Counter getStackAllocsFree() const {
1,025✔
359
    return getStackAllocsFreeThreadStats().sum_value;
1,025✔
360
  }
361
  Counter getStackArrayFree() const {
1,025✔
362
    return getStackArrayFreeThreadStats().sum_value;
1,025✔
363
  }
364
  Counter getHeapAllocsFree() const {
1,025✔
365
    return heapAllocsFree;
1,025✔
366
  }
367
  Counter getHeapArrayFree() const {
1,025✔
368
    return heapArrayFree;
1,025✔
369
  }
370
  Counter getNullAlloc() const {
1,025✔
371
    return nullAlloc;
1,025✔
372
  }
373
  Counter getZeroAlloc() const {
1,025✔
374
    return zeroAlloc;
1,025✔
375
  }
376
  Counter getNullAndZeroAlloc() const {
1,025✔
377
    return nullAndZeroAlloc;
1,025✔
378
  }
379
  Counter getNumUDefTypes() const {
1,025✔
380
    return numUDefTypes;
1,025✔
381
  }
382
  Counter getOmpHeapCalls() const {
1,025✔
383
    return omp_heap;
1,025✔
384
  }
385
  Counter getOmpFreeCalls() const {
1,025✔
386
    return omp_heap_free;
1,025✔
387
  }
388
  Counter getOmpStackCalls() const {
1,025✔
389
    return omp_stack;
1,025✔
390
  }
391
  /**
392
   * Must be locked by the caller.
393
   * @return
394
   */
395
  inline thread::ThreadRecorder& getCurrentThreadRecorder() {
558,915✔
396
    const auto tid = std::this_thread::get_id();
558,915✔
397
    return threadRecorders[tid];
558,915✔
398
  }
558,915✔
399

400
#define THREAD_VALS_GETTER_FN(COUNTER_NAME)                    \
401
  std::vector<Counter> get##COUNTER_NAME##ThreadData() const { \
402
    std::shared_lock guard(threadRecorderMutex);               \
403
    std::vector<Counter> vals;                                 \
404
    vals.reserve(threadRecorders.size());                      \
405
    for (const auto& [id, r] : threadRecorders) {              \
406
      vals.push_back(r.get##COUNTER_NAME());                   \
407
    }                                                          \
408
    return vals;                                               \
409
  }
410

411
  THREAD_VALS_GETTER_FN(HeapAllocs)
700✔
412
  THREAD_VALS_GETTER_FN(HeapArray)
700✔
413
  THREAD_VALS_GETTER_FN(HeapAllocsFree)
700✔
414
  THREAD_VALS_GETTER_FN(HeapArrayFree)
700✔
415
  THREAD_VALS_GETTER_FN(StackAllocs)
3,095✔
416
  THREAD_VALS_GETTER_FN(MaxStackAllocs)
3,095✔
417
  THREAD_VALS_GETTER_FN(StackArray)
3,095✔
418
  THREAD_VALS_GETTER_FN(StackAllocsFree)
3,095✔
419
  THREAD_VALS_GETTER_FN(StackArrayFree)
3,095✔
420

421
#undef THREAD_STATS_GETTER_FN
422

423
#define THREAD_STATS_GETTER_FN(COUNTER_NAME)                              \
424
  detail::CounterStats get##COUNTER_NAME##ThreadStats() const {           \
425
    return detail::CounterStats::create(get##COUNTER_NAME##ThreadData()); \
426
  }
427

428
  THREAD_STATS_GETTER_FN(HeapAllocs)
429
  THREAD_STATS_GETTER_FN(HeapArray)
430
  THREAD_STATS_GETTER_FN(HeapAllocsFree)
431
  THREAD_STATS_GETTER_FN(HeapArrayFree)
432
  THREAD_STATS_GETTER_FN(StackAllocs)
1,025✔
433
  THREAD_STATS_GETTER_FN(MaxStackAllocs)
1,025✔
434
  THREAD_STATS_GETTER_FN(StackArray)
1,025✔
435
  THREAD_STATS_GETTER_FN(StackAllocsFree)
1,025✔
436
  THREAD_STATS_GETTER_FN(StackArrayFree)
1,025✔
437

438
#undef THREADS_STATS_GETTER_FN
439

440
  AddressSet getMissing() const {
1,025✔
441
    std::shared_lock slock(missingMutex);
1,025✔
442
    return missing;
1,025✔
443
  }
1,025✔
444
  AddressSet getSeen() const {
1,025✔
445
    std::shared_lock slock(seenMutex);
1,025✔
446
    return seen;
1,025✔
447
  }
1,025✔
448
  TypeCountMap getTypeQuery() const {
2,050✔
449
    std::shared_lock slock(typeQueryMutex);
2,050✔
450
    return typeQuery;
2,050✔
451
  }
2,050✔
452
  TypeCountMap getStackAlloc() const {
4,547✔
453
    std::shared_lock slock(stackAllocMutex);
4,547✔
454
    return stackAlloc;
4,547✔
455
  }
4,547✔
456
  TypeCountMap getHeapAlloc() const {
4,547✔
457
    std::shared_lock slock(heapAllocMutex);
4,547✔
458
    return heapAlloc;
4,547✔
459
  }
4,547✔
460
  TypeCountMap getGlobalAlloc() const {
4,547✔
461
    std::shared_lock slock(globalAllocMutex);
4,547✔
462
    return globalAlloc;
4,547✔
463
  }
4,547✔
464
  TypeCountMap getStackFree() const {
4,547✔
465
    std::shared_lock slock(stackFreeMutex);
4,547✔
466
    return stackFree;
4,547✔
467
  }
4,547✔
468
  TypeCountMap getHeapFree() const {
4,547✔
469
    std::shared_lock slock(heapFreeMutex);
4,547✔
470
    return heapFree;
4,547✔
471
  }
4,547✔
472

473
  std::vector<std::thread::id> getThreadIds() const {
474
    std::vector<std::thread::id> ids;
475
    std::shared_lock slock(threadRecorderMutex);
476
    std::transform(threadRecorders.begin(), threadRecorders.end(), std::back_inserter(ids),
477
                   [](const auto& pair) { return pair.first; });
478
    return ids;
479
  }
480

481
  size_t getNumThreads() const {
1,025✔
482
    std::shared_lock guard(threadRecorderMutex);
1,025✔
483
    return threadRecorders.size();
1,025✔
484
  }
1,025✔
485

486
 private:
487
  AtomicCounter heapAllocs       = 0;
1,025✔
488
  AtomicCounter globalAllocs     = 0;
1,025✔
489
  AtomicCounter maxHeapAllocs    = 0;
1,025✔
490
  AtomicCounter curHeapAllocs    = 0;
1,025✔
491
  AtomicCounter addrReuses       = 0;
1,025✔
492
  AtomicCounter addrMissing      = 0;
1,025✔
493
  AtomicCounter addrChecked      = 0;
1,025✔
494
  AtomicCounter heapArray        = 0;
1,025✔
495
  AtomicCounter globalArray      = 0;
1,025✔
496
  AtomicCounter heapAllocsFree   = 0;
1,025✔
497
  AtomicCounter heapArrayFree    = 0;
1,025✔
498
  AtomicCounter nullAlloc        = 0;
1,025✔
499
  AtomicCounter zeroAlloc        = 0;
1,025✔
500
  AtomicCounter nullAndZeroAlloc = 0;
1,025✔
501
  AtomicCounter numUDefTypes     = 0;
1,025✔
502
  AtomicCounter omp_stack        = 0;
1,025✔
503
  AtomicCounter omp_heap         = 0;
1,025✔
504
  AtomicCounter omp_heap_free    = 0;
1,025✔
505

506
  //  ThreadRecorderMapSafe threadRecorders;
507
  mutable MutexT threadRecorderMutex;
508
  ThreadRecorderMap threadRecorders;
509

510
  AddressSet missing;
511
  mutable MutexT missingMutex;
512

513
  AddressSet seen;
514
  mutable MutexT seenMutex;
515

516
  TypeCountMap stackAlloc;
517
  mutable MutexT stackAllocMutex;
518

519
  TypeCountMap heapAlloc;
520
  mutable MutexT heapAllocMutex;
521

522
  TypeCountMap globalAlloc;
523
  mutable MutexT globalAllocMutex;
524

525
  TypeCountMap stackFree;
526
  mutable MutexT stackFreeMutex;
527

528
  TypeCountMap heapFree;
529
  mutable MutexT heapFreeMutex;
530

531
  TypeCountMap typeQuery;
532
  mutable MutexT typeQueryMutex;
533
};
534

535
/**
536
 * Used for no-operations in counter methods when not using softcounters.
537
 */
538
class NoneRecorder {
539
 public:
540
  [[maybe_unused]] inline void incTypeQuery(int) {
541
  }
542
  [[maybe_unused]] inline void incHeapAlloc(int, size_t) {
543
  }
544
  [[maybe_unused]] inline void incStackAlloc(int, size_t) {
545
  }
546
  [[maybe_unused]] inline void incGlobalAlloc(int, size_t) {
547
  }
548
  [[maybe_unused]] inline void incUsedInRequest(MemAddr) {
549
  }
550
  [[maybe_unused]] inline void decHeapAlloc() {
551
  }
552
  [[maybe_unused]] inline void decStackAlloc(size_t) {
553
  }
554
  [[maybe_unused]] inline void incAddrReuse() {
555
  }
556
  [[maybe_unused]] inline void incAddrMissing(MemAddr) {
557
  }
558
  [[maybe_unused]] inline void incStackFree(int, size_t) {
559
  }
560
  [[maybe_unused]] inline void incHeapFree(int, size_t) {
561
  }
562
  [[maybe_unused]] inline void incNullAddr() {
563
  }
564
  [[maybe_unused]] inline void incZeroLengthAddr() {
565
  }
566
  [[maybe_unused]] inline void incZeroLengthAndNullAddr() {
567
  }
568
  [[maybe_unused]] inline void incUDefTypes(size_t count) {
569
  }
570
  [[maybe_unused]] inline void incOmpContextStack() {
571
  }
572
  [[maybe_unused]] inline void incOmpContextHeap() {
573
  }
574
  [[maybe_unused]] inline void incOmpContextFree() {
575
  }
576
};
577

578
}  // namespace softcounter
579

580
#if defined(ENABLE_SOFTCOUNTER) && ENABLE_SOFTCOUNTER == 1
581
using Recorder = softcounter::AccessRecorder;
582
#else
583
using Recorder = softcounter::NoneRecorder;
584
#endif
585

586
}  // namespace typeart
587

588
#endif  // TYPEART_ACCESSCOUNTER_H
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc