Skip to content

Commit

Permalink
Opt signal trace
Browse files Browse the repository at this point in the history
  • Loading branch information
chenBright committed Dec 19, 2024
1 parent c44cb27 commit 6b52eba
Show file tree
Hide file tree
Showing 15 changed files with 536 additions and 335 deletions.
1 change: 1 addition & 0 deletions README_cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* [bthread or not](docs/cn/bthread_or_not.md)
* [thread-local](docs/cn/thread_local.md)
* [Execution Queue](docs/cn/execution_queue.md)
* [bthread tracer](docs/cn/bthread_tracer.md)
* Client
* [基础功能](docs/cn/client.md)
* [错误码](docs/cn/error_code.md)
Expand Down
12 changes: 11 additions & 1 deletion docs/cn/bthread_tracer.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,17 @@ jump_stack是bthread挂起或者运行的必经之路,也是STB的拦截点。
3. 访问服务的内置服务:`http://ip:port/bthreads/<bthread_id>?st=1`或者代码里调用`bthread::stack_trace()`函数。
4. 如果希望追踪pthread的调用栈,在对应pthread上调用`bthread::init_for_pthread_stack_trace()`函数获取一个伪bthread_t,然后使用步骤3即可获取pthread调用栈。

下面是追踪bthread调用栈的输出示例:
```shell
#0 0x00007fdbbed500b5 __clock_gettime_2
#1 0x000000000041f2b6 butil::cpuwide_time_ns()
#2 0x000000000041f289 butil::cpuwide_time_us()
#3 0x000000000041f1b9 butil::EveryManyUS::operator bool()
#4 0x0000000000413289 (anonymous namespace)::spin_and_log()
#5 0x00007fdbbfa58dc0 bthread::TaskGroup::task_runner()
```

# 相关flag

