Merge "Add a timeout to aos_dump"
diff --git a/aos/network/timestamp_filter.cc b/aos/network/timestamp_filter.cc
index 8d84adf..d5f1139 100644
--- a/aos/network/timestamp_filter.cc
+++ b/aos/network/timestamp_filter.cc
@@ -1207,7 +1207,7 @@
bool removed = false;
while (true) {
CHECK_LT(pop_filter_, filters_.size());
- BootFilter *boot_filter = &filters_[pop_filter_];
+ BootFilter *boot_filter = filters_[pop_filter_].get();
CHECK(boot_filter != nullptr);
size_t timestamps_size = 0;
while ((timestamps_size = boot_filter->filter.timestamps_size()) > 2) {
@@ -1229,13 +1229,13 @@
// There is 1 more filter, see if there is enough data in it to switch
// over to it.
- if (filters_[pop_filter_ + 1].filter.timestamps_size() < 2u) {
+ if (filters_[pop_filter_ + 1]->filter.timestamps_size() < 2u) {
return removed;
}
if (time <
BootTimestamp{.boot = static_cast<size_t>(boot_filter->boot.first),
.time = std::get<0>(
- filters_[pop_filter_ + 1].filter.timestamp(1))}) {
+ filters_[pop_filter_ + 1]->filter.timestamp(1))}) {
return removed;
}
}
diff --git a/aos/network/timestamp_filter.h b/aos/network/timestamp_filter.h
index 2ed98da..88031a1 100644
--- a/aos/network/timestamp_filter.h
+++ b/aos/network/timestamp_filter.h
@@ -301,8 +301,8 @@
size_t timestamps_size() const {
size_t result = 0u;
- for (const BootFilter &filter : filters_) {
- result += filter.filter.timestamps_size();
+ for (const std::unique_ptr<BootFilter> &filter : filters_) {
+ result += filter->filter.timestamps_size();
}
return result;
}
@@ -320,10 +320,10 @@
// For testing only:
void Debug() const {
- for (const BootFilter &filter : filters_) {
- LOG(INFO) << NodeNames() << " boota: " << filter.boot.first << ", "
- << filter.boot.second;
- filter.filter.Debug();
+ for (const std::unique_ptr<BootFilter> &filter : filters_) {
+ LOG(INFO) << NodeNames() << " boota: " << filter->boot.first << ", "
+ << filter->boot.second;
+ filter->filter.Debug();
}
}
@@ -340,18 +340,18 @@
// Returns true if there is a full line which hasn't been observed.
bool has_unobserved_line() const {
- return filters_.back().filter.has_unobserved_line();
+ return filters_.back()->filter.has_unobserved_line();
}
// Returns the time of the second point in the unobserved line, or min_time if
// there is no line.
logger::BootTimestamp unobserved_line_end() const {
- auto &f = filters_.back();
+ auto &f = *filters_.back();
return {static_cast<size_t>(f.boot.first), f.filter.unobserved_line_end()};
}
// Returns the time of the second point in the unobserved line on the remote
// node, or min_time if there is no line.
logger::BootTimestamp unobserved_line_remote_end() const {
- auto &f = filters_.back();
+ auto &f = *filters_.back();
return {static_cast<size_t>(f.boot.second),
f.filter.unobserved_line_remote_end()};
}
@@ -367,7 +367,7 @@
size_t current_filter = std::max(static_cast<ssize_t>(0), current_filter_);
while (true) {
- const BootFilter &filter = filters_[current_filter];
+ const BootFilter &filter = *filters_[current_filter];
std::optional<
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds>>
result = filter.filter.Observe();
@@ -400,7 +400,7 @@
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds>>
result =
current_filter_ < 0 ? std::nullopt
- : filters_[current_filter_].filter.Consume();
+ : filters_[current_filter_]->filter.Consume();
if (!result) {
if (static_cast<size_t>(current_filter_ + 1) == filters_.size()) {
return std::nullopt;
@@ -409,7 +409,7 @@
continue;
}
}
- BootFilter &filter = filters_[current_filter_];
+ BootFilter &filter = *filters_[current_filter_];
return std::make_tuple(
logger::BootTimestamp{static_cast<size_t>(filter.boot.first),
std::get<0>(*result)},
@@ -643,12 +643,12 @@
};
static bool FilterLessThanUpper(const std::pair<int, int> &l,
- const BootFilter &r) {
- return l < r.boot;
+ const std::unique_ptr<BootFilter> &r) {
+ return l < r->boot;
}
- static bool FilterLessThanLower(const BootFilter &l,
+ static bool FilterLessThanLower(const std::unique_ptr<BootFilter> &l,
const std::pair<int, int> &r) {
- return l.boot < r;
+ return l->boot < r;
}
protected:
@@ -656,21 +656,23 @@
auto it =
std::lower_bound(filters_.begin(), filters_.end(),
std::make_pair(boota, bootb), FilterLessThanLower);
- if (it != filters_.end() && it->boot == std::make_pair(boota, bootb)) {
- return &it->filter;
+ if (it != filters_.end() && (*it)->boot == std::make_pair(boota, bootb)) {
+ return &(*it)->filter;
}
if (!filters_.empty() && current_filter_ >= 0) {
CHECK_LT(static_cast<size_t>(current_filter_), filters_.size());
- CHECK_GE(boota, filters_[current_filter_].boot.first);
- CHECK_GE(bootb, filters_[current_filter_].boot.second) << NodeNames();
+ CHECK_GE(boota, filters_[current_filter_]->boot.first);
+ CHECK_GE(bootb, filters_[current_filter_]->boot.second) << NodeNames();
}
SingleFilter *result =
&filters_
.emplace(std::upper_bound(filters_.begin(), filters_.end(),
std::make_pair(boota, bootb),
FilterLessThanUpper),
- std::make_pair(boota, bootb), NodeNames())
+ std::make_unique<BootFilter>(std::make_pair(boota, bootb),
+ NodeNames()))
+ ->get()
->filter;
{
@@ -679,14 +681,14 @@
// means that both boots on both devices talked to both other boots.
int last_boota = -1;
int last_bootb = -1;
- for (const BootFilter &filter : filters_) {
- CHECK(filter.boot.first != last_boota ||
- filter.boot.second != last_bootb)
+ for (const std::unique_ptr<BootFilter> &filter : filters_) {
+ CHECK(filter->boot.first != last_boota ||
+ filter->boot.second != last_bootb)
<< ": Boots didn't increase.";
- CHECK_GE(filter.boot.first, last_boota);
- CHECK_GE(filter.boot.second, last_bootb);
- last_boota = filter.boot.first;
- last_bootb = filter.boot.second;
+ CHECK_GE(filter->boot.first, last_boota);
+ CHECK_GE(filter->boot.second, last_bootb);
+ last_boota = filter->boot.first;
+ last_bootb = filter->boot.second;
}
}
return result;
@@ -699,8 +701,8 @@
if (it == filters_.end()) {
return nullptr;
}
- if (it->boot == std::make_pair(boota, bootb)) {
- return &it->filter;
+ if (it->get()->boot == std::make_pair(boota, bootb)) {
+ return &it->get()->filter;
} else {
return nullptr;
}
@@ -714,7 +716,7 @@
}
private:
- std::vector<BootFilter> filters_;
+ std::vector<std::unique_ptr<BootFilter>> filters_;
ssize_t current_filter_ = -1;
diff --git a/aos/starter/starter_cmd.cc b/aos/starter/starter_cmd.cc
index b4d80d8..a076a9d 100644
--- a/aos/starter/starter_cmd.cc
+++ b/aos/starter/starter_cmd.cc
@@ -1,3 +1,4 @@
+#include <algorithm>
#include <chrono>
#include <functional>
#include <iostream>
@@ -25,6 +26,9 @@
"autocomplete script.");
DEFINE_string(_bash_autocomplete_word, "",
"Internal use: Current word being autocompleted");
+DEFINE_string(sort, "name",
+ "The name of the column to sort processes by. "
+ "Can be \"name\", \"state\", \"pid\", or \"uptime\".");
namespace {
@@ -85,6 +89,105 @@
"Uptime");
}
+std::vector<const aos::starter::ApplicationStatus *> SortApplications(
+ const aos::FlatbufferVector<aos::starter::Status> &status) {
+ std::vector<const aos::starter::ApplicationStatus *> sorted_statuses;
+ for (const aos::starter::ApplicationStatus *app_status :
+ *status.message().statuses()) {
+ sorted_statuses.push_back(app_status);
+ }
+ // If --sort flag not set, then return this unsorted vector as is.
+ if (FLAGS_sort.empty()) {
+ return sorted_statuses;
+ }
+
+ // Convert --sort flag to lowercase for testing below.
+ std::transform(FLAGS_sort.begin(), FLAGS_sort.end(), FLAGS_sort.begin(),
+ tolower);
+
+ // This function is called once for each node being reported upon, so there is
+ // no need to sort on node, it happens implicitly.
+
+ if (FLAGS_sort == "name") {
+ // Sort on name using std::string_view::operator< for lexicographic order.
+ std::sort(sorted_statuses.begin(), sorted_statuses.end(),
+ [](const aos::starter::ApplicationStatus *lhs,
+ const aos::starter::ApplicationStatus *rhs) {
+ return lhs->name()->string_view() < rhs->name()->string_view();
+ });
+ } else if (FLAGS_sort == "state") {
+ // Sort on state first, and then name for apps in same state.
+ // ApplicationStatus::state is an enum, so need to call EnumNameState()
+ // convenience wrapper to convert enum to char*, and then wrap in
+ // std::string_view for lexicographic ordering.
+ std::sort(sorted_statuses.begin(), sorted_statuses.end(),
+ [](const aos::starter::ApplicationStatus *lhs,
+ const aos::starter::ApplicationStatus *rhs) {
+ return (lhs->state() != rhs->state())
+ ? (std::string_view(
+ aos::starter::EnumNameState(lhs->state())) <
+ std::string_view(
+ aos::starter::EnumNameState(rhs->state())))
+ : (lhs->name()->string_view() <
+ rhs->name()->string_view());
+ });
+ } else if (FLAGS_sort == "pid") {
+ // Sort on pid first, and then name for when both apps are not running.
+ // If the app state is STOPPED, then it will not have a pid, so need to test
+ // that first. If only one app is STOPPED, then return Boolean state to put
+ // running apps before stopped.
+ std::sort(sorted_statuses.begin(), sorted_statuses.end(),
+ [](const aos::starter::ApplicationStatus *lhs,
+ const aos::starter::ApplicationStatus *rhs) {
+ if (lhs->state() == aos::starter::State::STOPPED) {
+ if (rhs->state() == aos::starter::State::STOPPED) {
+ return lhs->name()->string_view() <
+ rhs->name()->string_view();
+ } else {
+ return false;
+ }
+ } else {
+ if (rhs->state() == aos::starter::State::STOPPED) {
+ return true;
+ } else {
+ return lhs->pid() < rhs->pid();
+ }
+ }
+ });
+ } else if (FLAGS_sort == "uptime") {
+ // Sort on last_start_time first, and then name for when both apps are not
+ // running, or have exact same start time. Only use last_start_time when app
+ // is not STOPPED. If only one app is STOPPED, then return Boolean state to
+ // put running apps before stopped.
+ std::sort(
+ sorted_statuses.begin(), sorted_statuses.end(),
+ [](const aos::starter::ApplicationStatus *lhs,
+ const aos::starter::ApplicationStatus *rhs) {
+ if (lhs->state() == aos::starter::State::STOPPED) {
+ if (rhs->state() == aos::starter::State::STOPPED) {
+ return lhs->name()->string_view() < rhs->name()->string_view();
+ } else {
+ return false;
+ }
+ } else {
+ if (rhs->state() == aos::starter::State::STOPPED) {
+ return true;
+ } else {
+ return (lhs->last_start_time() == rhs->last_start_time())
+ ? (lhs->name()->string_view() <
+ rhs->name()->string_view())
+ : (lhs->last_start_time() < rhs->last_start_time());
+ }
+ }
+ });
+ } else {
+ std::cerr << "Unknown sort criteria \"" << FLAGS_sort << "\"" << std::endl;
+ exit(1);
+ }
+
+ return sorted_statuses;
+}
+
void PrintApplicationStatus(const aos::starter::ApplicationStatus *app_status,
const aos::monotonic_clock::time_point &time,
const aos::Node *node) {
@@ -116,8 +219,9 @@
const aos::FlatbufferVector<aos::starter::Status> &status =
optional_status->second;
const aos::monotonic_clock::time_point time = optional_status->first;
+ const auto &sorted_statuses = SortApplications(status);
for (const aos::starter::ApplicationStatus *app_status :
- *status.message().statuses()) {
+ sorted_statuses) {
PrintApplicationStatus(app_status, time, node);
}
} else {