|
28 | 28 | #include <signal.h> |
29 | 29 | #include <stddef.h> // size_t |
30 | 30 | #include <vector> |
| 31 | +#include <set> |
31 | 32 | #include <array> |
32 | 33 | #include <memory> |
33 | 34 | #include "butil/atomicops.h" // butil::atomic |
|
40 | 41 | DECLARE_int32(task_group_ntags); |
41 | 42 | namespace bthread { |
42 | 43 |
|
| 44 | +#ifdef BRPC_BTHREAD_TRACER |
| 45 | +class ShardedBthreadSet { |
| 46 | +public: |
| 47 | + explicit ShardedBthreadSet(size_t shard_count = 16) |
| 48 | + : _shard_count(shard_count), _shards(shard_count) {} |
| 49 | + |
| 50 | + void add(bthread_t id) { |
| 51 | + get_shard(id).add(id); |
| 52 | + } |
| 53 | + |
| 54 | + void remove(bthread_t id) { |
| 55 | + get_shard(id).remove(id); |
| 56 | + } |
| 57 | + |
| 58 | + std::set<bthread_t> get_all() { |
| 59 | + std::set<bthread_t> result; |
| 60 | + for (auto& shard : _shards) { |
| 61 | + shard.copy_to(result); |
| 62 | + } |
| 63 | + return result; |
| 64 | + } |
| 65 | + |
| 66 | +private: |
| 67 | + class Shard { |
| 68 | + public: |
| 69 | + Shard() { |
| 70 | + pthread_spin_init(&_spinlock, PTHREAD_PROCESS_PRIVATE); |
| 71 | + } |
| 72 | + |
| 73 | + ~Shard() { |
| 74 | + pthread_spin_destroy(&_spinlock); |
| 75 | + } |
| 76 | + |
| 77 | + Shard(const Shard&) = delete; |
| 78 | + Shard& operator=(const Shard&) = delete; |
| 79 | + |
| 80 | + void add(bthread_t id) { |
| 81 | + BAIDU_SCOPED_LOCK(_spinlock); |
| 82 | + _bthread_ids.insert(id); |
| 83 | + } |
| 84 | + |
| 85 | + void remove(bthread_t id) { |
| 86 | + BAIDU_SCOPED_LOCK(_spinlock); |
| 87 | + _bthread_ids.erase(id); |
| 88 | + } |
| 89 | + |
| 90 | + void copy_to(std::set<bthread_t>& target) { |
| 91 | + BAIDU_SCOPED_LOCK(_spinlock); |
| 92 | + target.insert(_bthread_ids.begin(), _bthread_ids.end()); |
| 93 | + } |
| 94 | + |
| 95 | + private: |
| 96 | + pthread_spinlock_t _spinlock; |
| 97 | + std::set<bthread_t> _bthread_ids; |
| 98 | + }; |
| 99 | + |
| 100 | + Shard& get_shard(bthread_t id) { |
| 101 | + return _shards[id % _shard_count]; |
| 102 | + } |
| 103 | + |
| 104 | + const size_t _shard_count; |
| 105 | + std::vector<Shard> _shards; |
| 106 | +}; |
| 107 | +#endif // BRPC_BTHREAD_TRACER |
| 108 | + |
43 | 109 | class TaskGroup; |
44 | 110 |
|
45 | 111 | // Control all task groups |
@@ -95,6 +161,9 @@ friend bthread_t init_for_pthread_stack_trace(); |
95 | 161 | // A stacktrace of bthread can be helpful in debugging. |
96 | 162 | void stack_trace(std::ostream& os, bthread_t tid); |
97 | 163 | std::string stack_trace(bthread_t tid); |
| 164 | + std::set<bthread_t> get_living_bthreads() { |
| 165 | + return _living_bthreads.get_all(); |
| 166 | + } |
98 | 167 | #endif // BRPC_BTHREAD_TRACER |
99 | 168 |
|
100 | 169 | void push_priority_queue(bthread_tag_t tag, bthread_t tid) { |
@@ -130,6 +199,16 @@ friend bthread_t init_for_pthread_stack_trace(); |
130 | 199 | bvar::Adder<int64_t>& tag_nworkers(bthread_tag_t tag); |
131 | 200 | bvar::Adder<int64_t>& tag_nbthreads(bthread_tag_t tag); |
132 | 201 |
|
| 202 | +#ifdef BRPC_BTHREAD_TRACER |
| 203 | + void record_bthread_start(bthread_t tid) { |
| 204 | + _living_bthreads.add(tid); |
| 205 | + } |
| 206 | + |
| 207 | + void record_bthread_finish(bthread_t tid) { |
| 208 | + _living_bthreads.remove(tid); |
| 209 | + } |
| 210 | +#endif // BRPC_BTHREAD_TRACER |
| 211 | + |
133 | 212 | std::vector<butil::atomic<size_t>> _tagged_ngroup; |
134 | 213 | std::vector<TaggedGroups> _tagged_groups; |
135 | 214 | butil::Mutex _modify_group_mutex; |
@@ -165,6 +244,7 @@ friend bthread_t init_for_pthread_stack_trace(); |
165 | 244 |
|
166 | 245 | #ifdef BRPC_BTHREAD_TRACER |
167 | 246 | TaskTracer _task_tracer; |
| 247 | + ShardedBthreadSet _living_bthreads; |
168 | 248 | #endif // BRPC_BTHREAD_TRACER |
169 | 249 |
|
170 | 250 | }; |
|
0 commit comments