Skip to content

Commit 531c451

Browse files
feat: socket engine stats functions (#1353)
1 parent dd567e6 commit 531c451

File tree

6 files changed

+126
-37
lines changed

6 files changed

+126
-37
lines changed

include/dpp/socketengine.h

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <cstdint>
2525
#include <unordered_map>
2626
#include <memory>
27+
#include <string_view>
2728
#include <functional>
2829
#include <shared_mutex>
2930
#include <dpp/thread_pool.h>
@@ -74,6 +75,51 @@ using socket_write_event = std::function<void(dpp::socket fd, const struct socke
7475
*/
7576
using socket_error_event = std::function<void(dpp::socket fd, const struct socket_events&, int error_code)>;
7677

78+
/**
79+
* @brief Contains statistics about the IO loop
80+
*/
81+
struct DPP_EXPORT socket_stats {
82+
/**
83+
* @brief Number of reads since startup
84+
*/
85+
uint64_t reads{0};
86+
87+
/**
88+
* @brief Number of writes since startup
89+
*/
90+
uint64_t writes{0};
91+
92+
/**
93+
* @brief Number of errors since startup
94+
*/
95+
uint64_t errors{0};
96+
97+
/**
98+
* @brief Number of updates to file descriptors
99+
*/
100+
uint64_t updates{0};
101+
102+
/**
103+
* @brief Number of deletions of file descriptors
104+
*/
105+
uint64_t deletions{0};
106+
107+
/**
108+
* @brief Number of loop iterations since startup
109+
*/
110+
uint64_t iterations{0};
111+
112+
/**
113+
* @brief Number of currently active file descriptors
114+
*/
115+
uint64_t active_fds{0};
116+
117+
/**
118+
* @brief Socket engine type
119+
*/
120+
std::string_view engine_type;
121+
};
122+
77123
/**
78124
* @brief Represents an active socket event set in the socket engine.
79125
*
@@ -150,21 +196,6 @@ using socket_container = std::unordered_map<dpp::socket, std::unique_ptr<socket_
150196
*/
151197
struct DPP_EXPORT socket_engine_base {
152198

153-
/**
154-
* @brief Mutex for fds
155-
*/
156-
std::shared_mutex fds_mutex;
157-
158-
/**
159-
* @brief File descriptors, and their states
160-
*/
161-
socket_container fds;
162-
163-
/**
164-
* @brief Number of file descriptors we are waiting to delete
165-
*/
166-
size_t to_delete_count{0};
167-
168199
/**
169200
* @brief Owning cluster
170201
*/
@@ -238,21 +269,49 @@ struct DPP_EXPORT socket_engine_base {
238269
*/
239270
void prune();
240271

272+
/**
273+
* @brief Merge new flags in with the given file descriptor
274+
* @param fd file descriptor
275+
* @param extra_flags extra flags to add
276+
*/
277+
void inplace_modify_fd(dpp::socket fd, uint8_t extra_flags);
278+
279+
/**
280+
* @brief Get statistics for socket engine
281+
* @return socket stats
282+
*/
283+
const socket_stats& get_stats() const;
284+
241285
protected:
242286

243287
/**
244-
* @brief Called by the prune() function to remove sockets when safe to do so.
245-
* This is normally at the end or before an iteration of the event loop.
246-
* @param fd File descriptor to remove
288+
* @brief Mutex for fds
247289
*/
248-
virtual bool remove_socket(dpp::socket fd);
290+
std::shared_mutex fds_mutex;
291+
292+
/**
293+
* @brief File descriptors, and their states
294+
*/
295+
socket_container fds;
296+
297+
/**
298+
* @brief Socket engine statistics
299+
*/
300+
socket_stats stats{};
249301

250302
/**
251303
* @brief Find a file descriptors socket events
252304
* @param fd file descriptor
253305
* @return file descriptor or nullptr if doesn't exist
254306
*/
255307
socket_events* get_fd(dpp::socket fd);
308+
309+
/**
310+
* @brief Called by the prune() function to remove sockets when safe to do so.
311+
* This is normally at the end or before an iteration of the event loop.
312+
* @param fd File descriptor to remove
313+
*/
314+
virtual bool remove_socket(dpp::socket fd);
256315
};
257316

258317
/**

src/dpp/socketengine.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,14 @@ bool socket_engine_base::register_socket(const socket_events &e) {
3535
auto i = fds.find(e.fd);
3636
if (e.fd != INVALID_SOCKET && i == fds.end()) {
3737
fds.emplace(e.fd, std::make_unique<socket_events>(e));
38+
stats.active_fds++;
3839
return true;
3940
}
4041
if (e.fd != INVALID_SOCKET && i != fds.end()) {
4142
remove_socket(e.fd);
4243
fds.erase(i);
4344
fds.emplace(e.fd, std::make_unique<socket_events>(e));
45+
stats.updates++;
4446
return true;
4547
}
4648
return false;
@@ -51,6 +53,7 @@ bool socket_engine_base::update_socket(const socket_events &e) {
5153
if (e.fd != INVALID_SOCKET && fds.find(e.fd) != fds.end()) {
5254
auto iter = fds.find(e.fd);
5355
*(iter->second) = e;
56+
stats.updates++;
5457
return true;
5558
}
5659
return false;
@@ -83,6 +86,23 @@ socket_events* socket_engine_base::get_fd(dpp::socket fd) {
8386
return iter->second.get();
8487
}
8588

89+
void socket_engine_base::inplace_modify_fd(dpp::socket fd, uint8_t extra_flags) {
90+
bool should_modify;
91+
socket_events s{};
92+
{
93+
std::lock_guard lk(fds_mutex);
94+
auto i = fds.find(fd);
95+
should_modify = i != fds.end() && (i->second->flags & extra_flags) != extra_flags;
96+
if (should_modify) {
97+
i->second->flags |= extra_flags;
98+
s = *(i->second);
99+
}
100+
}
101+
if (should_modify) {
102+
update_socket(s);
103+
}
104+
}
105+
86106
void socket_engine_base::prune() {
87107
if (time(nullptr) != last_time) {
88108
try {
@@ -101,6 +121,7 @@ void socket_engine_base::prune() {
101121

102122
last_time = time(nullptr);
103123
}
124+
stats.iterations++;
104125
}
105126

106127
bool socket_engine_base::delete_socket(dpp::socket fd) {
@@ -110,11 +131,17 @@ bool socket_engine_base::delete_socket(dpp::socket fd) {
110131
return false;
111132
}
112133
iter->second->flags |= WANT_DELETION;
134+
stats.deletions++;
135+
stats.active_fds--;
113136
return true;
114137
}
115138

116139
bool socket_engine_base::remove_socket(dpp::socket fd) {
117140
return true;
118141
}
119142

143+
const socket_stats& socket_engine_base::get_stats() const {
144+
return stats;
145+
}
146+
120147
}

src/dpp/socketengines/epoll.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct DPP_EXPORT socket_engine_epoll : public socket_engine_base {
5454

5555
int epoll_handle{INVALID_SOCKET};
5656
static constexpr size_t MAX_EVENTS = 65536;
57-
std::array<struct epoll_event, MAX_EVENTS> events;
57+
std::array<struct epoll_event, MAX_EVENTS> events{};
5858

5959
socket_engine_epoll(const socket_engine_epoll&) = delete;
6060
socket_engine_epoll(socket_engine_epoll&&) = delete;
@@ -65,6 +65,7 @@ struct DPP_EXPORT socket_engine_epoll : public socket_engine_base {
6565
if (epoll_handle == -1) {
6666
throw dpp::connection_exception("Failed to initialise epoll()");
6767
}
68+
stats.engine_type = "epoll";
6869
}
6970

7071
~socket_engine_epoll() override {
@@ -89,13 +90,15 @@ struct DPP_EXPORT socket_engine_epoll : public socket_engine_base {
8990
if ((eh->flags & WANT_DELETION) == 0L) try {
9091

9192
if ((ev.events & EPOLLHUP) != 0U) {
93+
stats.errors++;
9294
if (eh->on_error) {
9395
eh->on_error(fd, *eh, EPIPE);
9496
}
9597
continue;
9698
}
9799

98100
if ((ev.events & EPOLLERR) != 0U) {
101+
stats.errors++;
99102
socklen_t codesize = sizeof(int);
100103
int errcode{};
101104
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) {
@@ -111,18 +114,21 @@ struct DPP_EXPORT socket_engine_epoll : public socket_engine_base {
111114
/* Should we have a flag to allow keeping WANT_WRITE? Maybe like WANT_WRITE_ONCE or GREEDY_WANT_WRITE, eh */
112115
eh->flags = modify_event(epoll_handle, eh, eh->flags & ~WANT_WRITE);
113116
if (eh->on_write) {
117+
stats.writes++;
114118
eh->on_write(fd, *eh);
115119
}
116120
}
117121

118122
if ((ev.events & EPOLLIN) != 0U) {
119123
if (eh->on_read) {
124+
stats.reads++;
120125
eh->on_read(fd, *eh);
121126
}
122127
}
123128

124129
} catch (const std::exception& e) {
125130
owner->log(ll_trace, "Socket loop exception: " + std::string(e.what()));
131+
stats.errors++;
126132
eh->on_error(fd, *eh, 0);
127133
}
128134

src/dpp/socketengines/kqueue.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct DPP_EXPORT socket_engine_kqueue : public socket_engine_base {
4848
if (kqueue_handle == -1) {
4949
throw dpp::connection_exception("Failed to initialise kqueue()");
5050
}
51+
stats.engine_type = "kqueue";
5152
}
5253

5354
~socket_engine_kqueue() override {
@@ -78,6 +79,7 @@ struct DPP_EXPORT socket_engine_kqueue : public socket_engine_base {
7879
if (kev.flags & EV_EOF || kev.flags & EV_ERROR) {
7980
if (eh->on_error) {
8081
eh->on_error(kev.ident, *eh, kev.fflags);
82+
stats.errors++;
8183
}
8284
continue;
8385
}
@@ -86,15 +88,18 @@ struct DPP_EXPORT socket_engine_kqueue : public socket_engine_base {
8688
eh->flags &= ~bits_to_clr;
8789
if (eh->on_write) {
8890
eh->on_write(kev.ident, *eh);
91+
stats.writes++;
8992
}
9093
}
9194
else if (filter == EVFILT_READ) {
9295
if (eh->on_read) {
9396
eh->on_read(kev.ident, *eh);
97+
stats.reads++;
9498
}
9599
}
96100

97101
} catch (const std::exception& e) {
102+
stats.errors++;
98103
owner->log(ll_trace, "Socket loop exception: " + std::string(e.what()));
99104
eh->on_error(kev.ident, *eh, 0);
100105
}

src/dpp/socketengines/poll.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ struct DPP_EXPORT socket_engine_poll : public socket_engine_base {
100100

101101
if ((revents & POLLHUP) != 0) {
102102
eh->on_error(fd, *eh, 0);
103+
stats.errors++;
103104
continue;
104105
}
105106

@@ -109,21 +110,25 @@ struct DPP_EXPORT socket_engine_poll : public socket_engine_base {
109110
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *) &errcode, &codesize) < 0) {
110111
errcode = errno;
111112
}
113+
stats.errors++;
112114
eh->on_error(fd, *eh, errcode);
113115
continue;
114116
}
115117

