Seastar
High performance C++ framework for concurrent servers
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
stall_detector.hh
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#ifndef SEASTAR_MODULE
26#include <signal.h>
27#include <atomic>
28#include <limits>
29#include <chrono>
30#include <functional>
31#include <memory>
32#include <linux/perf_event.h>
33#endif
34#include <seastar/core/posix.hh>
37#include <seastar/util/modules.hh>
38
39namespace seastar {
40
41class reactor;
42class thread_cputime_clock;
43
44namespace internal {
45
46struct cpu_stall_detector_config {
47 std::chrono::duration<double> threshold = std::chrono::seconds(2);
48 unsigned stall_detector_reports_per_minute = 1;
49 float slack = 0.3; // fraction of threshold that we're allowed to overshoot
50 bool oneline = true; // print a simplified backtrace on a single line
51 std::function<void ()> report; // alternative reporting function for tests
52};
53
54// Detects stalls in continuations that run for too long
55class cpu_stall_detector {
56protected:
57 std::atomic<uint64_t> _last_tasks_processed_seen{};
58 std::atomic<uint64_t> _stall_detector_missed_ticks = { 0 };
59 unsigned _reported = 0;
60 unsigned _total_reported = 0;
61 unsigned _max_reports_per_minute;
62 unsigned _shard_id;
63 unsigned _thread_id;
64 unsigned _report_at{};
65 sched_clock::time_point _minute_mark{};
66 sched_clock::time_point _rearm_timer_at{};
67 sched_clock::time_point _run_started_at{};
68 sched_clock::duration _threshold;
69 sched_clock::duration _slack;
70 cpu_stall_detector_config _config;
72 friend reactor;
73 virtual bool is_spurious_signal() {
74 return false;
75 }
76 virtual void maybe_report_kernel_trace() {}
77private:
78 void maybe_report();
79 virtual void arm_timer() = 0;
80 void report_suppressions(sched_clock::time_point now);
81 void reset_suppression_state(sched_clock::time_point now);
82public:
83 using clock_type = thread_cputime_clock;
84public:
85 explicit cpu_stall_detector(cpu_stall_detector_config cfg = {});
86 virtual ~cpu_stall_detector() = default;
87 static int signal_number() { return SIGRTMIN + 1; }
88 void start_task_run(sched_clock::time_point now);
89 void end_task_run(sched_clock::time_point now);
90 void generate_trace();
91 void update_config(cpu_stall_detector_config cfg);
92 cpu_stall_detector_config get_config() const;
93 void on_signal();
94 virtual void start_sleep() = 0;
95 void end_sleep();
96};
97
98class cpu_stall_detector_posix_timer : public cpu_stall_detector {
99 timer_t _timer;
100public:
101 explicit cpu_stall_detector_posix_timer(cpu_stall_detector_config cfg = {});
102 virtual ~cpu_stall_detector_posix_timer() override;
103private:
104 virtual void arm_timer() override;
105 virtual void start_sleep() override;
106};
107
108class cpu_stall_detector_linux_perf_event : public cpu_stall_detector {
109 file_desc _fd;
110 bool _enabled = false;
111 uint64_t _current_period = 0;
112 struct ::perf_event_mmap_page* _mmap;
113 char* _data_area;
114 size_t _data_area_mask;
115 // after the detector has been armed (i.e., _enabled is true), this
116 // is the moment at or after which the next signal is expected to occur
117 // and can be used for detecting spurious signals
118 sched_clock::time_point _next_signal_time{};
119private:
120 class data_area_reader {
121 cpu_stall_detector_linux_perf_event& _p;
122 const char* _data_area;
123 size_t _data_area_mask;
124 uint64_t _head;
125 uint64_t _tail;
126 public:
127 explicit data_area_reader(cpu_stall_detector_linux_perf_event& p)
128 : _p(p)
129 , _data_area(p._data_area)
130 , _data_area_mask(p._data_area_mask) {
131 _head = _p._mmap->data_head;
132 _tail = _p._mmap->data_tail;
133 std::atomic_thread_fence(std::memory_order_acquire); // required after reading data_head
134 }
135 ~data_area_reader() {
136 std::atomic_thread_fence(std::memory_order_release); // not documented, but probably required before writing data_tail
137 _p._mmap->data_tail = _tail;
138 }
139 uint64_t read_u64() {
140 uint64_t ret;
141 // We cannot wrap around if the 8-byte unit is aligned
142 std::copy_n(_data_area + (_tail & _data_area_mask), 8, reinterpret_cast<char*>(&ret));
143 _tail += 8;
144 return ret;
145 }
146 template <typename S>
147 S read_struct() {
148 static_assert(sizeof(S) % 8 == 0);
149 S ret;
150 char* p = reinterpret_cast<char*>(&ret);
151 for (size_t i = 0; i != sizeof(S); i += 8) {
152 uint64_t w = read_u64();
153 std::copy_n(reinterpret_cast<const char*>(&w), 8, p + i);
154 }
155 return ret;
156 }
157 void skip(uint64_t bytes_to_skip) {
158 _tail += bytes_to_skip;
159 }
160 // skip all the remaining data in the buffer, as-if calling read until
161 // have_data returns false (but much faster)
162 void skip_all() {
163 _tail = _head;
164 }
165 bool have_data() const {
166 return _head != _tail;
167 }
168 };
169public:
170 static std::unique_ptr<cpu_stall_detector_linux_perf_event> try_make(cpu_stall_detector_config cfg = {});
171 explicit cpu_stall_detector_linux_perf_event(file_desc fd, cpu_stall_detector_config cfg = {});
172 ~cpu_stall_detector_linux_perf_event();
173 virtual void arm_timer() override;
174 virtual void start_sleep() override;
175 virtual bool is_spurious_signal() override;
176 virtual void maybe_report_kernel_trace() override;
177};
178
179std::unique_ptr<cpu_stall_detector> make_cpu_stall_detector(cpu_stall_detector_config cfg = {});
180
181}
182}
holds the metric definition.
Definition: metrics_registration.hh:94
future now()
Returns a ready future.
Definition: later.hh:35
holds the metric_groups definition needed by class that reports metrics
Seastar API namespace.
Definition: abort_on_ebadf.hh:26