Skip to content

Commit

Permalink
chore: introduce Idle measurement function (#323)
Browse files Browse the repository at this point in the history
  • Loading branch information
romange authored Oct 18, 2024
1 parent e56aa30 commit fae0c40
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 5 deletions.
3 changes: 3 additions & 0 deletions util/fibers/epoll_proactor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,10 @@ void EpollProactor::MainLoop(detail::Scheduler* scheduler) {
}
}

uint64_t start_cycle = GetCPUCycleCount();
int epoll_res = EpollWait(epoll_fd_, &ev_batch, timeout);
IdleEnd(start_cycle);

if (epoll_res < 0) {
epoll_res = errno;
if (epoll_res == EINTR)
Expand Down
20 changes: 16 additions & 4 deletions util/fibers/proactor_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,6 @@ void SigAction(int signal, siginfo_t*, void*) {
}
}

inline uint64_t GetCPUCycleCount() {
return absl::base_internal::CycleClock::Now();
}

unsigned pause_amplifier = 50;
uint64_t cycles_per_10us = 1000000; // correctly defined inside ModuleInit.
std::once_flag module_init;
Expand Down Expand Up @@ -293,6 +289,21 @@ bool ProactorBase::RunL2Tasks(detail::Scheduler* scheduler) {
return result;
}

void ProactorBase::IdleEnd(uint64_t start) {
uint64_t end = GetCPUCycleCount();

// Assuming that cpu clock frequency is
uint64_t kMinCyclePeriod = cycles_per_10us * 500'000ULL;
cpu_idle_cycles_ += (end - start);

if (end > cpu_measure_cycle_start_ + kMinCyclePeriod) {
load_numerator_ = cpu_idle_cycles_;
load_denominator_ = end - cpu_measure_cycle_start_;
cpu_idle_cycles_ = 0;
cpu_measure_cycle_start_ = end;
}
}

void ProactorBase::Pause(unsigned count) {
auto pc = pause_amplifier;

Expand Down Expand Up @@ -328,6 +339,7 @@ void ProactorBase::ModuleInit() {
}

void ProactorDispatcher::Run(detail::Scheduler* sched) {
proactor_->cpu_measure_cycle_start_ = ProactorBase::GetCPUCycleCount();
proactor_->MainLoop(sched);
}

Expand Down
29 changes: 29 additions & 0 deletions util/fibers/proactor_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#include "util/fibers/fibers.h"
#include "util/fibers/synchronization.h"

#if !defined(__x86_64__) && !defined(__aarch64__)
#include <absl/base/internal/cycleclock.h>
#endif

namespace util {
class LinuxSocketBase;

Expand Down Expand Up @@ -204,6 +208,11 @@ class ProactorBase {
return stats_;
}

// Returns the idle ratio of the proactor thread. The number is between 0 and 1.
double IdleRatio() const {
return double(load_numerator_) / load_denominator_;
}

protected:
enum { WAIT_SECTION_STATE = 1UL << 31 };
static constexpr unsigned kMaxSpinLimit = 5;
Expand Down Expand Up @@ -244,6 +253,7 @@ class ProactorBase {
return absl::GetCurrentTimeNanos();
}


// Returns true if we should poll scheduler tasks that run periodically but not too often.
bool ShouldPollL2Tasks() const;

Expand All @@ -252,6 +262,22 @@ class ProactorBase {
// Returns true if there are fibers that became ready as a result.
bool RunL2Tasks(detail::Scheduler* scheduler);

static uint64_t GetCPUCycleCount() {
#if defined(__x86_64__)
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return static_cast<int64_t>((high << 32) | low);
#elif defined(__aarch64__)
int64_t tv;
asm volatile("mrs %0, cntvct_el0" : "=r"(tv));
return tv;
#else
return absl::base_internal::CycleClock::Now();
#endif
}

void IdleEnd(uint64_t start);

pthread_t thread_id_ = 0U;
int sys_thread_id_ = 0;
int32_t pool_index_ = -1;
Expand Down Expand Up @@ -310,6 +336,9 @@ class ProactorBase {
}

uint64_t last_level2_cycle_ = 0;

uint64_t cpu_measure_cycle_start_ = 0, cpu_idle_cycles_ = 0;
uint64_t load_numerator_ = 0, load_denominator_ = 1;
};

class ProactorDispatcher : public DispatchPolicy {
Expand Down
3 changes: 2 additions & 1 deletion util/fibers/uring_proactor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -825,8 +825,9 @@ void UringProactor::MainLoop(detail::Scheduler* scheduler) {
DCHECK(!scheduler->HasReady());

VPRO(2) << "wait_for_cqe " << stats_.loop_cnt;

uint64_t start_cycle = GetCPUCycleCount();
wait_for_cqe(&ring_, 1, ts_arg);
IdleEnd(start_cycle);
VPRO(2) << "Woke up after wait_for_cqe ";

++stats_.num_stalls;
Expand Down

0 comments on commit fae0c40

Please sign in to comment.