10 #define UNW_LOCAL_ONLY 
   28 #include <sys/types.h> 
   31 #if !defined(ZTH_OS_WINDOWS) && !defined(ZTH_OS_BAREMETAL) 
   34 #       include <execinfo.h> 
   37 #ifdef ZTH_HAVE_LIBUNWIND 
   38 #       include <libunwind.h> 
   60                 if(!processEventBuffer())
 
   87                 size_t spareRoom = eventBuffer().capacity() - eventBuffer().size();
 
   88                 if(
unlikely(!f || f == m_worker.currentFiber() || spareRoom < 3)) {
 
   94                 if(
likely(spareRoom > 3)) {
 
  101                 Fiber* currentFiber_ = m_worker.currentFiber();
 
  104                         processEventBuffer();
 
  113                 e.
c_str = 
"Emerg flush";
 
  114                 eventBuffer().push_back(e);
 
  119                 eventBuffer().push_back(e);
 
  123                 eventBuffer().push_back(e);
 
  125                 zth_dbg(perf, 
"Emergency processEventBuffer()");
 
  126                 processEventBuffer();
 
  132                 eventBuffer().push_back(e);
 
  136                 eventBuffer().push_back(e);
 
  158                         if(processEventBuffer())
 
  161                         m_worker.suspend(*
this);
 
  172                 size_t eb_size = eb.size();
 
  179                 for(
size_t i = 0; i < eb_size; i++) {
 
  182                         char const* s = 
nullptr;
 
  187                                         for(
char* p = e.
str; *p; ++p) {
 
  188                                                 if(*p < 33 || *p > 126)
 
  191                                         string const& 
id = vcdId(e.
fiber);
 
  193                                                    "$var wire 1 %s \\#%" PRIu64
 
  194                                                    "_%s $end\n$var real 0 %s! \\#%" PRIu64
 
  203                                         string const& 
id = vcdId(e.
fiber);
 
  205                                                    "$var wire 1 %s %" PRIu64
 
  206                                                    "_Fiber $end\n$var real 0 %s! %" PRIu64
 
  218                                 bool doCleanup = 
false;
 
  243                                 if(fprintf(m_vcdd, 
"#%" PRIu64 
"%09ld\n%c%s\n",
 
  244                                            (uint64_t)t.
ts().tv_sec, t.
ts().tv_nsec, x,
 
  245                                            vcdId(e.
fiber).c_str())
 
  252                                         vcdIdRelease(e.
fiber);
 
  267                                 if(fprintf(m_vcdd, 
"#%" PRIu64 
"%09ld\ns", (uint64_t)t.
ts().tv_sec,
 
  274                                 char const* chunkStart = s;
 
  275                                 char const* chunkEnd = chunkStart;
 
  278                                         if(*chunkEnd < 33 || *chunkEnd > 126) {
 
  279                                                 if(fprintf(m_vcdd, 
"%.*s\\x%02hhx", len, chunkStart,
 
  280                                                            (
unsigned char)*chunkEnd)
 
  285                                                 chunkStart = chunkEnd = chunkEnd + 1;
 
  293                                 if(fprintf(m_vcdd, 
"%s %s!\n", chunkStart, vcdId(e.
fiber).c_str())
 
  305                 for(
size_t i = 0; i < eb_size; i++)
 
  311                 fprintf(stderr, 
"Cannot write VCD file; %s\n", 
err(res).c_str());
 
  320                 char vcdFilename_[32];
 
  321                 char const* vcdFilename =
 
  322                         snprintf(vcdFilename_, 
sizeof(vcdFilename_), 
"zth.%d.vcd", (
int)getpid())
 
  327                 if(!(m_vcd = fopen(vcdFilename, 
"w"))) {
 
  329                         fprintf(stderr, 
"Cannot open VCD file %s; %s\n", vcdFilename,
 
  334 #ifdef ZTH_OS_WINDOWS 
  336                 m_vcdd = fopen(
"zth.vcdd", 
"w+");
 
  341                         fprintf(stderr, 
"Cannot open temporary VCD data file; %s\n",
 
  348                         if(time(&now) != -1) {
 
  349 #if defined(ZTH_OS_LINUX) || defined(ZTH_OS_MAC) 
  351                                 char* strnow = ctime_r(&now, dateBuf);
 
  354                                 char* strnow = ctime(&now);
 
  357                                         if(fprintf(m_vcd, 
"$date %s$end\n", strnow) < 0)
 
  363                            "$version %s $end\n$timescale 1 ns $end\n$scope module top $end\n",
 
  368                 fprintf(stderr, 
"Using %s for perf VCD output\n", vcdFilename);
 
  372                 fprintf(stderr, 
"Cannot write %s", vcdFilename);
 
  383                 return res ? res : EIO;
 
  388                 if(!m_vcd || !m_vcdd)
 
  392                 if(fprintf(m_vcd, 
"$upscope $end\n$enddefinitions $end\n") < 0)
 
  400                         while((cnt = fread(buf, 1, 
sizeof(buf), m_vcdd)) > 0)
 
  401                                 if(fwrite(buf, cnt, 1, m_vcd) != 1)
 
  418                 fprintf(stderr, 
"Cannot read temporary VCD data file\n");
 
  419                 return res ? res : EIO;
 
  421                 fprintf(stderr, 
"Cannot write VCD file\n");
 
  422                 return res ? res : EIO;
 
  427                 std::pair<decltype(m_vcdIds.begin()), 
bool> i =
 
  428                         m_vcdIds.insert(std::make_pair(
fiber, 
string()));
 
  431                         return i.first->second;
 
  438                 char* s = &buf[
sizeof(buf) - 1];
 
  442                         *--s = (char)(
id % 93 + 34);
 
  446                 return i.first->second = s;
 
  451                 decltype(m_vcdIds.begin()) it = m_vcdIds.find(
fiber);
 
  452                 if(it != m_vcdIds.end())
 
  476         return perfFiber->
run();
 
  518         m_fiberId = m_fiber ? m_fiber->
id() : 0;
 
  520 #ifdef ZTH_HAVE_LIBUNWIND 
  523         if(unw_getcontext(&uc))
 
  527         unw_init_local(&cursor, &uc);
 
  529         for(
size_t i = 0; i < skip && unw_step(&cursor) > 0; i++)
 
  534         while(unw_step(&cursor) > 0 && depth < maxDepth) {
 
  537                         unw_get_reg(&cursor, UNW_REG_SP, &sp);
 
  541                 unw_get_reg(&cursor, UNW_REG_IP, &ip);
 
  542                 m_bt.push_back(
reinterpret_cast<void*
>(ip));
 
  544                 if(unw_get_proc_info(&cursor, &pip) == 0
 
  545                    && pip.start_ip == 
reinterpret_cast<unw_word_t
>(&
context_entry))
 
  551         m_truncated = depth == maxDepth;
 
  552 #elif !defined(ZTH_OS_WINDOWS) && !defined(ZTH_OS_BAREMETAL) 
  553         m_bt.resize(maxDepth);
 
  554         m_bt.resize((
size_t)backtrace(m_bt.data(), (
int)maxDepth));
 
  556         m_truncated = m_bt.size() == maxDepth;
 
  565 #if !defined(ZTH_OS_WINDOWS) && !defined(ZTH_OS_BAREMETAL) 
  569                 if(-
end > (ssize_t)
bt().size())
 
  573         if(start > (
size_t)
end)
 
  577         FILE* atosf = 
nullptr;
 
  580                 int len = snprintf(atos, 
sizeof(atos), 
"atos -p %d\n", getpid());
 
  581                 if(len > 0 && (
size_t)len < 
sizeof(atos)) {
 
  583                         atosf = popen(atos, 
"w");
 
  592                        backtrace_symbols(&
bt()[start], (
int)((
size_t)
end - start + 1));
 
  594         for(
size_t i = start; i <= (size_t)
end; i++) {
 
  597                         fprintf(atosf, 
"%p\n", 
bt()[i]);
 
  603                 if(dladdr(
bt()[i], &info)) {
 
  606                                 abi::__cxa_demangle(info.dli_sname, 
nullptr, 
nullptr, &status);
 
  607                         if(status == 0 && demangled) {
 
  610                                         color, 
"%s%-3zd 0x%0*" PRIxPTR 
" %s + %" PRIuPTR 
"\n",
 
  612                                         reinterpret_cast<uintptr_t
>(
bt()[i]), demangled,
 
  613                                         reinterpret_cast<uintptr_t
>(
bt()[i])
 
  614                                                 - 
reinterpret_cast<uintptr_t
>(info.dli_saddr));
 
  617                                         color, 
"%s%-3zd %s(%s+0x%" PRIxPTR 
") [0x%" PRIxPTR 
"]\n",
 
  620                                         reinterpret_cast<uintptr_t
>(
bt()[i])
 
  621                                                 - 
reinterpret_cast<uintptr_t
>(info.dli_saddr),
 
  622                                         reinterpret_cast<uintptr_t
>(
bt()[i]));
 
  636                                 color, 
"%s%-3zd 0x%0*" PRIxPTR 
"\n",
 
  638                                 reinterpret_cast<uintptr_t
>(
bt()[i]));
 
  653 #if !defined(ZTH_OS_WINDOWS) && !defined(ZTH_OS_BAREMETAL) 
  655                 color, 
"%sBacktrace of fiber %p #%" PRIu64 
":\n", color >= 0 ? 
ZTH_DBG_PREFIX : 
"",
 
  670         if(other.
t0() > 
t0()) {
 
  691                 size_t max_common = std::min(this_bt.size(), other_bt.size());
 
  692                 while((
size_t)common < max_common
 
  693                       && this_bt[this_bt.size() - 1 - (
size_t)common]
 
  694                                  == other_bt[other_bt.size() - 1 - (
size_t)common])
 
  699                 color, 
"%sExecution from fiber %p #%" PRIu64 
":\n",
 
void printDelta(Backtrace const &other, int color=-1) const
 
bool truncated() const noexcept
 
vector_type< void * >::type bt_type
 
void print(int color=-1) const
 
Timestamp const  & t0() const noexcept
 
Timestamp const  & t1() const noexcept
 
void printPartial(size_t start, ssize_t end=-1, int color=-1) const
 
Backtrace(size_t skip=0, size_t maxDepth=128)
 
uint64_t fiberId() const noexcept
 
bt_type const  & bt() const noexcept
 
State state() const noexcept
 
virtual int fiberHook(Fiber &f) override
 
string const  & vcdId(uint64_t fiber)
 
static perf_eventBuffer_type & eventBuffer()
 
virtual void entry() override
 
virtual ~PerfFiber() override
 
void vcdIdRelease(uint64_t fiber)
 
PerfFiber(Worker *worker)
 
An abstract class, that can be started as a fiber.
 
virtual int fiberHook(Fiber &f)
 
static safe_ptr< singleton_type >::type instance() noexcept
Return the only instance of T within this thread.
 
Convenient wrapper around struct timespec that contains a time interval.
 
constexpr struct timespec const  & ts() const noexcept
 
Convenient wrapper around struct timespec that contains an absolute timestamp.
 
uint64_t id() const noexcept
 
void setName(string const &name)
 
The class that manages the fibers within this thread.
 
Fiber * currentFiber() const noexcept
 
#define zth_config(name)
Checks if the given zth::Config field is enabled.
 
fiber_type< F >::factory fiber(F f, char const *name=nullptr)
Create a new fiber.
 
@ end
End-of-guard-list marker.
 
#define zth_dbg(group, fmt, a...)
Debug printf()-like function.
 
void log_color(int color, char const *fmt,...)
Logs a given printf()-like formatted string using an ANSI color code.
 
char const  * banner() noexcept
Prints a banner line with version and configuration information.
 
#define ZTH_CLASS_NEW_DELETE(T)
Define new/delete operators for a class, which are allocator-aware.
 
#define ZTH_TLS_STATIC(type, var, init)
 
#define ZTH_TLS_DEFINE(type, var, init)
 
void getContext(Worker **worker, Fiber **fiber) noexcept
 
void context_entry(Context *context)
 
Timestamp const startTime
 
__thread perf_eventBuffer_type * perf_eventBuffer
 
vector_type< PerfEvent<> >::type perf_eventBuffer_type
 
void perf_flushEventBuffer() noexcept
 
string err(int e)
Return a string like strerror() does, but as a zth::string.
 
static bool const EnablePerfEvent
Enable (but not necessarily record) perf.
 
static bool const Debug
This is a debug build when set to true.
 
static size_t const PerfEventBufferSize
Buffer size for perf events.
 
An event to be processed by perf_event().
 
std::map type using Config::Allocator::type.
 
#define ZTH_DBG_PREFIX
Prefix for every zth_dbg() call.
 
#define zth_assert(expr)
assert(), but better integrated in Zth.
 
#define likely(expr)
Marks the given expression to likely be evaluated to true.
 
#define ZTH_CLASS_NOCOPY(Class)
 
#define unlikely(expr)
Marks the given expression to likely be evaluated to true.