aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Common/QueryProfiler.h
blob: 38fe125f614d5210df83dc2947186eb5f9ec93ee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#pragma once

#include <optional>
#include <base/types.h>
#include <signal.h>
#include <time.h>

#include "clickhouse_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);
};

}