[adb] Optimize fdevent machinery

- Use one fewer heap allocation per fdevent object
- Lazy-init the fdevent context

Bug: 151239696
Test: various adb commands on Win/Linux

Change-Id: Ic7de207b30495e618f187e097c0276ad42c34005
Merged-In: Ic7de207b30495e618f187e097c0276ad42c34005
This commit is contained in:
Yurii Zubrytskyi 2020-03-18 22:29:10 -07:00
parent 2488c21d8b
commit 4eb910e82e
5 changed files with 51 additions and 51 deletions

View file

@ -63,7 +63,10 @@ fdevent* fdevent_context::Create(unique_fd fd, std::variant<fd_func, fd_func2> f
int fd_num = fd.get();
fdevent* fde = new fdevent();
auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fdevent{});
CHECK(inserted);
fdevent* fde = &it->second;
fde->id = fdevent_id_++;
fde->state = 0;
fde->fd = std::move(fd);
@ -76,10 +79,6 @@ fdevent* fdevent_context::Create(unique_fd fd, std::variant<fd_func, fd_func2> f
LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
}
auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fde);
CHECK(inserted);
UNUSED(it);
this->Register(fde);
return fde;
}
@ -92,12 +91,12 @@ unique_fd fdevent_context::Destroy(fdevent* fde) {
this->Unregister(fde);
auto erased = this->installed_fdevents_.erase(fde->fd.get());
unique_fd fd = std::move(fde->fd);
auto erased = this->installed_fdevents_.erase(fd.get());
CHECK_EQ(1UL, erased);
unique_fd result = std::move(fde->fd);
delete fde;
return result;
return fd;
}
void fdevent_context::Add(fdevent* fde, unsigned events) {
@ -123,9 +122,9 @@ std::optional<std::chrono::milliseconds> fdevent_context::CalculatePollDuration(
for (const auto& [fd, fde] : this->installed_fdevents_) {
UNUSED(fd);
auto timeout_opt = fde->timeout;
auto timeout_opt = fde.timeout;
if (timeout_opt) {
auto deadline = fde->last_active + *timeout_opt;
auto deadline = fde.last_active + *timeout_opt;
auto time_left = duration_cast<std::chrono::milliseconds>(deadline - now);
if (time_left < 0ms) {
time_left = 0ms;
@ -194,11 +193,13 @@ static std::unique_ptr<fdevent_context> fdevent_create_context() {
#endif
}
static auto& g_ambient_fdevent_context =
*new std::unique_ptr<fdevent_context>(fdevent_create_context());
static auto& g_ambient_fdevent_context() {
static auto context = fdevent_create_context().release();
return context;
}
static fdevent_context* fdevent_get_ambient() {
return g_ambient_fdevent_context.get();
return g_ambient_fdevent_context();
}
fdevent* fdevent_create(int fd, fd_func func, void* arg) {
@ -256,5 +257,6 @@ size_t fdevent_installed_count() {
}
void fdevent_reset() {
g_ambient_fdevent_context = fdevent_create_context();
auto old = std::exchange(g_ambient_fdevent_context(), fdevent_create_context().release());
delete old;
}

View file

@ -52,6 +52,20 @@ struct fdevent_event {
unsigned events;
};
struct fdevent final {
uint64_t id;
unique_fd fd;
int force_eof = 0;
uint16_t state = 0;
std::optional<std::chrono::milliseconds> timeout;
std::chrono::steady_clock::time_point last_active;
std::variant<fd_func, fd_func2> func;
void* arg = nullptr;
};
struct fdevent_context {
public:
virtual ~fdevent_context() = default;
@ -113,7 +127,7 @@ struct fdevent_context {
std::atomic<bool> terminate_loop_ = false;
protected:
std::unordered_map<int, fdevent*> installed_fdevents_;
std::unordered_map<int, fdevent> installed_fdevents_;
private:
uint64_t fdevent_id_ = 0;
@ -121,20 +135,6 @@ struct fdevent_context {
std::deque<std::function<void()>> run_queue_ GUARDED_BY(run_queue_mutex_);
};
struct fdevent {
uint64_t id;
unique_fd fd;
int force_eof = 0;
uint16_t state = 0;
std::optional<std::chrono::milliseconds> timeout;
std::chrono::steady_clock::time_point last_active;
std::variant<fd_func, fd_func2> func;
void* arg = nullptr;
};
// Backwards compatibility shims that forward to the global fdevent_context.
fdevent* fdevent_create(int fd, fd_func func, void* arg);
fdevent* fdevent_create(int fd, fd_func2 func, void* arg);

View file

@ -155,15 +155,15 @@ void fdevent_context_epoll::Loop() {
event_map[fde] = events;
}
for (const auto& [fd, fde] : installed_fdevents_) {
for (auto& [fd, fde] : installed_fdevents_) {
unsigned events = 0;
if (auto it = event_map.find(fde); it != event_map.end()) {
if (auto it = event_map.find(&fde); it != event_map.end()) {
events = it->second;
}
if (events == 0) {
if (fde->timeout) {
auto deadline = fde->last_active + *fde->timeout;
if (fde.timeout) {
auto deadline = fde.last_active + *fde.timeout;
if (deadline < post_poll) {
events |= FDE_TIMEOUT;
}
@ -171,13 +171,13 @@ void fdevent_context_epoll::Loop() {
}
if (events != 0) {
LOG(DEBUG) << dump_fde(fde) << " got events " << std::hex << std::showbase
LOG(DEBUG) << dump_fde(&fde) << " got events " << std::hex << std::showbase
<< events;
fde_events.push_back({fde, events});
fde->last_active = post_poll;
fde_events.push_back({&fde, events});
fde.last_active = post_poll;
}
}
this->HandleEvents(std::move(fde_events));
this->HandleEvents(fde_events);
fde_events.clear();
}

View file

@ -47,12 +47,7 @@ struct fdevent_context_epoll final : public fdevent_context {
protected:
virtual void Interrupt() final;
public:
// All operations to fdevent should happen only in the main thread.
// That's why we don't need a lock for fdevent.
std::unordered_map<int, fdevent*> epoll_node_map_;
std::list<fdevent*> pending_list_;
private:
unique_fd epoll_fd_;
unique_fd interrupt_fd_;
fdevent* interrupt_fde_ = nullptr;

View file

@ -103,24 +103,27 @@ static std::string dump_pollfds(const std::vector<adb_pollfd>& pollfds) {
void fdevent_context_poll::Loop() {
main_thread_id_ = android::base::GetThreadId();
std::vector<adb_pollfd> pollfds;
std::vector<fdevent_event> poll_events;
while (true) {
if (terminate_loop_) {
break;
}
D("--- --- waiting for events");
std::vector<adb_pollfd> pollfds;
pollfds.clear();
for (const auto& [fd, fde] : this->installed_fdevents_) {
adb_pollfd pfd;
pfd.fd = fd;
pfd.events = 0;
if (fde->state & FDE_READ) {
if (fde.state & FDE_READ) {
pfd.events |= POLLIN;
}
if (fde->state & FDE_WRITE) {
if (fde.state & FDE_WRITE) {
pfd.events |= POLLOUT;
}
if (fde->state & FDE_ERROR) {
if (fde.state & FDE_ERROR) {
pfd.events |= POLLERR;
}
#if defined(__linux__)
@ -147,7 +150,6 @@ void fdevent_context_poll::Loop() {
}
auto post_poll = std::chrono::steady_clock::now();
std::vector<fdevent_event> poll_events;
for (const auto& pollfd : pollfds) {
unsigned events = 0;
@ -170,7 +172,7 @@ void fdevent_context_poll::Loop() {
auto it = this->installed_fdevents_.find(pollfd.fd);
CHECK(it != this->installed_fdevents_.end());
fdevent* fde = it->second;
fdevent* fde = &it->second;
if (events == 0) {
if (fde->timeout) {
@ -187,7 +189,8 @@ void fdevent_context_poll::Loop() {
fde->last_active = post_poll;
}
}
this->HandleEvents(std::move(poll_events));
this->HandleEvents(poll_events);
poll_events.clear();
}
main_thread_id_.reset();