116118
if ((revents & POLLIN) != 0) {
119+
stats.reads++;
117120
eh->on_read(fd, *eh);
118121
}
119122

120123
if ((revents & POLLOUT) != 0) {
124+
stats.writes++;
121125
eh->flags &= ~WANT_WRITE;
122126
update_socket(*eh);
123127
eh->on_write(fd, *eh);
124128
}
125129

126130
} catch (const std::exception &e) {
131+
stats.errors++;
127132
eh->on_error(fd, *eh, 0);
128133
}
129134

@@ -181,7 +186,9 @@ struct DPP_EXPORT socket_engine_poll : public socket_engine_base {
181186
return r;
182187
}
183188

184-
explicit socket_engine_poll(cluster* creator) : socket_engine_base(creator) { };
189+
explicit socket_engine_poll(cluster* creator) : socket_engine_base(creator) {
190+
stats.engine_type = "poll";
191+
};
185192

186193
protected:
187194

src/dpp/wsclient.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -132,22 +132,7 @@ void websocket_client::write(const std::string_view data, ws_opcode _opcode)
132132
ssl_client::socket_write(data);
133133
}
134134

135-
bool should_append_want_write = false;
136-
socket_events *new_se = nullptr;
137-
{
138-
std::lock_guard lk(owner->socketengine->fds_mutex);
139-
auto i = owner->socketengine->fds.find(sfd);
140-
141-
should_append_want_write = i != owner->socketengine->fds.end() && (i->second->flags & WANT_WRITE) != WANT_WRITE;
142-
if (should_append_want_write) {
143-
new_se = i->second.get();
144-
new_se->flags |= WANT_WRITE;
145-
}
146-
}
147-
148-
if (should_append_want_write) {
149-
owner->socketengine->update_socket(*new_se);
150-
}
135+
owner->socketengine->inplace_modify_fd(sfd, WANT_WRITE);
151136
}
152137

153138
bool websocket_client::handle_buffer(std::string& buffer)

0 commit comments

Comments
 (0)