Add ThreadInfo to process_info.fbs
Add `per_thread_info` argument for the aos Top constructor.
When enabled, this will cause Top to include cpu usage per
per thread for all processes it reports on.
The process_info.fbs file has been updated to include this new
optional field.
Change-Id: I394a2ccb09f714b0edf0249fdab4332742bf3d3e
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/util/top_test.cc b/aos/util/top_test.cc
index 6888457..ce9986f 100644
--- a/aos/util/top_test.cc
+++ b/aos/util/top_test.cc
@@ -7,6 +7,7 @@
#include <thread>
#include "gtest/gtest.h"
+#include <gmock/gmock.h>
#include "aos/events/shm_event_loop.h"
#include "aos/json_to_flatbuffer.h"
@@ -15,11 +16,18 @@
namespace aos::util::testing {
+void SetThreadName(const std::string &name) {
+ pthread_setname_np(pthread_self(), name.c_str());
+}
+
+constexpr std::string_view kTestCPUConsumer = "TestCPUConsumer";
+
class TopTest : public ::testing::Test {
protected:
TopTest()
: shm_dir_(aos::testing::TestTmpDir() + "/aos"),
cpu_consumer_([this]() {
+ SetThreadName(std::string(kTestCPUConsumer));
while (!stop_flag_.load()) {
}
}),
@@ -60,7 +68,8 @@
TEST_F(TopTest, QuerySingleProcess) {
const pid_t pid = getpid();
- Top top(&event_loop_);
+ Top top(&event_loop_, Top::TrackThreadsMode::kDisabled,
+ Top::TrackPerThreadInfoMode::kDisabled);
top.set_track_pids({pid});
event_loop_.AddTimer([this]() { event_loop_.Exit(); })
->Schedule(event_loop_.monotonic_now() + std::chrono::seconds(2));
@@ -80,6 +89,49 @@
// Sanity check memory usage.
ASSERT_LT(1000000, info.message().physical_memory());
ASSERT_GT(1000000000, info.message().physical_memory());
+
+ // Verify no per-thread information is included by default.
+ ASSERT_FALSE(info.message().has_threads());
+}
+
+TEST_F(TopTest, QuerySingleProcessWithThreads) {
+ const pid_t pid = getpid();
+ Top top(&event_loop_, Top::TrackThreadsMode::kDisabled,
+ Top::TrackPerThreadInfoMode::kEnabled);
+ top.set_track_pids({pid});
+ event_loop_.AddTimer([this]() { event_loop_.Exit(); })
+ ->Schedule(event_loop_.monotonic_now() + std::chrono::seconds(2));
+ event_loop_.Run();
+ flatbuffers::FlatBufferBuilder fbb;
+ fbb.ForceDefaults(true);
+ fbb.Finish(top.InfoForProcess(&fbb, pid));
+ aos::FlatbufferDetachedBuffer<ProcessInfo> info = fbb.Release();
+ ASSERT_EQ(pid, info.message().pid());
+ ASSERT_TRUE(info.message().has_name());
+ ASSERT_EQ("top_test", info.message().name()->string_view());
+ // Check that we did indeed consume ~1 CPU core (because we're multi-threaded,
+ // we could've consumed a bit more; and on systems where we are competing with
+ // other processes for CPU time, we may not get a full 100% load).
+ ASSERT_LT(0.5, info.message().cpu_usage());
+ ASSERT_GT(1.1, info.message().cpu_usage());
+ // Sanity check memory usage.
+ ASSERT_LT(1000000, info.message().physical_memory());
+ ASSERT_GT(1000000000, info.message().physical_memory());
+
+ // Validate that we have some per-thread information.
+ ASSERT_TRUE(info.message().has_threads());
+ ASSERT_GT(info.message().threads()->size(), 0);
+ std::set<std::string_view> thread_names;
+ double thread_cpu_usage = 0.0;
+ for (const ThreadInfo *thread_info : *info.message().threads()) {
+ thread_names.insert(thread_info->name()->str());
+ thread_cpu_usage += thread_info->cpu_usage();
+ ASSERT_TRUE(thread_info->has_state());
+ }
+ // Validate that at least one thread was named correctly.
+ ASSERT_THAT(thread_names, ::testing::Contains(kTestCPUConsumer));
+ // Validate that we consumed at some cpu one a thread.
+ ASSERT_GT(thread_cpu_usage, 0);
}
TEST_F(TopTest, TopProcesses) {
@@ -108,7 +160,8 @@
}
}
- Top top(&event_loop_);
+ Top top(&event_loop_, Top::TrackThreadsMode::kDisabled,
+ Top::TrackPerThreadInfoMode::kDisabled);
top.set_track_top_processes(true);
event_loop_.AddTimer([this]() { event_loop_.Exit(); })
->Schedule(event_loop_.monotonic_now() + std::chrono::seconds(2));
@@ -152,7 +205,8 @@
TEST_F(TopTest, AllTopProcesses) {
constexpr int kNProcesses = 1000000;
- Top top(&event_loop_);
+ Top top(&event_loop_, Top::TrackThreadsMode::kDisabled,
+ Top::TrackPerThreadInfoMode::kDisabled);
top.set_track_top_processes(true);
event_loop_.AddTimer([this]() { event_loop_.Exit(); })
->Schedule(event_loop_.monotonic_now() + std::chrono::seconds(2));