- `enable_fast_unwind`:是否启用快速回溯功能,默认为true。大多数情况下,不需要关闭快速回溯功能。除非你关注的调用栈函数名转换失败,显示为`<unknown>`,则可以尝试关闭快速回溯功能,但这会导致性能下降。以包含30帧的调用栈举例,快速回溯只需要400~500us,而关闭快速回溯则需要4ms左右,性能下降了近10倍
- `enable_fast_unwind`:是否启用快速回溯功能,默认为true。大多数情况下,不需要关闭快速回溯功能。除非你关注的调用栈函数名转换失败,显示为`<unknown>`,则可以尝试关闭快速回溯功能,但这会导致性能下降。以包含30帧的调用栈举例,快速回溯基本上在200us以内就可以完成,而关闭快速回溯则需要4ms左右,性能下降了近20倍
- `signal_trace_timeout_ms`:信号追踪模式的超时时间,默认为50ms。虽然libunwind文档显示回溯功能是异步信号安全的,但是[gpertools社区发现libunwind在某些情况下会死锁](https://github.com/gperftools/gperftools/issues/775),所以TaskTracer会设置了超时时间,超时后会放弃回溯,打破死锁。
2 changes: 1 addition & 1 deletion src/brpc/builtin/bthreads_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#include "brpc/builtin/bthreads_service.h"

namespace bthread {
void print_task(std::ostream& os, bthread_t tid);
extern void print_task(std::ostream& os, bthread_t tid);
}


Expand Down
3 changes: 1 addition & 2 deletions src/brpc/input_messenger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,7 @@ int InputMessenger::ProcessNewMessage(
// This unique_ptr prevents msg to be lost before transfering
// ownership to last_msg
DestroyingPtr<InputMessageBase> msg(pr.message());
QueueMessage(last_msg.release(), &num_bthread_created,
m->_keytable_pool);
QueueMessage(last_msg.release(), &num_bthread_created, m->_keytable_pool);
if (_handlers[index].process == NULL) {
LOG(ERROR) << "process of index=" << index << " is NULL";
continue;
Expand Down
26 changes: 5 additions & 21 deletions src/brpc/reloadable_flags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
// specific language governing permissions and limitations
// under the License.


#include <unistd.h> // write, _exit
#include <gflags/gflags.h>
#include "butil/macros.h"
#include "brpc/reloadable_flags.h"

namespace brpc {
Expand Down Expand Up @@ -62,37 +58,25 @@ bool NonNegativeInteger(const char*, int64_t val) {
return val >= 0;
}

template <typename T>
static bool RegisterFlagValidatorOrDieImpl(
const T* flag, bool (*validate_fn)(const char*, T val)) {
if (GFLAGS_NS::RegisterFlagValidator(flag, validate_fn)) {
return true;
}
// Error printed by gflags does not have newline. Add one to it.
char newline = '\n';
butil::ignore_result(write(2, &newline, 1));
_exit(1);
}

bool RegisterFlagValidatorOrDie(const bool* flag,
bool (*validate_fn)(const char*, bool)) {
return RegisterFlagValidatorOrDieImpl(flag, validate_fn);
return butil::RegisterFlagValidatorOrDieImpl(flag, validate_fn);
}
bool RegisterFlagValidatorOrDie(const int32_t* flag,
bool (*validate_fn)(const char*, int32_t)) {
return RegisterFlagValidatorOrDieImpl(flag, validate_fn);
return butil::RegisterFlagValidatorOrDieImpl(flag, validate_fn);
}
bool RegisterFlagValidatorOrDie(const int64_t* flag,
bool (*validate_fn)(const char*, int64_t)) {
return RegisterFlagValidatorOrDieImpl(flag, validate_fn);
return butil::RegisterFlagValidatorOrDieImpl(flag, validate_fn);
}
bool RegisterFlagValidatorOrDie(const uint64_t* flag,
bool (*validate_fn)(const char*, uint64_t)) {
return RegisterFlagValidatorOrDieImpl(flag, validate_fn);
return butil::RegisterFlagValidatorOrDieImpl(flag, validate_fn);
}
bool RegisterFlagValidatorOrDie(const double* flag,
bool (*validate_fn)(const char*, double)) {
return RegisterFlagValidatorOrDieImpl(flag, validate_fn);
return butil::RegisterFlagValidatorOrDieImpl(flag, validate_fn);
}

} // namespace brpc
47 changes: 13 additions & 34 deletions src/brpc/reloadable_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,7 @@
#ifndef BRPC_RELOADABLE_FLAGS_H
#define BRPC_RELOADABLE_FLAGS_H

// To brpc developers: This is a header included by user, don't depend
// on internal structures, use opaque pointers instead.

#include <stdint.h>

// Register an always-true valiator to a gflag so that the gflag is treated as
// reloadable by brpc. If a validator exists, abort the program.
// You should call this macro within global scope. for example:
//
// DEFINE_int32(foo, 0, "blah blah");
// BRPC_VALIDATE_GFLAG(foo, brpc::PassValidate);
//
// This macro does not work for string-flags because they're thread-unsafe to
// modify directly. To emphasize this, you have to write the validator by
// yourself and use GFLAGS_NS::GetCommandLineOption() to acess the flag.
#define BRPC_VALIDATE_GFLAG(flag, validate_fn) \
namespace brpc_flags {} \
const int register_FLAGS_ ## flag ## _dummy \
__attribute__((__unused__)) = \
::brpc::RegisterFlagValidatorOrDie( \
&FLAGS_##flag, (validate_fn))

#include "butil/reloadable_flags.h"

namespace brpc {

Expand All @@ -59,18 +38,18 @@ extern bool PositiveInteger(const char*, uint64_t);
extern bool NonNegativeInteger(const char*, int32_t);
extern bool NonNegativeInteger(const char*, int64_t);

extern bool RegisterFlagValidatorOrDie(const bool* flag,
bool (*validate_fn)(const char*, bool));
extern bool RegisterFlagValidatorOrDie(const int32_t* flag,
bool (*validate_fn)(const char*, int32_t));
extern bool RegisterFlagValidatorOrDie(const uint32_t* flag,
bool (*validate_fn)(const char*, uint32_t));
extern bool RegisterFlagValidatorOrDie(const int64_t* flag,
bool (*validate_fn)(const char*, int64_t));
extern bool RegisterFlagValidatorOrDie(const uint64_t* flag,
bool (*validate_fn)(const char*, uint64_t));
extern bool RegisterFlagValidatorOrDie(const double* flag,
bool (*validate_fn)(const char*, double));
extern bool RegisterFlagValidatorOrDie(
const bool* flag, bool (*validate_fn)(const char*, bool));
extern bool RegisterFlagValidatorOrDie(
const int32_t* flag, bool (*validate_fn)(const char*, int32_t));
extern bool RegisterFlagValidatorOrDie(
const uint32_t* flag, bool (*validate_fn)(const char*, uint32_t));
extern bool RegisterFlagValidatorOrDie(
const int64_t* flag, bool (*validate_fn)(const char*, int64_t));
extern bool RegisterFlagValidatorOrDie(
const uint64_t* flag, bool (*validate_fn)(const char*, uint64_t));
extern bool RegisterFlagValidatorOrDie(
const double* flag, bool (*validate_fn)(const char*, double));
} // namespace brpc


Expand Down
46 changes: 2 additions & 44 deletions src/brpc/shared_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,53 +19,11 @@
#ifndef BRPC_SHARED_OBJECT_H
#define BRPC_SHARED_OBJECT_H

#include "butil/intrusive_ptr.hpp" // butil::intrusive_ptr
#include "butil/atomicops.h"

#include "butil/shared_object.h"

namespace brpc {

// Inherit this class to be intrusively shared. Comparing to shared_ptr,
// intrusive_ptr saves one malloc (for shared_count) and gets better cache
// locality when the ref/deref are frequent, in the cost of lack of weak_ptr
// and worse interface.
class SharedObject {
friend void intrusive_ptr_add_ref(SharedObject*);
friend void intrusive_ptr_release(SharedObject*);

public:
SharedObject() : _nref(0) { }
int ref_count() const { return _nref.load(butil::memory_order_relaxed); }

// Add ref and returns the ref_count seen before added.
// The effect is basically same as butil::intrusive_ptr<T>(obj).detach()
// except that the latter one does not return the seen ref_count which is
// useful in some scenarios.
int AddRefManually()
{ return _nref.fetch_add(1, butil::memory_order_relaxed); }

// Remove one ref, if the ref_count hit zero, delete this object.
// Same as butil::intrusive_ptr<T>(obj, false).reset(NULL)
void RemoveRefManually() {
if (_nref.fetch_sub(1, butil::memory_order_release) == 1) {
butil::atomic_thread_fence(butil::memory_order_acquire);
delete this;
}
}

protected:
virtual ~SharedObject() { }
private:
butil::atomic<int> _nref;
};

inline void intrusive_ptr_add_ref(SharedObject* obj) {
obj->AddRefManually();
}

inline void intrusive_ptr_release(SharedObject* obj) {
obj->RemoveRefManually();
}
using butil::SharedObject;

} // namespace brpc

Expand Down
2 changes: 1 addition & 1 deletion src/bthread/task_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ int TaskControl::init(int concurrency) {
}

#ifdef BRPC_BTHREAD_TRACER
if (_task_tracer.Init() != 0) {
if (!_task_tracer.Init()) {
LOG(ERROR) << "Fail to init TaskTracer";
return -1;
}
Expand Down
13 changes: 10 additions & 3 deletions src/bthread/task_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,13 @@ void TaskGroup::sched_to(TaskGroup** pg, TaskMeta* next_meta) {
CHECK(cur_meta->stack == g->_main_stack);
}
#endif
} /* else because of ending_sched(including pthread_task->pthread_task). */
#ifdef BRPC_BTHREAD_TRACER
else {
// _cur_meta: TASK_STATUS_FIRST_READY -> TASK_STATUS_RUNNING.
TaskTracer::set_running_status(g->tid(), g->_cur_meta);
}
// else because of ending_sched(including pthread_task->pthread_task)
#endif // BRPC_BTHREAD_TRACER
} else {
LOG(FATAL) << "bthread=" << g->current_tid() << " sched_to itself!";
}
Expand Down Expand Up @@ -1013,13 +1018,15 @@ void print_task(std::ostream& os, bthread_t tid) {
<< "}\nhas_tls=" << has_tls
<< "\nuptime_ns=" << butil::cpuwide_time_ns() - cpuwide_start_ns
<< "\ncputime_ns=" << stat.cputime_ns
<< "\nnswitch=" << stat.nswitch
<< "\nnswitch=" << stat.nswitch
#ifdef BRPC_BTHREAD_TRACER
<< "\nstatus=" << status
<< "\ntraced=" << traced
<< "\nworker_tid=" << worker_tid;
#endif // BRPC_BTHREAD_TRACER
#else
;
(void)status;(void)traced;(void)worker_tid;
#endif // BRPC_BTHREAD_TRACER
}
}

Expand Down
Loading

0 comments on commit 6b52eba

Please sign in to comment.