/* Copyright (C) 2014 InfiniDB, Inc. Copyright (C) 2016 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /*************************************************************************** * $Id: resourceMonitor.cpp 3072 2013-04-04 19:04:45Z rdempsey $ * * Author: Zhixuan Zhu ***************************************************************************/ #include #include #include #include #include #include #include #include "liboamcpp.h" using namespace std; using namespace oam; /** * constants define */ enum HOST_INFO { USER = 0, SYSTEM, NICE, IDLE }; const string FE_MOUNT_DIR = "/var/log/mariadb/columnstore/"; // FE mount dir const int MONITOR_FREQ = 15; // monitor frequency in sec const int LOG_FREQ = 900; // log frequency in sec const int DEBUG = false; /** * global variables */ static char cpu[5]; static unsigned int usage[LOG_FREQ / MONITOR_FREQ]; static int usageCount = 0; /** * @brief get cpu usage for cpuNo */ unsigned int* getUsage(char* cpuNo); /** * @brief get cpu usage diffence over 3 seconds */ unsigned int* diffUsage(); /** * @brief calculate overall cpu usage */ unsigned int calcCPUusage(unsigned int* times); /** * @brief log cpu usage to active log file */ void logCPUactive (unsigned int); /** * @brief log cpu peak and average to stat file */ void logCPUstat (); /***************************************************************************************** * @brief main function * * purpose: Get current CPU usage and return current state * *****************************************************************************************/ int main (int argc, char** argv) { unsigned int* times; unsigned int cpuUsage = 0; // set defaults unsigned int cpuCritical = 9000, cpuMajor = 8000, cpuMinor = 7000, cpuMinorClear = 6000; strcpy (cpu, "cpu"); // get specific CPU info times = diffUsage(); // no cpus available on the system if (times == NULL) { cout << "No cpus on the system" << endl; return 0; } cpuUsage = calcCPUusage(times); logCPUactive(cpuUsage); cout << "cpuUsage: " << cpuUsage << endl; // Get CPU usage water mark from server configuration and compare ServerConfig serverConfig; Oam oam; try { oam.getSystemConfig (serverConfig); cpuCritical = serverConfig.ServerCPUCriticalThreshold; cpuMajor = serverConfig.ServerCPUMajorThreshold; cpuMinor = serverConfig.ServerCPUMinorThreshold; cpuMinorClear = serverConfig.ServerCPUMinorClearThreshold; } catch (runtime_error e) { throw e; } cout << "critical water: " << serverConfig.ServerCPUCriticalThreshold << endl; if (cpuUsage >= cpuCritical) { cout << "return critical: " << CRITICAL << endl; return CRITICAL; } else if (cpuUsage >= cpuMajor) { cout << "return major: " << MAJOR << endl; return MAJOR; } else if (cpuUsage >= cpuMinor) { cout << "return Minor: " << MINOR << endl; return MINOR; } else if (cpuUsage >= cpuMinorClear) { cout << "return MinorClear: " << WARNING << endl; return WARNING; } else { cout << "return Below MinorClear: " << NO_SEVERITY << endl; return NO_SEVERITY; } } /***************************************************************************************** * @brief diffUsage * * purpose: Compare usage different for changes * *****************************************************************************************/ unsigned int* diffUsage() { static unsigned int times1[4]; unsigned int* times; int i; times = getUsage(cpu); if (times == NULL) return NULL; memcpy(times1, getUsage(cpu), sizeof(unsigned int) * 4); sleep(3); times = getUsage(cpu); for (i = 0; i < 4; i++) times1[i] = times[i] - times1[i]; return times1; } /***************************************************************************************** * @brief diffUsage * * purpose: Compare usage different for changes * *****************************************************************************************/ unsigned int* getUsage(char* cpuNo) { static unsigned int times[4]; char tmp[5]; char str[80]; FILE* file; file = fopen("/proc/stat", "r"); while (fgets(str, 80, file)) { // search for cpuNo if ((strstr (str, cpuNo) != NULL)) { sscanf(str, "%s %u %u %u %u", tmp, ×[0], ×[1], ×[2], ×[3]); fclose(file); return times; } } fclose(file); return NULL; } /***************************************************************************************** * @brief calcCPUusage * * purpose: Calculate CPU usage * *****************************************************************************************/ unsigned int calcCPUusage (unsigned int* times) { unsigned int total = 0; for (int i = 0; i < 4; i++) total += times[i]; double load = (double)times[IDLE] * 100.0 / (double)total; return (int)((100.0 - load)); } /***************************************************************************************** * @brief logCPUactive * * purpose: Log Peak and Average CPU usage * *****************************************************************************************/ void logCPUactive (unsigned int cpuUsage) { // determin the active log file name string usageLogFileName = FE_MOUNT_DIR; usageLogFileName = usageLogFileName + cpu + ".log"; if (DEBUG) cout << usageLogFileName << endl; fstream usageLogFile; usageLogFile.open (usageLogFileName.c_str(), ios::in | ios::out); if (usageLogFile.fail()) { ofstream file (usageLogFileName.c_str()); file.close(); usageLogFile.open(usageLogFileName.c_str(), ios::in | ios::out); if (!usageLogFile) cout << "--error" << endl; } // get the counter usageLogFile.seekg(0, ios::beg); usageLogFile.read (reinterpret_cast(&usageCount), sizeof (int)); if (usageLogFile.eof()) usageLogFile.clear(); // new iteration if (usageCount == 0) { usageLogFile.seekp(0, ios::beg); usageLogFile.write (reinterpret_cast(&usageCount), sizeof (int)); } usageCount ++; // append new usage data to the end usageLogFile.seekp (0, ios::end); usageLogFile.write (reinterpret_cast(&cpuUsage), sizeof (int)); if (DEBUG) cout << "usage: " << usageCount << endl; // calculate peak and average if it's time to log usage data if (usageCount >= LOG_FREQ / MONITOR_FREQ) { usageLogFile.seekg (4, ios::beg); usageLogFile.read ((char*)usage, sizeof(unsigned int) * LOG_FREQ / MONITOR_FREQ); if (usageLogFile.eof()) usageLogFile.clear(); if (DEBUG) { for (int i = 0; i < usageCount; i++) { cout << usage [i] << endl; } } logCPUstat(); // delete the file usageLogFile.close(); unlink (usageLogFileName.c_str()); } // else, update usageCount else { usageLogFile.seekp(0, ios::beg); usageLogFile.write (reinterpret_cast(&usageCount), sizeof (int)); usageLogFile.close(); } } /***************************************************************************************** * @brief logCPUstat * * purpose: Log CPU stat using system API * *****************************************************************************************/ void logCPUstat () { unsigned int max = 0; unsigned int sum = 0; float average = 0.0; for (int i = 0; i < usageCount; i++) { if (usage[i] > max) max = usage[i]; sum += usage[i]; } average = sum / usageCount; // Call system log api to store stats. // for now, write on local for testing purpose. string statFileName = FE_MOUNT_DIR; statFileName = statFileName + cpu + "stat.log"; ofstream file (statFileName.c_str(), ios::app); file << max << " " << average << endl; file.close(); }