ClickHouse/src/Common/QueryProfiler.h
Azat Khuzhin a10aa9ad50 Force libunwind usage (removes gcc_eh support)
libunwind is reentrant and signal safe, and works faster then then
gcc_eh (plus it has some custom patches for problems that have been
found during it's usage in ClickHouse).

gcc_eh may be missing in the system (if gcc was not installed), and
even if it exists clickhouse uses -nodefaultlibs, so some care should be
made to make it work.

Also this library is tiny and there shouln't be any problem to require
it always (there is already tendency to require some contrib libraries,
i.e. poco).

Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
2023-07-08 20:55:50 +02:00

90 lines
1.9 KiB
C++

#pragma once
#include <optional>
#include <base/types.h>
#include <signal.h>
#include <time.h>
#include "config.h"
namespace Poco
{
class Logger;
}
namespace DB
{
/**
* Query profiler implementation for selected thread.
*
* This class installs timer and signal handler on creation to:
* 1. periodically pause given thread
* 2. collect thread's current stack trace
* 3. write collected stack trace to trace_pipe for TraceCollector
*
* Destructor tries to unset timer and restore previous signal handler.
* Note that signal handler implementation is defined by template parameter. See QueryProfilerReal and QueryProfilerCPU.
*/
#ifndef __APPLE__
class Timer
{
public:
Timer();
Timer(const Timer &) = delete;
Timer & operator = (const Timer &) = delete;
~Timer();
void createIfNecessary(UInt64 thread_id, int clock_type, int pause_signal);
void set(UInt32 period);
void stop();
void cleanup();
private:
Poco::Logger * log;
std::optional<timer_t> timer_id;
};
#endif
template <typename ProfilerImpl>
class QueryProfilerBase
{
public:
QueryProfilerBase(UInt64 thread_id, int clock_type, UInt32 period, int pause_signal_);
~QueryProfilerBase();
private:
void cleanup();
Poco::Logger * log;
#ifndef __APPLE__
inline static thread_local Timer timer = Timer();
#endif
/// Pause signal to interrupt threads to get traces
int pause_signal;
};
/// Query profiler with timer based on real clock
class QueryProfilerReal : public QueryProfilerBase<QueryProfilerReal>
{
public:
QueryProfilerReal(UInt64 thread_id, UInt32 period); /// NOLINT
static void signalHandler(int sig, siginfo_t * info, void * context);
};
/// Query profiler with timer based on CPU clock
class QueryProfilerCPU : public QueryProfilerBase<QueryProfilerCPU>
{
public:
QueryProfilerCPU(UInt64 thread_id, UInt32 period); /// NOLINT
static void signalHandler(int sig, siginfo_t * info, void * context);
};
}