1*1285115cSWilliam A. Kennington III // Copyright 2021 Google LLC 2*1285115cSWilliam A. Kennington III // 3*1285115cSWilliam A. Kennington III // Licensed under the Apache License, Version 2.0 (the "License"); 4*1285115cSWilliam A. Kennington III // you may not use this file except in compliance with the License. 5*1285115cSWilliam A. Kennington III // You may obtain a copy of the License at 6*1285115cSWilliam A. Kennington III // 7*1285115cSWilliam A. Kennington III // http://www.apache.org/licenses/LICENSE-2.0 8*1285115cSWilliam A. Kennington III // 9*1285115cSWilliam A. Kennington III // Unless required by applicable law or agreed to in writing, software 10*1285115cSWilliam A. Kennington III // distributed under the License is distributed on an "AS IS" BASIS, 11*1285115cSWilliam A. Kennington III // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1285115cSWilliam A. Kennington III // See the License for the specific language governing permissions and 13*1285115cSWilliam A. Kennington III // limitations under the License. 14*1285115cSWilliam A. Kennington III 15*1285115cSWilliam A. Kennington III #include "util.hpp" 16*1285115cSWilliam A. Kennington III 17*1285115cSWilliam A. Kennington III #include <unistd.h> 18*1285115cSWilliam A. Kennington III 19*1285115cSWilliam A. Kennington III #include <phosphor-logging/log.hpp> 20*1285115cSWilliam A. Kennington III 21*1285115cSWilliam A. Kennington III #include <cmath> 22*1285115cSWilliam A. Kennington III #include <cstdlib> 23*1285115cSWilliam A. Kennington III #include <fstream> 24*1285115cSWilliam A. Kennington III #include <sstream> 25*1285115cSWilliam A. Kennington III #include <string> 26*1285115cSWilliam A. Kennington III #include <string_view> 27*1285115cSWilliam A. Kennington III 28*1285115cSWilliam A. Kennington III namespace metric_blob 29*1285115cSWilliam A. Kennington III { 30*1285115cSWilliam A. Kennington III 31*1285115cSWilliam A. Kennington III using phosphor::logging::log; 32*1285115cSWilliam A. Kennington III using level = phosphor::logging::level; 33*1285115cSWilliam A. Kennington III 34*1285115cSWilliam A. Kennington III char controlCharsToSpace(char c) 35*1285115cSWilliam A. Kennington III { 36*1285115cSWilliam A. Kennington III if (c < 32) 37*1285115cSWilliam A. Kennington III { 38*1285115cSWilliam A. Kennington III c = ' '; 39*1285115cSWilliam A. Kennington III } 40*1285115cSWilliam A. Kennington III return c; 41*1285115cSWilliam A. Kennington III } 42*1285115cSWilliam A. Kennington III 43*1285115cSWilliam A. Kennington III long getTicksPerSec() 44*1285115cSWilliam A. Kennington III { 45*1285115cSWilliam A. Kennington III return sysconf(_SC_CLK_TCK); 46*1285115cSWilliam A. Kennington III } 47*1285115cSWilliam A. Kennington III 48*1285115cSWilliam A. Kennington III std::string readFileIntoString(const std::string_view fileName) 49*1285115cSWilliam A. Kennington III { 50*1285115cSWilliam A. Kennington III std::stringstream ss; 51*1285115cSWilliam A. Kennington III std::ifstream ifs(fileName.data()); 52*1285115cSWilliam A. Kennington III while (ifs.good()) 53*1285115cSWilliam A. Kennington III { 54*1285115cSWilliam A. Kennington III std::string line; 55*1285115cSWilliam A. Kennington III std::getline(ifs, line); 56*1285115cSWilliam A. Kennington III ss << line; 57*1285115cSWilliam A. Kennington III if (ifs.good()) 58*1285115cSWilliam A. Kennington III ss << std::endl; 59*1285115cSWilliam A. Kennington III } 60*1285115cSWilliam A. Kennington III return ss.str(); 61*1285115cSWilliam A. Kennington III } 62*1285115cSWilliam A. Kennington III 63*1285115cSWilliam A. Kennington III bool isNumericPath(const std::string_view path, int& value) 64*1285115cSWilliam A. Kennington III { 65*1285115cSWilliam A. Kennington III size_t p = path.rfind('/'); 66*1285115cSWilliam A. Kennington III if (p == std::string::npos) 67*1285115cSWilliam A. Kennington III { 68*1285115cSWilliam A. Kennington III return false; 69*1285115cSWilliam A. Kennington III } 70*1285115cSWilliam A. Kennington III int id = 0; 71*1285115cSWilliam A. Kennington III for (size_t i = p + 1; i < path.size(); ++i) 72*1285115cSWilliam A. Kennington III { 73*1285115cSWilliam A. Kennington III const char ch = path[i]; 74*1285115cSWilliam A. Kennington III if (ch < '0' || ch > '9') 75*1285115cSWilliam A. Kennington III return false; 76*1285115cSWilliam A. Kennington III else 77*1285115cSWilliam A. Kennington III { 78*1285115cSWilliam A. Kennington III id = id * 10 + (ch - '0'); 79*1285115cSWilliam A. Kennington III } 80*1285115cSWilliam A. Kennington III } 81*1285115cSWilliam A. Kennington III value = id; 82*1285115cSWilliam A. Kennington III return true; 83*1285115cSWilliam A. Kennington III } 84*1285115cSWilliam A. Kennington III 85*1285115cSWilliam A. Kennington III // Trims all control characters at the end of a string. 86*1285115cSWilliam A. Kennington III std::string trimStringRight(std::string_view s) 87*1285115cSWilliam A. Kennington III { 88*1285115cSWilliam A. Kennington III std::string ret(s.data()); 89*1285115cSWilliam A. Kennington III while (!ret.empty()) 90*1285115cSWilliam A. Kennington III { 91*1285115cSWilliam A. Kennington III if (ret.back() <= 32) 92*1285115cSWilliam A. Kennington III ret.pop_back(); 93*1285115cSWilliam A. Kennington III else 94*1285115cSWilliam A. Kennington III break; 95*1285115cSWilliam A. Kennington III } 96*1285115cSWilliam A. Kennington III return ret; 97*1285115cSWilliam A. Kennington III } 98*1285115cSWilliam A. Kennington III 99*1285115cSWilliam A. Kennington III std::string getCmdLine(const int pid) 100*1285115cSWilliam A. Kennington III { 101*1285115cSWilliam A. Kennington III const std::string& cmdlinePath = 102*1285115cSWilliam A. Kennington III "/proc/" + std::to_string(pid) + "/cmdline"; 103*1285115cSWilliam A. Kennington III 104*1285115cSWilliam A. Kennington III std::string cmdline = readFileIntoString(cmdlinePath); 105*1285115cSWilliam A. Kennington III for (size_t i = 0; i < cmdline.size(); ++i) 106*1285115cSWilliam A. Kennington III { 107*1285115cSWilliam A. Kennington III cmdline[i] = controlCharsToSpace(cmdline[i]); 108*1285115cSWilliam A. Kennington III } 109*1285115cSWilliam A. Kennington III 110*1285115cSWilliam A. Kennington III // Trim empty strings 111*1285115cSWilliam A. Kennington III cmdline = trimStringRight(cmdline); 112*1285115cSWilliam A. Kennington III 113*1285115cSWilliam A. Kennington III return cmdline; 114*1285115cSWilliam A. Kennington III } 115*1285115cSWilliam A. Kennington III 116*1285115cSWilliam A. Kennington III // strtok is used in this function in order to avoid usage of <sstream>. 117*1285115cSWilliam A. Kennington III // However, that would require us to create a temporary std::string. 118*1285115cSWilliam A. Kennington III TcommUtimeStime parseTcommUtimeStimeString(std::string_view content, 119*1285115cSWilliam A. Kennington III const long ticksPerSec) 120*1285115cSWilliam A. Kennington III { 121*1285115cSWilliam A. Kennington III TcommUtimeStime ret; 122*1285115cSWilliam A. Kennington III ret.tcomm = ""; 123*1285115cSWilliam A. Kennington III ret.utime = ret.stime = 0; 124*1285115cSWilliam A. Kennington III 125*1285115cSWilliam A. Kennington III const float invTicksPerSec = 1.0f / static_cast<float>(ticksPerSec); 126*1285115cSWilliam A. Kennington III 127*1285115cSWilliam A. Kennington III // pCol now points to the first part in content after content is split by 128*1285115cSWilliam A. Kennington III // space. 129*1285115cSWilliam A. Kennington III // This is not ideal, 130*1285115cSWilliam A. Kennington III std::string temp(content); 131*1285115cSWilliam A. Kennington III char* pCol = strtok(temp.data(), " "); 132*1285115cSWilliam A. Kennington III 133*1285115cSWilliam A. Kennington III if (pCol != nullptr) 134*1285115cSWilliam A. Kennington III { 135*1285115cSWilliam A. Kennington III const int fields[] = {1, 13, 14}; // tcomm, utime, stime 136*1285115cSWilliam A. Kennington III int fieldIdx = 0; 137*1285115cSWilliam A. Kennington III for (int colIdx = 0; colIdx < 15; ++colIdx) 138*1285115cSWilliam A. Kennington III { 139*1285115cSWilliam A. Kennington III if (fieldIdx < 3 && colIdx == fields[fieldIdx]) 140*1285115cSWilliam A. Kennington III { 141*1285115cSWilliam A. Kennington III switch (fieldIdx) 142*1285115cSWilliam A. Kennington III { 143*1285115cSWilliam A. Kennington III case 0: 144*1285115cSWilliam A. Kennington III { 145*1285115cSWilliam A. Kennington III ret.tcomm = std::string(pCol); 146*1285115cSWilliam A. Kennington III break; 147*1285115cSWilliam A. Kennington III } 148*1285115cSWilliam A. Kennington III case 1: 149*1285115cSWilliam A. Kennington III [[fallthrough]]; 150*1285115cSWilliam A. Kennington III case 2: 151*1285115cSWilliam A. Kennington III { 152*1285115cSWilliam A. Kennington III int ticks = std::atoi(pCol); 153*1285115cSWilliam A. Kennington III float t = static_cast<float>(ticks) * invTicksPerSec; 154*1285115cSWilliam A. Kennington III 155*1285115cSWilliam A. Kennington III if (fieldIdx == 1) 156*1285115cSWilliam A. Kennington III { 157*1285115cSWilliam A. Kennington III ret.utime = t; 158*1285115cSWilliam A. Kennington III } 159*1285115cSWilliam A. Kennington III else if (fieldIdx == 2) 160*1285115cSWilliam A. Kennington III { 161*1285115cSWilliam A. Kennington III ret.stime = t; 162*1285115cSWilliam A. Kennington III } 163*1285115cSWilliam A. Kennington III break; 164*1285115cSWilliam A. Kennington III } 165*1285115cSWilliam A. Kennington III } 166*1285115cSWilliam A. Kennington III ++fieldIdx; 167*1285115cSWilliam A. Kennington III } 168*1285115cSWilliam A. Kennington III pCol = strtok(nullptr, " "); 169*1285115cSWilliam A. Kennington III } 170*1285115cSWilliam A. Kennington III } 171*1285115cSWilliam A. Kennington III 172*1285115cSWilliam A. Kennington III if (ticksPerSec <= 0) 173*1285115cSWilliam A. Kennington III { 174*1285115cSWilliam A. Kennington III log<level::ERR>("ticksPerSec is equal or less than zero"); 175*1285115cSWilliam A. Kennington III } 176*1285115cSWilliam A. Kennington III 177*1285115cSWilliam A. Kennington III return ret; 178*1285115cSWilliam A. Kennington III } 179*1285115cSWilliam A. Kennington III 180*1285115cSWilliam A. Kennington III TcommUtimeStime getTcommUtimeStime(const int pid, const long ticksPerSec) 181*1285115cSWilliam A. Kennington III { 182*1285115cSWilliam A. Kennington III const std::string& statPath = "/proc/" + std::to_string(pid) + "/stat"; 183*1285115cSWilliam A. Kennington III return parseTcommUtimeStimeString(readFileIntoString(statPath), 184*1285115cSWilliam A. Kennington III ticksPerSec); 185*1285115cSWilliam A. Kennington III } 186*1285115cSWilliam A. Kennington III 187*1285115cSWilliam A. Kennington III // Returns true if successfully parsed and false otherwise. If parsing was 188*1285115cSWilliam A. Kennington III // successful, value is set accordingly. 189*1285115cSWilliam A. Kennington III // Input: "MemAvailable: 1234 kB" 190*1285115cSWilliam A. Kennington III // Returns true, value set to 1234 191*1285115cSWilliam A. Kennington III bool parseMeminfoValue(const std::string_view content, 192*1285115cSWilliam A. Kennington III const std::string_view keyword, int& value) 193*1285115cSWilliam A. Kennington III { 194*1285115cSWilliam A. Kennington III size_t p = content.find(keyword); 195*1285115cSWilliam A. Kennington III if (p != std::string::npos) 196*1285115cSWilliam A. Kennington III { 197*1285115cSWilliam A. Kennington III std::string_view v = content.substr(p + keyword.size()); 198*1285115cSWilliam A. Kennington III p = v.find("kB"); 199*1285115cSWilliam A. Kennington III if (p != std::string::npos) 200*1285115cSWilliam A. Kennington III { 201*1285115cSWilliam A. Kennington III v = v.substr(0, p); 202*1285115cSWilliam A. Kennington III value = std::atoi(v.data()); 203*1285115cSWilliam A. Kennington III return true; 204*1285115cSWilliam A. Kennington III } 205*1285115cSWilliam A. Kennington III } 206*1285115cSWilliam A. Kennington III return false; 207*1285115cSWilliam A. Kennington III } 208*1285115cSWilliam A. Kennington III 209*1285115cSWilliam A. Kennington III bool parseProcUptime(const std::string_view content, double& uptime, 210*1285115cSWilliam A. Kennington III double& idleProcessTime) 211*1285115cSWilliam A. Kennington III { 212*1285115cSWilliam A. Kennington III double t0, t1; // Attempts to parse uptime and idleProcessTime 213*1285115cSWilliam A. Kennington III int ret = sscanf(content.data(), "%lf %lf", &t0, &t1); 214*1285115cSWilliam A. Kennington III if (ret == 2 && std::isfinite(t0) && std::isfinite(t1)) 215*1285115cSWilliam A. Kennington III { 216*1285115cSWilliam A. Kennington III uptime = t0; 217*1285115cSWilliam A. Kennington III idleProcessTime = t1; 218*1285115cSWilliam A. Kennington III return true; 219*1285115cSWilliam A. Kennington III } 220*1285115cSWilliam A. Kennington III return false; 221*1285115cSWilliam A. Kennington III } 222*1285115cSWilliam A. Kennington III 223*1285115cSWilliam A. Kennington III } // namespace metric_blob