]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/src/core/stall_detector.hh
import quincy beta 17.1.0
[ceph.git] / ceph / src / seastar / src / core / stall_detector.hh
CommitLineData
11fdf7f2
TL
1
2/*
3 * This file is open source software, licensed to you under the terms
4 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
5 * distributed with this work for additional information regarding copyright
6 * ownership. You may not use this file except in compliance with the License.
7 *
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19/*
20 * Copyright (C) 2018 ScyllaDB
21 */
22
23#pragma once
24
25#include <signal.h>
26#include <limits>
27#include <chrono>
28#include <functional>
20effc67 29#include <memory>
11fdf7f2 30#include <seastar/core/posix.hh>
9f95a23c 31#include <seastar/core/metrics_registration.hh>
20effc67
TL
32#include <seastar/core/scheduling.hh>
33#include <linux/perf_event.h>
11fdf7f2
TL
34
35namespace seastar {
36
37class reactor;
f67539c2 38class thread_cputime_clock;
11fdf7f2
TL
39
40namespace internal {
41
42struct cpu_stall_detector_config {
43 std::chrono::duration<double> threshold = std::chrono::seconds(2);
44 unsigned stall_detector_reports_per_minute = 1;
45 float slack = 0.3; // fraction of threshold that we're allowed to overshoot
20effc67 46 bool oneline = true; // print a simplified backtrace on a single line
11fdf7f2
TL
47 std::function<void ()> report; // alternative reporting function for tests
48};
49
50// Detects stalls in continuations that run for too long
51class cpu_stall_detector {
20effc67 52protected:
9f95a23c 53 std::atomic<uint64_t> _last_tasks_processed_seen{};
11fdf7f2
TL
54 unsigned _stall_detector_reports_per_minute;
55 std::atomic<uint64_t> _stall_detector_missed_ticks = { 0 };
56 unsigned _reported = 0;
9f95a23c 57 unsigned _total_reported = 0;
11fdf7f2
TL
58 unsigned _max_reports_per_minute;
59 unsigned _shard_id;
60 unsigned _thread_id;
61 unsigned _report_at{};
20effc67
TL
62 sched_clock::time_point _minute_mark{};
63 sched_clock::time_point _rearm_timer_at{};
64 sched_clock::time_point _run_started_at{};
65 sched_clock::duration _threshold;
66 sched_clock::duration _slack;
11fdf7f2 67 cpu_stall_detector_config _config;
9f95a23c 68 seastar::metrics::metric_groups _metrics;
11fdf7f2 69 friend reactor;
20effc67
TL
70 virtual bool reap_event_and_check_spuriousness() {
71 return false;
72 }
73 virtual void maybe_report_kernel_trace() {}
11fdf7f2
TL
74private:
75 void maybe_report();
20effc67
TL
76 virtual void arm_timer() = 0;
77 void report_suppressions(sched_clock::time_point now);
11fdf7f2 78public:
f67539c2
TL
79 using clock_type = thread_cputime_clock;
80public:
81 explicit cpu_stall_detector(cpu_stall_detector_config cfg = {});
20effc67 82 virtual ~cpu_stall_detector() = default;
11fdf7f2 83 static int signal_number() { return SIGRTMIN + 1; }
20effc67
TL
84 void start_task_run(sched_clock::time_point now);
85 void end_task_run(sched_clock::time_point now);
11fdf7f2
TL
86 void generate_trace();
87 void update_config(cpu_stall_detector_config cfg);
88 cpu_stall_detector_config get_config() const;
89 void on_signal();
20effc67 90 virtual void start_sleep() = 0;
11fdf7f2
TL
91 void end_sleep();
92};
93
20effc67
TL
94class cpu_stall_detector_posix_timer : public cpu_stall_detector {
95 timer_t _timer;
96public:
97 explicit cpu_stall_detector_posix_timer(cpu_stall_detector_config cfg = {});
98 virtual ~cpu_stall_detector_posix_timer() override;
99private:
100 virtual void arm_timer() override;
101 virtual void start_sleep() override;
102};
103
104class cpu_stall_detector_linux_perf_event : public cpu_stall_detector {
105 file_desc _fd;
106 bool _enabled = false;
107 uint64_t _current_period = 0;
108 struct ::perf_event_mmap_page* _mmap;
109 char* _data_area;
110 size_t _data_area_mask;
111private:
112 class data_area_reader {
113 cpu_stall_detector_linux_perf_event& _p;
114 const char* _data_area;
115 size_t _data_area_mask;
116 uint64_t _head;
117 uint64_t _tail;
118 public:
119 explicit data_area_reader(cpu_stall_detector_linux_perf_event& p)
120 : _p(p)
121 , _data_area(p._data_area)
122 , _data_area_mask(p._data_area_mask) {
123 _head = _p._mmap->data_head;
124 _tail = _p._mmap->data_tail;
125 std::atomic_thread_fence(std::memory_order_acquire); // required after reading data_head
126 }
127 ~data_area_reader() {
128 std::atomic_thread_fence(std::memory_order_release); // not documented, but probably required before writing data_tail
129 _p._mmap->data_tail = _tail;
130 }
131 uint64_t read_u64() {
132 uint64_t ret;
133 // We cannot wrap around if the 8-byte unit is aligned
134 std::copy_n(_data_area + (_tail & _data_area_mask), 8, reinterpret_cast<char*>(&ret));
135 _tail += 8;
136 return ret;
137 }
138 template <typename S>
139 S read_struct() {
140 static_assert(sizeof(S) % 8 == 0);
141 S ret;
142 char* p = reinterpret_cast<char*>(&ret);
143 for (size_t i = 0; i != sizeof(S); i += 8) {
144 uint64_t w = read_u64();
145 std::copy_n(reinterpret_cast<const char*>(&w), 8, p + i);
146 }
147 return ret;
148 }
149 void skip(uint64_t bytes_to_skip) {
150 _tail += bytes_to_skip;
151 }
152 bool have_data() const {
153 return _head != _tail;
154 }
155 };
156public:
157 static std::unique_ptr<cpu_stall_detector_linux_perf_event> try_make(cpu_stall_detector_config cfg = {});
158 explicit cpu_stall_detector_linux_perf_event(file_desc fd, cpu_stall_detector_config cfg = {});
159 ~cpu_stall_detector_linux_perf_event();
160 virtual void arm_timer() override;
161 virtual void start_sleep() override;
162 virtual bool reap_event_and_check_spuriousness() override;
163 virtual void maybe_report_kernel_trace() override;
164};
165
166std::unique_ptr<cpu_stall_detector> make_cpu_stall_detector(cpu_stall_detector_config cfg = {});
167
11fdf7f2
TL
168}
169}