Skip to content

Commit

Permalink
FillCpuInfo fails when files under /proc are not retrievable
Browse files Browse the repository at this point in the history
sometimes. Including checks in base/cpuinfo.cc so that we
 return error and deal with error messages for all calls that
 open /proc files. If error occurs, we log a message and dont
 send UVE.The tasktriggers should return TRUE even if FillCpuInfo
 fails otherwise, the task will get recycled.
Closes-Bug:#1681594

Change-Id: I23f670aed1047b84f2aeba1268c92286399b93ae
  • Loading branch information
arvindvis committed Apr 18, 2017
1 parent b61eaa1 commit 57564be
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 60 deletions.
9 changes: 7 additions & 2 deletions src/analytics/main.cc
Expand Up @@ -62,8 +62,13 @@ bool CollectorVersion(string &version) {
bool CollectorCPULogger(const string & hostname) {

CpuLoadInfo cpu_load_info;
CpuLoadData::FillCpuInfo(cpu_load_info, false);

bool ret_val = CpuLoadData::FillCpuInfo(cpu_load_info, false);
if (!ret_val) {
//Error occured in call to FillCpuInfo, dont send the
//CpuLoadInfo
LOG(ERROR, "Not sending CPUInfo : Unable to access /proc files");
return true;
}
ModuleCpuState state;
state.set_name(hostname);

Expand Down
4 changes: 2 additions & 2 deletions src/analytics/test/options_test.cc
Expand Up @@ -90,7 +90,7 @@ TEST_F(OptionsTest, NoArguments) {
EXPECT_EQ(options_.disable_flow_collection(), false);
EXPECT_EQ(options_.disable_db_messages_writes(), false);
EXPECT_EQ(options_.enable_db_messages_keyword_writes(), false);
EXPECT_EQ(options_.disable_db_stats_writes(), false);
EXPECT_EQ(options_.disable_db_statistics_writes(), false);
EXPECT_EQ(options_.disable_all_db_writes(), false);
uint16_t protobuf_port(0);
EXPECT_FALSE(options_.collector_protobuf_port(&protobuf_port));
Expand Down Expand Up @@ -139,7 +139,7 @@ TEST_F(OptionsTest, DefaultConfFile) {
EXPECT_EQ(options_.disable_flow_collection(), false);
EXPECT_EQ(options_.disable_db_messages_writes(), false);
EXPECT_EQ(options_.enable_db_messages_keyword_writes(), false);
EXPECT_EQ(options_.disable_db_stats_writes(), false);
EXPECT_EQ(options_.disable_db_statistics_writes(), false);
EXPECT_EQ(options_.disable_all_db_writes(), false);
uint16_t protobuf_port(0);
EXPECT_FALSE(options_.collector_protobuf_port(&protobuf_port));
Expand Down
130 changes: 81 additions & 49 deletions src/base/cpuinfo.cc
Expand Up @@ -22,14 +22,15 @@

using namespace boost;

static void error_check(std::ifstream &file) {
assert(file.is_open());
assert(!file.fail());
assert(!file.bad());
static bool error_check(std::ifstream &file) {
if (!file.is_open() || file.fail() || file.bad()) {
return false;
}
return true;
}

static uint32_t NumCpus() {
static uint32_t count = 0;
static int NumCpus() {
static int count = 0;

if (count != 0) {
return count;
Expand All @@ -41,7 +42,9 @@ static uint32_t NumCpus() {
return count;
#else
std::ifstream file("/proc/cpuinfo");
error_check(file);
if (!error_check(file)) {
return -1;
}
std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
// Create a find_iterator
Expand All @@ -54,18 +57,22 @@ static uint32_t NumCpus() {
#endif
}

static void LoadAvg(CpuLoad &load) {
static bool LoadAvg(CpuLoad &load) {
double averages[3];
uint32_t num_cpus = NumCpus();
int num_cpus = NumCpus();
if (num_cpus < 0) {
return false;
}
getloadavg(averages, 3);
if (num_cpus > 0) {
load.one_min_avg = averages[0]/num_cpus;
load.five_min_avg = averages[1]/num_cpus;
load.fifteen_min_avg = averages[2]/num_cpus;
}
return true;
}

static void ProcessMemInfo(ProcessMemInfo &info) {
static bool ProcessMemInfo(ProcessMemInfo &info) {
#ifdef __APPLE__
struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
Expand All @@ -79,10 +86,12 @@ static void ProcessMemInfo(ProcessMemInfo &info) {
info.virt = t_info.virtual_size;
// XXX Peak virt not availabe, just fill in virt
info.peakvirt = t_info.virtual_size;
return;
return true;
#else
std::ifstream file("/proc/self/status");
error_check(file);
if (!error_check(file)) {
return false;
}
bool vmsize = false;
bool peak = false;
bool rss = false;
Expand All @@ -106,12 +115,15 @@ static void ProcessMemInfo(ProcessMemInfo &info) {
if (rss && vmsize && peak)
break;
}
return true;
#endif
}

static void SystemMemInfo(SystemMemInfo &info) {
static bool SystemMemInfo(SystemMemInfo &info) {
std::ifstream file("/proc/meminfo");
error_check(file);
if (!error_check(file)) {
return false;
}
std::string tmp;
// MemTotal: 132010576 kB
file >> tmp; file >> info.total; file >> tmp;
Expand All @@ -123,11 +135,12 @@ static void SystemMemInfo(SystemMemInfo &info) {
file >> tmp; file >> info.cached;
// Used = Total - Free
info.used = info.total - info.free;
return true;
}

static clock_t snapshot, prev_sys_cpu, prev_user_cpu;

static void ProcessCpuShare(double &percentage) {
static bool ProcessCpuShare(double &percentage) {
struct tms cpu_taken;
clock_t now;

Expand All @@ -140,23 +153,37 @@ static void ProcessCpuShare(double &percentage) {
(double)((cpu_taken.tms_stime - prev_sys_cpu) +
(cpu_taken.tms_utime - prev_user_cpu)) / (now - snapshot);
percentage *= 100;
percentage /= NumCpus();
int num_cpus = NumCpus();
if (num_cpus < 0) {
return false;
}
percentage /= num_cpus;
}
snapshot = now;
prev_sys_cpu = cpu_taken.tms_stime;
prev_user_cpu = cpu_taken.tms_utime;
return true;
}

void CpuLoadData::GetCpuLoadInfo(CpuInfo &info, bool system) {
bool CpuLoadData::GetCpuLoadInfo(CpuInfo &info, bool system) {
if (system) {
LoadAvg(info.load_avg);
SystemMemInfo(info.sys_mem_info);
if (!LoadAvg(info.load_avg)) {
return false;
}
if (!SystemMemInfo(info.sys_mem_info)) {
return false;
}
}

ProcessMemInfo(info.mem_info);
if (!ProcessMemInfo(info.mem_info)) {
return false;
}

ProcessCpuShare(info.process_cpu_share);
if (!ProcessCpuShare(info.process_cpu_share)) {
return false;
}
info.num_cpu = NumCpus();
return true;
}

void CpuLoadData::Init() {
Expand All @@ -166,41 +193,46 @@ void CpuLoadData::Init() {
prev_user_cpu = cpu_taken.tms_utime;
}

void CpuLoadData::FillCpuInfo(CpuLoadInfo &cpu_load_info, bool system) {
bool CpuLoadData::FillCpuInfo(CpuLoadInfo &cpu_load_info, bool system) {
CpuInfo info;
CpuLoadData::GetCpuLoadInfo(info, system);
cpu_load_info.set_num_cpu(info.num_cpu);
MemInfo mem_info;
mem_info.set_virt(info.mem_info.virt);
mem_info.set_peakvirt(info.mem_info.peakvirt);
mem_info.set_res(info.mem_info.res);
cpu_load_info.set_meminfo(mem_info);

cpu_load_info.set_cpu_share(info.process_cpu_share);

if (system) {
CpuLoadAvg load_avg;
load_avg.set_one_min_avg(info.load_avg.one_min_avg);
load_avg.set_five_min_avg(info.load_avg.five_min_avg);
load_avg.set_fifteen_min_avg(info.load_avg.fifteen_min_avg);
cpu_load_info.set_cpuload(load_avg);

SysMemInfo sys_mem_info;
sys_mem_info.set_total(info.sys_mem_info.total);
sys_mem_info.set_used(info.sys_mem_info.used);
sys_mem_info.set_free(info.sys_mem_info.free);
sys_mem_info.set_buffers(info.sys_mem_info.buffers);
sys_mem_info.set_cached(info.sys_mem_info.cached);
cpu_load_info.set_sys_mem_info(sys_mem_info);
if (!CpuLoadData::GetCpuLoadInfo(info, system)) {
// Error occured while getting the information
return false;
} else {
MemInfo mem_info;
mem_info.set_virt(info.mem_info.virt);
mem_info.set_peakvirt(info.mem_info.peakvirt);
mem_info.set_res(info.mem_info.res);
cpu_load_info.set_meminfo(mem_info);

cpu_load_info.set_cpu_share(info.process_cpu_share);

if (system) {
CpuLoadAvg load_avg;
load_avg.set_one_min_avg(info.load_avg.one_min_avg);
load_avg.set_five_min_avg(info.load_avg.five_min_avg);
load_avg.set_fifteen_min_avg(info.load_avg.fifteen_min_avg);
cpu_load_info.set_cpuload(load_avg);

SysMemInfo sys_mem_info;
sys_mem_info.set_total(info.sys_mem_info.total);
sys_mem_info.set_used(info.sys_mem_info.used);
sys_mem_info.set_free(info.sys_mem_info.free);
sys_mem_info.set_buffers(info.sys_mem_info.buffers);
sys_mem_info.set_cached(info.sys_mem_info.cached);
cpu_load_info.set_sys_mem_info(sys_mem_info);
}
}
return true;
}

void CpuLoadInfoReq::HandleRequest() const {
CpuLoadInfo cpu_load_info;
CpuLoadData::FillCpuInfo(cpu_load_info, true);

bool status = CpuLoadData::FillCpuInfo(cpu_load_info, true);
CpuLoadInfoResp *resp = new CpuLoadInfoResp;
resp->set_cpu_info(cpu_load_info);
if (status) {
resp->set_cpu_info(cpu_load_info);
}
resp->set_context(context());
resp->Response();
}
Expand Down
4 changes: 2 additions & 2 deletions src/base/cpuinfo.h
Expand Up @@ -43,8 +43,8 @@ struct CpuInfo {

class CpuLoadData {
public:
static void GetCpuLoadInfo(CpuInfo &info, bool system);
static void FillCpuInfo(CpuLoadInfo &info, bool system);
static bool GetCpuLoadInfo(CpuInfo &info, bool system);
static bool FillCpuInfo(CpuLoadInfo &info, bool system);
static void Init();
};

Expand Down
12 changes: 9 additions & 3 deletions src/control-node/main.cc
Expand Up @@ -192,9 +192,15 @@ static bool ControlNodeInfoLogger(BgpServer *server,
Timer *node_info_log_timer) {
// Send CPU usage Information.
CpuLoadInfo cpu_load_info;
CpuLoadData::FillCpuInfo(cpu_load_info, false);
SendCpuInfoStat<ControlCpuStateTrace, ControlCpuState>(server->localname(),
cpu_load_info);
bool ret_val = CpuLoadData::FillCpuInfo(cpu_load_info, false);
if (!ret_val) {
//Error occured in call to FillCpuInfo, dont send the
//CpuLoadInfo
LOG(ERROR, "Not sending CPUInfo : Unable to access /proc files");
} else {
SendCpuInfoStat<ControlCpuStateTrace, ControlCpuState>(
server->localname(), cpu_load_info);
}

static bool first = true;
static BgpRouterState state;
Expand Down
11 changes: 10 additions & 1 deletion src/query_engine/qed.cc
Expand Up @@ -59,7 +59,16 @@ bool QEInfoLogTimer() {
bool QEInfoLogger(const string &hostname) {

CpuLoadInfo cpu_load_info;
CpuLoadData::FillCpuInfo(cpu_load_info, false);
bool ret_val = CpuLoadData::FillCpuInfo(cpu_load_info, false);
if (!ret_val) {
//Error occured in call to FillCpuInfo, dont send the
//CpuLoadInfo
LOG(ERROR, "Not sending CPUInfo : Unable to access /proc files");
qe_info_log_timer->Cancel();
qe_info_log_timer->Start(60*1000, boost::bind(&QEInfoLogTimer),
NULL);
return true;
}

ModuleCpuState state;
state.set_name(hostname);
Expand Down
9 changes: 8 additions & 1 deletion src/vnsw/agent/uve/vrouter_uve_entry_base.cc
Expand Up @@ -744,7 +744,14 @@ bool VrouterUveEntryBase::SendVrouterMsg() {
if ((cpu_stats_count_ % 2) == 0) {
static bool cpu_first = true;
CpuLoadInfo cpu_load_info;
CpuLoadData::FillCpuInfo(cpu_load_info, true);
bool ret_val = CpuLoadData::FillCpuInfo(cpu_load_info, true);
if (!ret_val) {
//Error occured in call to FillCpuInfo, dont send the CpuLoadInfo
LOG(ERROR, "Not sending CPUInfo : Unable to access /proc files");
cpu_stats_count_ = 0;
return changed;
}

if (prev_stats_.get_cpu_info() != cpu_load_info || cpu_first) {
stats.set_cpu_info(cpu_load_info);
prev_stats_.set_cpu_info(cpu_load_info);
Expand Down

0 comments on commit 57564be

Please sign in to comment.