From 5cd200831b67e2f96178a617a35b274e0e6be364 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 23 Nov 2014 19:28:07 +0200 Subject: [PATCH 1/3] memory: add allocation statistics collection --- core/memory.cc | 15 +++++++++++++++ core/memory.hh | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/core/memory.cc b/core/memory.cc index ed1bab28bb..809e514b8a 100644 --- a/core/memory.cc +++ b/core/memory.cc @@ -61,6 +61,9 @@ using pageidx = uint32_t; struct page; class page_list; +static uint64_t g_allocs; +static uint64_t g_frees; + namespace bi = boost::intrusive; class page_list_link { @@ -641,6 +644,7 @@ size_t object_size(void* ptr) { } void* allocate(size_t size) { + ++g_allocs; if (size <= sizeof(free_object)) { size = sizeof(free_object); } @@ -652,6 +656,7 @@ void* allocate(size_t size) { } void* allocate_aligned(size_t align, size_t size) { + ++g_allocs; size = std::max(size, align); if (size <= sizeof(free_object)) { size = sizeof(free_object); @@ -664,10 +669,12 @@ void* allocate_aligned(size_t align, size_t size) { } void free(void* obj) { + ++g_frees; cpu_mem.free(obj); } void free(void* obj, size_t size) { + ++g_frees; cpu_mem.free(obj, size); } @@ -705,6 +712,10 @@ void configure(std::vector m) { } } +statistics stats() { + return statistics{g_allocs, g_frees}; +} + } using namespace memory; @@ -916,6 +927,10 @@ void set_reclaim_hook(std::function)> hook) { void configure(std::vector m) { } +statistics stats() { + return statistics{0, 0}; +} + } #endif diff --git a/core/memory.hh b/core/memory.hh index 13a003355a..51dbd763f4 100644 --- a/core/memory.hh +++ b/core/memory.hh @@ -33,6 +33,23 @@ public: void set_reclaim_hook( std::function)> hook); +class statistics; +statistics stats(); + +class statistics { + uint64_t _objects_allocated; + uint64_t _objects_freed; +private: + statistics(uint64_t allocs, uint64_t frees) + : _objects_allocated(allocs), _objects_freed(frees) {} +public: + uint64_t object_allocated() const { return _objects_allocated; } + uint64_t object_freed() const { return _objects_freed; } + size_t allocated_objects() const { return object_allocated() - object_freed(); } + friend statistics stats(); +}; + + } #endif /* MEMORY_HH_ */ From a7f14fa13e8f38c9bbf6a90fb346ba0b1117fee2 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 23 Nov 2014 19:28:26 +0200 Subject: [PATCH 2/3] core: export memory statistics via collectd --- core/reactor.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/reactor.cc b/core/reactor.cc index 3d1f463c01..6a465349bf 100644 --- a/core/reactor.cc +++ b/core/reactor.cc @@ -406,6 +406,27 @@ int reactor::run() { , scollectd::make_typed(scollectd::data_type::GAUGE , std::bind(&decltype(_timers)::size, &_timers)) ), + scollectd::add_polled_metric( + scollectd::type_instance_id("memory", + scollectd::per_cpu_plugin_instance, + "total_operations", "malloc"), + scollectd::make_typed(scollectd::data_type::DERIVE, + [] { return memory::stats().object_allocated(); }) + ), + scollectd::add_polled_metric( + scollectd::type_instance_id("memory", + scollectd::per_cpu_plugin_instance, + "total_operations", "free"), + scollectd::make_typed(scollectd::data_type::DERIVE, + [] { return memory::stats().object_freed(); }) + ), + scollectd::add_polled_metric( + scollectd::type_instance_id("memory", + scollectd::per_cpu_plugin_instance, + "objects", "malloc"), + scollectd::make_typed(scollectd::data_type::GAUGE, + [] { return memory::stats().allocated_objects(); }) + ), }; #ifndef HAVE_OSV From 0903e36179b6ce528c2432c595ef1633aa9f5b03 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 23 Nov 2014 19:28:54 +0200 Subject: [PATCH 3/3] httpd: export statistics via collectd --- apps/httpd/httpd.cc | 57 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/apps/httpd/httpd.cc b/apps/httpd/httpd.cc index a58b3f6733..e6ee94ef95 100644 --- a/apps/httpd/httpd.cc +++ b/apps/httpd/httpd.cc @@ -10,6 +10,7 @@ #include "core/smp.hh" #include "core/queue.hh" #include "core/future-util.hh" +#include "core/scollectd.hh" #include #include #include @@ -17,9 +18,23 @@ #include #include #include +#include + +class http_server; +class http_stats; + +class http_stats { + std::vector _regs; +public: + http_stats(http_server& server); +}; class http_server { std::vector _listeners; + http_stats _stats{*this}; + uint64_t _total_connections = 0; + uint64_t _current_connections = 0; + uint64_t _requests_served = 0; public: future<> listen(ipv4_addr addr) { listen_options lo; @@ -49,6 +64,7 @@ public: }); } class connection { + http_server& _server; connected_socket _fd; input_stream _read_buf; output_stream _write_buf; @@ -67,8 +83,14 @@ public: queue> _responses { 10 }; public: connection(http_server& server, connected_socket&& fd, socket_address addr) - : _fd(std::move(fd)), _read_buf(_fd.input()) - , _write_buf(_fd.output()) {} + : _server(server), _fd(std::move(fd)), _read_buf(_fd.input()) + , _write_buf(_fd.output()) { + ++_server._total_connections; + ++_server._current_connections; + } + ~connection() { + --_server._current_connections; + } future<> process() { // Launch read and write "threads" simultaneously: return when_all(read(), respond()).then([] (std::tuple, future<>> joined) { @@ -82,6 +104,7 @@ public: if (_parser.eof()) { return _responses.push_eventually({}); } + ++_server._requests_served; _req = _parser.get_parsed_request(); return _responses.not_full().then([this] { bool close = generate_response(std::move(_req)); @@ -173,8 +196,38 @@ public: return _write_buf.write(_resp->_body.begin(), _resp->_body.size()); } }; + uint64_t total_connections() const { + return _total_connections; + } + uint64_t current_connections() const { + return _current_connections; + } + uint64_t requests_served() const { + return _requests_served; + } }; +http_stats::http_stats(http_server& server) + : _regs{ + scollectd::add_polled_metric( + scollectd::type_instance_id("httpd", scollectd::per_cpu_plugin_instance, + "connections", "http-connections"), + scollectd::make_typed(scollectd::data_type::DERIVE, + [&server] { return server.total_connections(); })), + scollectd::add_polled_metric( + scollectd::type_instance_id("httpd", scollectd::per_cpu_plugin_instance, + "current_connections", "current"), + scollectd::make_typed(scollectd::data_type::GAUGE, + [&server] { return server.current_connections(); })), + scollectd::add_polled_metric( + scollectd::type_instance_id("httpd", scollectd::per_cpu_plugin_instance, + "http_requests", "served"), + scollectd::make_typed(scollectd::data_type::DERIVE, + [&server] { return server.requests_served(); })), + } { +} + + int main(int ac, char** av) { app_template app; app.add_options()