xref: /openbmc/google-misc/dhcp-done/subprojects/metrics-ipmi-blobs/metric.cpp (revision b63d6314d059140f1ed23456d798544ac8e30d45)
11285115cSWilliam A. Kennington III // Copyright 2021 Google LLC
21285115cSWilliam A. Kennington III //
31285115cSWilliam A. Kennington III // Licensed under the Apache License, Version 2.0 (the "License");
41285115cSWilliam A. Kennington III // you may not use this file except in compliance with the License.
51285115cSWilliam A. Kennington III // You may obtain a copy of the License at
61285115cSWilliam A. Kennington III //
71285115cSWilliam A. Kennington III //      http://www.apache.org/licenses/LICENSE-2.0
81285115cSWilliam A. Kennington III //
91285115cSWilliam A. Kennington III // Unless required by applicable law or agreed to in writing, software
101285115cSWilliam A. Kennington III // distributed under the License is distributed on an "AS IS" BASIS,
111285115cSWilliam A. Kennington III // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121285115cSWilliam A. Kennington III // See the License for the specific language governing permissions and
131285115cSWilliam A. Kennington III // limitations under the License.
141285115cSWilliam A. Kennington III 
151285115cSWilliam A. Kennington III #include "metric.hpp"
161285115cSWilliam A. Kennington III 
171285115cSWilliam A. Kennington III #include "metricblob.pb.h"
181285115cSWilliam A. Kennington III 
191285115cSWilliam A. Kennington III #include "util.hpp"
201285115cSWilliam A. Kennington III 
211285115cSWilliam A. Kennington III #include <sys/statvfs.h>
221285115cSWilliam A. Kennington III 
231285115cSWilliam A. Kennington III #include <phosphor-logging/log.hpp>
241285115cSWilliam A. Kennington III 
251285115cSWilliam A. Kennington III #include <cstdint>
261285115cSWilliam A. Kennington III #include <filesystem>
271285115cSWilliam A. Kennington III #include <sstream>
281285115cSWilliam A. Kennington III #include <string>
291285115cSWilliam A. Kennington III #include <string_view>
301285115cSWilliam A. Kennington III 
311285115cSWilliam A. Kennington III namespace metric_blob
321285115cSWilliam A. Kennington III {
331285115cSWilliam A. Kennington III 
341285115cSWilliam A. Kennington III using phosphor::logging::entry;
351285115cSWilliam A. Kennington III using phosphor::logging::log;
361285115cSWilliam A. Kennington III using level = phosphor::logging::level;
371285115cSWilliam A. Kennington III 
381285115cSWilliam A. Kennington III BmcHealthSnapshot::BmcHealthSnapshot() :
391285115cSWilliam A. Kennington III     done(false), stringId(0), ticksPerSec(0)
401285115cSWilliam A. Kennington III {}
411285115cSWilliam A. Kennington III 
421285115cSWilliam A. Kennington III struct ProcStatEntry
431285115cSWilliam A. Kennington III {
441285115cSWilliam A. Kennington III     std::string cmdline;
451285115cSWilliam A. Kennington III     std::string tcomm;
461285115cSWilliam A. Kennington III     float utime;
471285115cSWilliam A. Kennington III     float stime;
481285115cSWilliam A. Kennington III 
491285115cSWilliam A. Kennington III     // Processes with the longest utime + stime are ranked first.
501285115cSWilliam A. Kennington III     // Tie breaking is done with cmdline then tcomm.
511285115cSWilliam A. Kennington III     bool operator<(const ProcStatEntry& other) const
521285115cSWilliam A. Kennington III     {
531285115cSWilliam A. Kennington III         const float negTime = -(utime + stime);
541285115cSWilliam A. Kennington III         const float negOtherTime = -(other.utime + other.stime);
551285115cSWilliam A. Kennington III         return std::tie(negTime, cmdline, tcomm) <
561285115cSWilliam A. Kennington III                std::tie(negOtherTime, other.cmdline, other.tcomm);
571285115cSWilliam A. Kennington III     }
581285115cSWilliam A. Kennington III };
591285115cSWilliam A. Kennington III 
601285115cSWilliam A. Kennington III bmcmetrics::metricproto::BmcProcStatMetric BmcHealthSnapshot::getProcStatList()
611285115cSWilliam A. Kennington III {
621285115cSWilliam A. Kennington III     constexpr std::string_view procPath = "/proc/";
631285115cSWilliam A. Kennington III 
641285115cSWilliam A. Kennington III     bmcmetrics::metricproto::BmcProcStatMetric ret;
651285115cSWilliam A. Kennington III     std::vector<ProcStatEntry> entries;
661285115cSWilliam A. Kennington III 
671285115cSWilliam A. Kennington III     for (const auto& procEntry : std::filesystem::directory_iterator(procPath))
681285115cSWilliam A. Kennington III     {
691285115cSWilliam A. Kennington III         const std::string& path = procEntry.path();
701285115cSWilliam A. Kennington III         int pid = -1;
711285115cSWilliam A. Kennington III         if (isNumericPath(path, pid))
721285115cSWilliam A. Kennington III         {
731285115cSWilliam A. Kennington III             ProcStatEntry entry;
741285115cSWilliam A. Kennington III 
751285115cSWilliam A. Kennington III             try
761285115cSWilliam A. Kennington III             {
771285115cSWilliam A. Kennington III                 entry.cmdline = getCmdLine(pid);
781285115cSWilliam A. Kennington III                 TcommUtimeStime t = getTcommUtimeStime(pid, ticksPerSec);
791285115cSWilliam A. Kennington III                 entry.tcomm = t.tcomm;
801285115cSWilliam A. Kennington III                 entry.utime = t.utime;
811285115cSWilliam A. Kennington III                 entry.stime = t.stime;
821285115cSWilliam A. Kennington III 
831285115cSWilliam A. Kennington III                 entries.push_back(entry);
841285115cSWilliam A. Kennington III             }
851285115cSWilliam A. Kennington III             catch (const std::exception& e)
861285115cSWilliam A. Kennington III             {
871285115cSWilliam A. Kennington III                 log<level::ERR>("Could not obtain process stats");
881285115cSWilliam A. Kennington III             }
891285115cSWilliam A. Kennington III         }
901285115cSWilliam A. Kennington III     }
911285115cSWilliam A. Kennington III 
921285115cSWilliam A. Kennington III     std::sort(entries.begin(), entries.end());
931285115cSWilliam A. Kennington III 
941285115cSWilliam A. Kennington III     bool isOthers = false;
951285115cSWilliam A. Kennington III     ProcStatEntry others;
961285115cSWilliam A. Kennington III     others.cmdline = "(Others)";
971285115cSWilliam A. Kennington III     others.utime = others.stime = 0;
981285115cSWilliam A. Kennington III 
991285115cSWilliam A. Kennington III     // Only show this many processes and aggregate all remaining ones into
1001285115cSWilliam A. Kennington III     // "others" in order to keep the size of the snapshot reasonably small.
1011285115cSWilliam A. Kennington III     // With 10 process stat entries and 10 FD count entries, the size of the
1021285115cSWilliam A. Kennington III     // snapshot reaches around 1.5KiB. This is non-trivial, and we have to set
1031285115cSWilliam A. Kennington III     // the collection interval long enough so as not to over-stress the IPMI
1041285115cSWilliam A. Kennington III     // interface and the data collection service. The value of 10 is chosen
1051285115cSWilliam A. Kennington III     // empirically, it might be subject to adjustments when the system is
1061285115cSWilliam A. Kennington III     // launched later.
1071285115cSWilliam A. Kennington III     constexpr int topN = 10;
1081285115cSWilliam A. Kennington III 
1091285115cSWilliam A. Kennington III     for (size_t i = 0; i < entries.size(); ++i)
1101285115cSWilliam A. Kennington III     {
1111285115cSWilliam A. Kennington III         if (i >= topN)
1121285115cSWilliam A. Kennington III         {
1131285115cSWilliam A. Kennington III             isOthers = true;
1141285115cSWilliam A. Kennington III         }
1151285115cSWilliam A. Kennington III 
1161285115cSWilliam A. Kennington III         ProcStatEntry& entry = entries[i];
1171285115cSWilliam A. Kennington III 
1181285115cSWilliam A. Kennington III         if (isOthers)
1191285115cSWilliam A. Kennington III         {
1201285115cSWilliam A. Kennington III             others.utime += entry.utime;
1211285115cSWilliam A. Kennington III             others.stime += entry.stime;
1221285115cSWilliam A. Kennington III         }
1231285115cSWilliam A. Kennington III         else
1241285115cSWilliam A. Kennington III         {
1251285115cSWilliam A. Kennington III             bmcmetrics::metricproto::BmcProcStatMetric::BmcProcStat s;
1261285115cSWilliam A. Kennington III             std::string fullCmdline = entry.cmdline;
1271285115cSWilliam A. Kennington III             if (entry.tcomm.size() > 0)
1281285115cSWilliam A. Kennington III             {
1291285115cSWilliam A. Kennington III                 fullCmdline += " " + entry.tcomm;
1301285115cSWilliam A. Kennington III             }
1311285115cSWilliam A. Kennington III             s.set_sidx_cmdline(getStringID(fullCmdline));
1321285115cSWilliam A. Kennington III             s.set_utime(entry.utime);
1331285115cSWilliam A. Kennington III             s.set_stime(entry.stime);
1341285115cSWilliam A. Kennington III             *(ret.add_stats()) = s;
1351285115cSWilliam A. Kennington III         }
1361285115cSWilliam A. Kennington III     }
1371285115cSWilliam A. Kennington III 
1381285115cSWilliam A. Kennington III     if (isOthers)
1391285115cSWilliam A. Kennington III     {
1401285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcProcStatMetric::BmcProcStat s;
1411285115cSWilliam A. Kennington III         s.set_sidx_cmdline(getStringID(others.cmdline));
1421285115cSWilliam A. Kennington III         s.set_utime(others.utime);
1431285115cSWilliam A. Kennington III         s.set_stime(others.stime);
1441285115cSWilliam A. Kennington III         *(ret.add_stats()) = s;
1451285115cSWilliam A. Kennington III     }
1461285115cSWilliam A. Kennington III 
1471285115cSWilliam A. Kennington III     return ret;
1481285115cSWilliam A. Kennington III }
1491285115cSWilliam A. Kennington III 
1501285115cSWilliam A. Kennington III int getFdCount(int pid)
1511285115cSWilliam A. Kennington III {
1521285115cSWilliam A. Kennington III     const std::string& fdPath = "/proc/" + std::to_string(pid) + "/fd";
1531285115cSWilliam A. Kennington III     return std::distance(std::filesystem::directory_iterator(fdPath),
1541285115cSWilliam A. Kennington III                          std::filesystem::directory_iterator{});
1551285115cSWilliam A. Kennington III }
1561285115cSWilliam A. Kennington III 
1571285115cSWilliam A. Kennington III struct FdStatEntry
1581285115cSWilliam A. Kennington III {
1591285115cSWilliam A. Kennington III     int fdCount;
1601285115cSWilliam A. Kennington III     std::string cmdline;
1611285115cSWilliam A. Kennington III     std::string tcomm;
1621285115cSWilliam A. Kennington III 
1631285115cSWilliam A. Kennington III     // Processes with the largest fdCount goes first.
1641285115cSWilliam A. Kennington III     // Tie-breaking using cmdline then tcomm.
1651285115cSWilliam A. Kennington III     bool operator<(const FdStatEntry& other) const
1661285115cSWilliam A. Kennington III     {
1671285115cSWilliam A. Kennington III         const int negFdCount = -fdCount;
1681285115cSWilliam A. Kennington III         const int negOtherFdCount = -other.fdCount;
1691285115cSWilliam A. Kennington III         return std::tie(negFdCount, cmdline, tcomm) <
1701285115cSWilliam A. Kennington III                std::tie(negOtherFdCount, other.cmdline, other.tcomm);
1711285115cSWilliam A. Kennington III     }
1721285115cSWilliam A. Kennington III };
1731285115cSWilliam A. Kennington III 
1741285115cSWilliam A. Kennington III bmcmetrics::metricproto::BmcFdStatMetric BmcHealthSnapshot::getFdStatList()
1751285115cSWilliam A. Kennington III {
1761285115cSWilliam A. Kennington III     bmcmetrics::metricproto::BmcFdStatMetric ret;
1771285115cSWilliam A. Kennington III 
1781285115cSWilliam A. Kennington III     // Sort by fd count, no tie-breaking
1791285115cSWilliam A. Kennington III     std::vector<FdStatEntry> entries;
1801285115cSWilliam A. Kennington III 
1811285115cSWilliam A. Kennington III     const std::string_view procPath = "/proc/";
1821285115cSWilliam A. Kennington III     for (const auto& procEntry : std::filesystem::directory_iterator(procPath))
1831285115cSWilliam A. Kennington III     {
1841285115cSWilliam A. Kennington III         const std::string& path = procEntry.path();
1851285115cSWilliam A. Kennington III         int pid = 0;
1861285115cSWilliam A. Kennington III         FdStatEntry entry;
1871285115cSWilliam A. Kennington III         if (isNumericPath(path, pid))
1881285115cSWilliam A. Kennington III         {
1891285115cSWilliam A. Kennington III             try
1901285115cSWilliam A. Kennington III             {
1911285115cSWilliam A. Kennington III                 entry.fdCount = getFdCount(pid);
1921285115cSWilliam A. Kennington III                 TcommUtimeStime t = getTcommUtimeStime(pid, ticksPerSec);
1931285115cSWilliam A. Kennington III                 entry.cmdline = getCmdLine(pid);
1941285115cSWilliam A. Kennington III                 entry.tcomm = t.tcomm;
1951285115cSWilliam A. Kennington III                 entries.push_back(entry);
1961285115cSWilliam A. Kennington III             }
1971285115cSWilliam A. Kennington III             catch (const std::exception& e)
1981285115cSWilliam A. Kennington III             {
1991285115cSWilliam A. Kennington III                 log<level::ERR>("Could not get file descriptor stats");
2001285115cSWilliam A. Kennington III             }
2011285115cSWilliam A. Kennington III         }
2021285115cSWilliam A. Kennington III     }
2031285115cSWilliam A. Kennington III 
2041285115cSWilliam A. Kennington III     std::sort(entries.begin(), entries.end());
2051285115cSWilliam A. Kennington III 
2061285115cSWilliam A. Kennington III     bool isOthers = false;
2071285115cSWilliam A. Kennington III 
2081285115cSWilliam A. Kennington III     // Only report the detailed fd count and cmdline for the top 10 entries,
2091285115cSWilliam A. Kennington III     // and collapse all others into "others".
2101285115cSWilliam A. Kennington III     constexpr int topN = 10;
2111285115cSWilliam A. Kennington III 
2121285115cSWilliam A. Kennington III     FdStatEntry others;
2131285115cSWilliam A. Kennington III     others.cmdline = "(Others)";
2141285115cSWilliam A. Kennington III     others.fdCount = 0;
2151285115cSWilliam A. Kennington III 
2161285115cSWilliam A. Kennington III     for (size_t i = 0; i < entries.size(); ++i)
2171285115cSWilliam A. Kennington III     {
2181285115cSWilliam A. Kennington III         if (i >= topN)
2191285115cSWilliam A. Kennington III         {
2201285115cSWilliam A. Kennington III             isOthers = true;
2211285115cSWilliam A. Kennington III         }
2221285115cSWilliam A. Kennington III 
2231285115cSWilliam A. Kennington III         const FdStatEntry& entry = entries[i];
2241285115cSWilliam A. Kennington III         if (isOthers)
2251285115cSWilliam A. Kennington III         {
2261285115cSWilliam A. Kennington III             others.fdCount += entry.fdCount;
2271285115cSWilliam A. Kennington III         }
2281285115cSWilliam A. Kennington III         else
2291285115cSWilliam A. Kennington III         {
2301285115cSWilliam A. Kennington III             bmcmetrics::metricproto::BmcFdStatMetric::BmcFdStat s;
2311285115cSWilliam A. Kennington III             std::string fullCmdline = entry.cmdline;
2321285115cSWilliam A. Kennington III             if (entry.tcomm.size() > 0)
2331285115cSWilliam A. Kennington III             {
2341285115cSWilliam A. Kennington III                 fullCmdline += " " + entry.tcomm;
2351285115cSWilliam A. Kennington III             }
2361285115cSWilliam A. Kennington III             s.set_sidx_cmdline(getStringID(fullCmdline));
2371285115cSWilliam A. Kennington III             s.set_fd_count(entry.fdCount);
2381285115cSWilliam A. Kennington III             *(ret.add_stats()) = s;
2391285115cSWilliam A. Kennington III         }
2401285115cSWilliam A. Kennington III     }
2411285115cSWilliam A. Kennington III 
2421285115cSWilliam A. Kennington III     if (isOthers)
2431285115cSWilliam A. Kennington III     {
2441285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcFdStatMetric::BmcFdStat s;
2451285115cSWilliam A. Kennington III         s.set_sidx_cmdline(getStringID(others.cmdline));
2461285115cSWilliam A. Kennington III         s.set_fd_count(others.fdCount);
2471285115cSWilliam A. Kennington III         *(ret.add_stats()) = s;
2481285115cSWilliam A. Kennington III     }
2491285115cSWilliam A. Kennington III 
2501285115cSWilliam A. Kennington III     return ret;
2511285115cSWilliam A. Kennington III }
2521285115cSWilliam A. Kennington III 
2531285115cSWilliam A. Kennington III void BmcHealthSnapshot::serializeSnapshotToArray(
2541285115cSWilliam A. Kennington III     const bmcmetrics::metricproto::BmcMetricSnapshot& snapshot)
2551285115cSWilliam A. Kennington III {
2561285115cSWilliam A. Kennington III     size_t size = snapshot.ByteSizeLong();
2571285115cSWilliam A. Kennington III     if (size > 0)
2581285115cSWilliam A. Kennington III     {
2591285115cSWilliam A. Kennington III         pbDump.resize(size);
2601285115cSWilliam A. Kennington III         if (!snapshot.SerializeToArray(pbDump.data(), size))
2611285115cSWilliam A. Kennington III         {
2621285115cSWilliam A. Kennington III             log<level::ERR>("Could not serialize protobuf to array");
2631285115cSWilliam A. Kennington III         }
2641285115cSWilliam A. Kennington III     }
2651285115cSWilliam A. Kennington III }
2661285115cSWilliam A. Kennington III 
2671285115cSWilliam A. Kennington III void BmcHealthSnapshot::doWork()
2681285115cSWilliam A. Kennington III {
2691285115cSWilliam A. Kennington III     bmcmetrics::metricproto::BmcMetricSnapshot snapshot;
2701285115cSWilliam A. Kennington III 
2711285115cSWilliam A. Kennington III     // Memory info
272*b63d6314SMichael Shen     std::string meminfoBuffer = readFileThenGrepIntoString("/proc/meminfo");
2731285115cSWilliam A. Kennington III 
2741285115cSWilliam A. Kennington III     {
2751285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcMemoryMetric m;
2761285115cSWilliam A. Kennington III 
2771285115cSWilliam A. Kennington III         std::string_view sv(meminfoBuffer.data());
2781285115cSWilliam A. Kennington III         // MemAvailable
2791285115cSWilliam A. Kennington III         int value;
2801285115cSWilliam A. Kennington III         bool ok = parseMeminfoValue(sv, "MemAvailable:", value);
2811285115cSWilliam A. Kennington III         if (ok)
2821285115cSWilliam A. Kennington III         {
2831285115cSWilliam A. Kennington III             m.set_mem_available(value);
2841285115cSWilliam A. Kennington III         }
2851285115cSWilliam A. Kennington III 
2861285115cSWilliam A. Kennington III         ok = parseMeminfoValue(sv, "Slab:", value);
2871285115cSWilliam A. Kennington III         if (ok)
2881285115cSWilliam A. Kennington III         {
2891285115cSWilliam A. Kennington III             m.set_slab(value);
2901285115cSWilliam A. Kennington III         }
2911285115cSWilliam A. Kennington III 
2921285115cSWilliam A. Kennington III         ok = parseMeminfoValue(sv, "KernelStack:", value);
2931285115cSWilliam A. Kennington III         if (ok)
2941285115cSWilliam A. Kennington III         {
2951285115cSWilliam A. Kennington III             m.set_kernel_stack(value);
2961285115cSWilliam A. Kennington III         }
2971285115cSWilliam A. Kennington III 
2981285115cSWilliam A. Kennington III         *(snapshot.mutable_memory_metric()) = m;
2991285115cSWilliam A. Kennington III     }
3001285115cSWilliam A. Kennington III 
3011285115cSWilliam A. Kennington III     // Uptime
302*b63d6314SMichael Shen     std::string uptimeBuffer = readFileThenGrepIntoString("/proc/uptime");
303*b63d6314SMichael Shen     double uptime = 0;
304*b63d6314SMichael Shen     double idleProcessTime = 0;
305*b63d6314SMichael Shen     BootTimesMonotonic btm;
306*b63d6314SMichael Shen     if (!parseProcUptime(uptimeBuffer, uptime, idleProcessTime))
307*b63d6314SMichael Shen     {
308*b63d6314SMichael Shen         log<level::ERR>("Error parsing /proc/uptime");
309*b63d6314SMichael Shen     }
310*b63d6314SMichael Shen     else if (!getBootTimesMonotonic(btm))
311*b63d6314SMichael Shen     {
312*b63d6314SMichael Shen         log<level::ERR>("Could not get boot time");
313*b63d6314SMichael Shen     }
314*b63d6314SMichael Shen     else
3151285115cSWilliam A. Kennington III     {
3161285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcUptimeMetric m1;
3171285115cSWilliam A. Kennington III         m1.set_uptime(uptime);
3181285115cSWilliam A. Kennington III         m1.set_idle_process_time(idleProcessTime);
319*b63d6314SMichael Shen         if (btm.firmwareTime == 0 && btm.powerOnSecCounterTime != 0)
320*b63d6314SMichael Shen         {
321*b63d6314SMichael Shen             m1.set_firmware_boot_time_sec(
322*b63d6314SMichael Shen                 static_cast<double>(btm.powerOnSecCounterTime) - uptime);
3231285115cSWilliam A. Kennington III         }
3241285115cSWilliam A. Kennington III         else
3251285115cSWilliam A. Kennington III         {
326*b63d6314SMichael Shen             m1.set_firmware_boot_time_sec(
327*b63d6314SMichael Shen                 static_cast<double>(btm.firmwareTime - btm.loaderTime) / 1e6);
328*b63d6314SMichael Shen         }
329*b63d6314SMichael Shen         m1.set_loader_boot_time_sec(static_cast<double>(btm.loaderTime) / 1e6);
330*b63d6314SMichael Shen         // initrf presents
331*b63d6314SMichael Shen         if (btm.initrdTime != 0)
332*b63d6314SMichael Shen         {
333*b63d6314SMichael Shen             m1.set_kernel_boot_time_sec(static_cast<double>(btm.initrdTime) /
334*b63d6314SMichael Shen                                         1e6);
335*b63d6314SMichael Shen             m1.set_initrd_boot_time_sec(
336*b63d6314SMichael Shen                 static_cast<double>(btm.userspaceTime - btm.initrdTime) / 1e6);
337*b63d6314SMichael Shen             m1.set_userspace_boot_time_sec(
338*b63d6314SMichael Shen                 static_cast<double>(btm.finishTime - btm.userspaceTime) / 1e6);
339*b63d6314SMichael Shen         }
340*b63d6314SMichael Shen         else
341*b63d6314SMichael Shen         {
342*b63d6314SMichael Shen             m1.set_kernel_boot_time_sec(static_cast<double>(btm.userspaceTime) /
343*b63d6314SMichael Shen                                         1e6);
344*b63d6314SMichael Shen             m1.set_initrd_boot_time_sec(0);
345*b63d6314SMichael Shen             m1.set_userspace_boot_time_sec(
346*b63d6314SMichael Shen                 static_cast<double>(btm.finishTime - btm.userspaceTime) / 1e6);
347*b63d6314SMichael Shen         }
348*b63d6314SMichael Shen         *(snapshot.mutable_uptime_metric()) = m1;
3491285115cSWilliam A. Kennington III     }
3501285115cSWilliam A. Kennington III 
3511285115cSWilliam A. Kennington III     // Storage space
3521285115cSWilliam A. Kennington III     struct statvfs fiData;
3531285115cSWilliam A. Kennington III     if ((statvfs("/", &fiData)) < 0)
3541285115cSWilliam A. Kennington III     {
3551285115cSWilliam A. Kennington III         log<level::ERR>("Could not call statvfs");
3561285115cSWilliam A. Kennington III     }
3571285115cSWilliam A. Kennington III     else
3581285115cSWilliam A. Kennington III     {
3591285115cSWilliam A. Kennington III         uint64_t kib = (fiData.f_bsize * fiData.f_bfree) / 1024;
3601285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcDiskSpaceMetric m2;
3611285115cSWilliam A. Kennington III         m2.set_rwfs_kib_available(static_cast<int>(kib));
3621285115cSWilliam A. Kennington III         *(snapshot.mutable_storage_space_metric()) = m2;
3631285115cSWilliam A. Kennington III     }
3641285115cSWilliam A. Kennington III 
3651285115cSWilliam A. Kennington III     // The next metrics require a sane ticks_per_sec value, typically 100 on
3661285115cSWilliam A. Kennington III     // the BMC. In the very rare circumstance when it's 0, exit early and return
3671285115cSWilliam A. Kennington III     // a partially complete snapshot (no process).
3681285115cSWilliam A. Kennington III     ticksPerSec = getTicksPerSec();
3691285115cSWilliam A. Kennington III 
3701285115cSWilliam A. Kennington III     // FD stat
3711285115cSWilliam A. Kennington III     *(snapshot.mutable_fdstat_metric()) = getFdStatList();
3721285115cSWilliam A. Kennington III 
3731285115cSWilliam A. Kennington III     if (ticksPerSec == 0)
3741285115cSWilliam A. Kennington III     {
3751285115cSWilliam A. Kennington III         log<level::ERR>("ticksPerSec is 0, skipping the process list metric");
3761285115cSWilliam A. Kennington III         serializeSnapshotToArray(snapshot);
3771285115cSWilliam A. Kennington III         done = true;
3781285115cSWilliam A. Kennington III         return;
3791285115cSWilliam A. Kennington III     }
3801285115cSWilliam A. Kennington III 
3811285115cSWilliam A. Kennington III     // Proc stat
3821285115cSWilliam A. Kennington III     *(snapshot.mutable_procstat_metric()) = getProcStatList();
3831285115cSWilliam A. Kennington III 
3841285115cSWilliam A. Kennington III     // String table
3851285115cSWilliam A. Kennington III     std::vector<std::string_view> strings(stringTable.size());
3861285115cSWilliam A. Kennington III     for (const auto& [s, i] : stringTable)
3871285115cSWilliam A. Kennington III     {
3881285115cSWilliam A. Kennington III         strings[i] = s;
3891285115cSWilliam A. Kennington III     }
3901285115cSWilliam A. Kennington III 
3911285115cSWilliam A. Kennington III     bmcmetrics::metricproto::BmcStringTable st;
3921285115cSWilliam A. Kennington III     for (size_t i = 0; i < strings.size(); ++i)
3931285115cSWilliam A. Kennington III     {
3941285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcStringTable::StringEntry entry;
3951285115cSWilliam A. Kennington III         entry.set_value(strings[i].data());
3961285115cSWilliam A. Kennington III         *(st.add_entries()) = entry;
3971285115cSWilliam A. Kennington III     }
3981285115cSWilliam A. Kennington III     *(snapshot.mutable_string_table()) = st;
3991285115cSWilliam A. Kennington III 
4001285115cSWilliam A. Kennington III     // Save to buffer
4011285115cSWilliam A. Kennington III     serializeSnapshotToArray(snapshot);
4021285115cSWilliam A. Kennington III     done = true;
4031285115cSWilliam A. Kennington III }
4041285115cSWilliam A. Kennington III 
4051285115cSWilliam A. Kennington III // BmcBlobSessionStat (9) but passing meta as reference instead of pointer,
4061285115cSWilliam A. Kennington III // since the metadata must not be null at this point.
4071285115cSWilliam A. Kennington III bool BmcHealthSnapshot::stat(blobs::BlobMeta& meta)
4081285115cSWilliam A. Kennington III {
4091285115cSWilliam A. Kennington III     if (!done)
4101285115cSWilliam A. Kennington III     {
4111285115cSWilliam A. Kennington III         // Bits 8~15 are blob-specific state flags.
4121285115cSWilliam A. Kennington III         // For this blob, bit 8 is set when metric collection is still in
4131285115cSWilliam A. Kennington III         // progress.
4141285115cSWilliam A. Kennington III         meta.blobState |= (1 << 8);
4151285115cSWilliam A. Kennington III     }
4161285115cSWilliam A. Kennington III     else
4171285115cSWilliam A. Kennington III     {
4181285115cSWilliam A. Kennington III         meta.blobState = 0;
4191285115cSWilliam A. Kennington III         meta.blobState = blobs::StateFlags::open_read;
4201285115cSWilliam A. Kennington III         meta.size = pbDump.size();
4211285115cSWilliam A. Kennington III     }
4221285115cSWilliam A. Kennington III     return true;
4231285115cSWilliam A. Kennington III }
4241285115cSWilliam A. Kennington III 
4251285115cSWilliam A. Kennington III std::string_view BmcHealthSnapshot::read(uint32_t offset,
4261285115cSWilliam A. Kennington III                                          uint32_t requestedSize)
4271285115cSWilliam A. Kennington III {
4281285115cSWilliam A. Kennington III     uint32_t size = static_cast<uint32_t>(pbDump.size());
4291285115cSWilliam A. Kennington III     if (offset >= size)
4301285115cSWilliam A. Kennington III     {
4311285115cSWilliam A. Kennington III         return {};
4321285115cSWilliam A. Kennington III     }
4331285115cSWilliam A. Kennington III     return std::string_view(pbDump.data() + offset,
4341285115cSWilliam A. Kennington III                             std::min(requestedSize, size - offset));
4351285115cSWilliam A. Kennington III }
4361285115cSWilliam A. Kennington III 
4371285115cSWilliam A. Kennington III int BmcHealthSnapshot::getStringID(const std::string_view s)
4381285115cSWilliam A. Kennington III {
4391285115cSWilliam A. Kennington III     int ret = 0;
4401285115cSWilliam A. Kennington III     auto itr = stringTable.find(s.data());
4411285115cSWilliam A. Kennington III     if (itr == stringTable.end())
4421285115cSWilliam A. Kennington III     {
4431285115cSWilliam A. Kennington III         stringTable[s.data()] = stringId;
4441285115cSWilliam A. Kennington III         ret = stringId;
4451285115cSWilliam A. Kennington III         ++stringId;
4461285115cSWilliam A. Kennington III     }
4471285115cSWilliam A. Kennington III     else
4481285115cSWilliam A. Kennington III     {
4491285115cSWilliam A. Kennington III         ret = itr->second;
4501285115cSWilliam A. Kennington III     }
4511285115cSWilliam A. Kennington III     return ret;
4521285115cSWilliam A. Kennington III }
4531285115cSWilliam A. Kennington III 
4541285115cSWilliam A. Kennington III } // namespace metric_blob