xref: /openbmc/google-misc/dhcp-done/subprojects/metrics-ipmi-blobs/metric.cpp (revision 1285115c16180bd28a3cfe79d9db8d10c84fe2ed)
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 "metric.hpp"
16*1285115cSWilliam A. Kennington III 
17*1285115cSWilliam A. Kennington III #include "metricblob.pb.h"
18*1285115cSWilliam A. Kennington III 
19*1285115cSWilliam A. Kennington III #include "util.hpp"
20*1285115cSWilliam A. Kennington III 
21*1285115cSWilliam A. Kennington III #include <sys/statvfs.h>
22*1285115cSWilliam A. Kennington III 
23*1285115cSWilliam A. Kennington III #include <phosphor-logging/log.hpp>
24*1285115cSWilliam A. Kennington III 
25*1285115cSWilliam A. Kennington III #include <cstdint>
26*1285115cSWilliam A. Kennington III #include <filesystem>
27*1285115cSWilliam A. Kennington III #include <sstream>
28*1285115cSWilliam A. Kennington III #include <string>
29*1285115cSWilliam A. Kennington III #include <string_view>
30*1285115cSWilliam A. Kennington III 
31*1285115cSWilliam A. Kennington III namespace metric_blob
32*1285115cSWilliam A. Kennington III {
33*1285115cSWilliam A. Kennington III 
34*1285115cSWilliam A. Kennington III using phosphor::logging::entry;
35*1285115cSWilliam A. Kennington III using phosphor::logging::log;
36*1285115cSWilliam A. Kennington III using level = phosphor::logging::level;
37*1285115cSWilliam A. Kennington III 
38*1285115cSWilliam A. Kennington III BmcHealthSnapshot::BmcHealthSnapshot() :
39*1285115cSWilliam A. Kennington III     done(false), stringId(0), ticksPerSec(0)
40*1285115cSWilliam A. Kennington III {}
41*1285115cSWilliam A. Kennington III 
42*1285115cSWilliam A. Kennington III struct ProcStatEntry
43*1285115cSWilliam A. Kennington III {
44*1285115cSWilliam A. Kennington III     std::string cmdline;
45*1285115cSWilliam A. Kennington III     std::string tcomm;
46*1285115cSWilliam A. Kennington III     float utime;
47*1285115cSWilliam A. Kennington III     float stime;
48*1285115cSWilliam A. Kennington III 
49*1285115cSWilliam A. Kennington III     // Processes with the longest utime + stime are ranked first.
50*1285115cSWilliam A. Kennington III     // Tie breaking is done with cmdline then tcomm.
51*1285115cSWilliam A. Kennington III     bool operator<(const ProcStatEntry& other) const
52*1285115cSWilliam A. Kennington III     {
53*1285115cSWilliam A. Kennington III         const float negTime = -(utime + stime);
54*1285115cSWilliam A. Kennington III         const float negOtherTime = -(other.utime + other.stime);
55*1285115cSWilliam A. Kennington III         return std::tie(negTime, cmdline, tcomm) <
56*1285115cSWilliam A. Kennington III                std::tie(negOtherTime, other.cmdline, other.tcomm);
57*1285115cSWilliam A. Kennington III     }
58*1285115cSWilliam A. Kennington III };
59*1285115cSWilliam A. Kennington III 
60*1285115cSWilliam A. Kennington III bmcmetrics::metricproto::BmcProcStatMetric BmcHealthSnapshot::getProcStatList()
61*1285115cSWilliam A. Kennington III {
62*1285115cSWilliam A. Kennington III     constexpr std::string_view procPath = "/proc/";
63*1285115cSWilliam A. Kennington III 
64*1285115cSWilliam A. Kennington III     bmcmetrics::metricproto::BmcProcStatMetric ret;
65*1285115cSWilliam A. Kennington III     std::vector<ProcStatEntry> entries;
66*1285115cSWilliam A. Kennington III 
67*1285115cSWilliam A. Kennington III     for (const auto& procEntry : std::filesystem::directory_iterator(procPath))
68*1285115cSWilliam A. Kennington III     {
69*1285115cSWilliam A. Kennington III         const std::string& path = procEntry.path();
70*1285115cSWilliam A. Kennington III         int pid = -1;
71*1285115cSWilliam A. Kennington III         if (isNumericPath(path, pid))
72*1285115cSWilliam A. Kennington III         {
73*1285115cSWilliam A. Kennington III             ProcStatEntry entry;
74*1285115cSWilliam A. Kennington III 
75*1285115cSWilliam A. Kennington III             try
76*1285115cSWilliam A. Kennington III             {
77*1285115cSWilliam A. Kennington III                 entry.cmdline = getCmdLine(pid);
78*1285115cSWilliam A. Kennington III                 TcommUtimeStime t = getTcommUtimeStime(pid, ticksPerSec);
79*1285115cSWilliam A. Kennington III                 entry.tcomm = t.tcomm;
80*1285115cSWilliam A. Kennington III                 entry.utime = t.utime;
81*1285115cSWilliam A. Kennington III                 entry.stime = t.stime;
82*1285115cSWilliam A. Kennington III 
83*1285115cSWilliam A. Kennington III                 entries.push_back(entry);
84*1285115cSWilliam A. Kennington III             }
85*1285115cSWilliam A. Kennington III             catch (const std::exception& e)
86*1285115cSWilliam A. Kennington III             {
87*1285115cSWilliam A. Kennington III                 log<level::ERR>("Could not obtain process stats");
88*1285115cSWilliam A. Kennington III             }
89*1285115cSWilliam A. Kennington III         }
90*1285115cSWilliam A. Kennington III     }
91*1285115cSWilliam A. Kennington III 
92*1285115cSWilliam A. Kennington III     std::sort(entries.begin(), entries.end());
93*1285115cSWilliam A. Kennington III 
94*1285115cSWilliam A. Kennington III     bool isOthers = false;
95*1285115cSWilliam A. Kennington III     ProcStatEntry others;
96*1285115cSWilliam A. Kennington III     others.cmdline = "(Others)";
97*1285115cSWilliam A. Kennington III     others.utime = others.stime = 0;
98*1285115cSWilliam A. Kennington III 
99*1285115cSWilliam A. Kennington III     // Only show this many processes and aggregate all remaining ones into
100*1285115cSWilliam A. Kennington III     // "others" in order to keep the size of the snapshot reasonably small.
101*1285115cSWilliam A. Kennington III     // With 10 process stat entries and 10 FD count entries, the size of the
102*1285115cSWilliam A. Kennington III     // snapshot reaches around 1.5KiB. This is non-trivial, and we have to set
103*1285115cSWilliam A. Kennington III     // the collection interval long enough so as not to over-stress the IPMI
104*1285115cSWilliam A. Kennington III     // interface and the data collection service. The value of 10 is chosen
105*1285115cSWilliam A. Kennington III     // empirically, it might be subject to adjustments when the system is
106*1285115cSWilliam A. Kennington III     // launched later.
107*1285115cSWilliam A. Kennington III     constexpr int topN = 10;
108*1285115cSWilliam A. Kennington III 
109*1285115cSWilliam A. Kennington III     for (size_t i = 0; i < entries.size(); ++i)
110*1285115cSWilliam A. Kennington III     {
111*1285115cSWilliam A. Kennington III         if (i >= topN)
112*1285115cSWilliam A. Kennington III         {
113*1285115cSWilliam A. Kennington III             isOthers = true;
114*1285115cSWilliam A. Kennington III         }
115*1285115cSWilliam A. Kennington III 
116*1285115cSWilliam A. Kennington III         ProcStatEntry& entry = entries[i];
117*1285115cSWilliam A. Kennington III 
118*1285115cSWilliam A. Kennington III         if (isOthers)
119*1285115cSWilliam A. Kennington III         {
120*1285115cSWilliam A. Kennington III             others.utime += entry.utime;
121*1285115cSWilliam A. Kennington III             others.stime += entry.stime;
122*1285115cSWilliam A. Kennington III         }
123*1285115cSWilliam A. Kennington III         else
124*1285115cSWilliam A. Kennington III         {
125*1285115cSWilliam A. Kennington III             bmcmetrics::metricproto::BmcProcStatMetric::BmcProcStat s;
126*1285115cSWilliam A. Kennington III             std::string fullCmdline = entry.cmdline;
127*1285115cSWilliam A. Kennington III             if (entry.tcomm.size() > 0)
128*1285115cSWilliam A. Kennington III             {
129*1285115cSWilliam A. Kennington III                 fullCmdline += " " + entry.tcomm;
130*1285115cSWilliam A. Kennington III             }
131*1285115cSWilliam A. Kennington III             s.set_sidx_cmdline(getStringID(fullCmdline));
132*1285115cSWilliam A. Kennington III             s.set_utime(entry.utime);
133*1285115cSWilliam A. Kennington III             s.set_stime(entry.stime);
134*1285115cSWilliam A. Kennington III             *(ret.add_stats()) = s;
135*1285115cSWilliam A. Kennington III         }
136*1285115cSWilliam A. Kennington III     }
137*1285115cSWilliam A. Kennington III 
138*1285115cSWilliam A. Kennington III     if (isOthers)
139*1285115cSWilliam A. Kennington III     {
140*1285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcProcStatMetric::BmcProcStat s;
141*1285115cSWilliam A. Kennington III         s.set_sidx_cmdline(getStringID(others.cmdline));
142*1285115cSWilliam A. Kennington III         s.set_utime(others.utime);
143*1285115cSWilliam A. Kennington III         s.set_stime(others.stime);
144*1285115cSWilliam A. Kennington III         *(ret.add_stats()) = s;
145*1285115cSWilliam A. Kennington III     }
146*1285115cSWilliam A. Kennington III 
147*1285115cSWilliam A. Kennington III     return ret;
148*1285115cSWilliam A. Kennington III }
149*1285115cSWilliam A. Kennington III 
150*1285115cSWilliam A. Kennington III int getFdCount(int pid)
151*1285115cSWilliam A. Kennington III {
152*1285115cSWilliam A. Kennington III     const std::string& fdPath = "/proc/" + std::to_string(pid) + "/fd";
153*1285115cSWilliam A. Kennington III     return std::distance(std::filesystem::directory_iterator(fdPath),
154*1285115cSWilliam A. Kennington III                          std::filesystem::directory_iterator{});
155*1285115cSWilliam A. Kennington III }
156*1285115cSWilliam A. Kennington III 
157*1285115cSWilliam A. Kennington III struct FdStatEntry
158*1285115cSWilliam A. Kennington III {
159*1285115cSWilliam A. Kennington III     int fdCount;
160*1285115cSWilliam A. Kennington III     std::string cmdline;
161*1285115cSWilliam A. Kennington III     std::string tcomm;
162*1285115cSWilliam A. Kennington III 
163*1285115cSWilliam A. Kennington III     // Processes with the largest fdCount goes first.
164*1285115cSWilliam A. Kennington III     // Tie-breaking using cmdline then tcomm.
165*1285115cSWilliam A. Kennington III     bool operator<(const FdStatEntry& other) const
166*1285115cSWilliam A. Kennington III     {
167*1285115cSWilliam A. Kennington III         const int negFdCount = -fdCount;
168*1285115cSWilliam A. Kennington III         const int negOtherFdCount = -other.fdCount;
169*1285115cSWilliam A. Kennington III         return std::tie(negFdCount, cmdline, tcomm) <
170*1285115cSWilliam A. Kennington III                std::tie(negOtherFdCount, other.cmdline, other.tcomm);
171*1285115cSWilliam A. Kennington III     }
172*1285115cSWilliam A. Kennington III };
173*1285115cSWilliam A. Kennington III 
174*1285115cSWilliam A. Kennington III bmcmetrics::metricproto::BmcFdStatMetric BmcHealthSnapshot::getFdStatList()
175*1285115cSWilliam A. Kennington III {
176*1285115cSWilliam A. Kennington III     bmcmetrics::metricproto::BmcFdStatMetric ret;
177*1285115cSWilliam A. Kennington III 
178*1285115cSWilliam A. Kennington III     // Sort by fd count, no tie-breaking
179*1285115cSWilliam A. Kennington III     std::vector<FdStatEntry> entries;
180*1285115cSWilliam A. Kennington III 
181*1285115cSWilliam A. Kennington III     const std::string_view procPath = "/proc/";
182*1285115cSWilliam A. Kennington III     for (const auto& procEntry : std::filesystem::directory_iterator(procPath))
183*1285115cSWilliam A. Kennington III     {
184*1285115cSWilliam A. Kennington III         const std::string& path = procEntry.path();
185*1285115cSWilliam A. Kennington III         int pid = 0;
186*1285115cSWilliam A. Kennington III         FdStatEntry entry;
187*1285115cSWilliam A. Kennington III         if (isNumericPath(path, pid))
188*1285115cSWilliam A. Kennington III         {
189*1285115cSWilliam A. Kennington III             try
190*1285115cSWilliam A. Kennington III             {
191*1285115cSWilliam A. Kennington III                 entry.fdCount = getFdCount(pid);
192*1285115cSWilliam A. Kennington III                 TcommUtimeStime t = getTcommUtimeStime(pid, ticksPerSec);
193*1285115cSWilliam A. Kennington III                 entry.cmdline = getCmdLine(pid);
194*1285115cSWilliam A. Kennington III                 entry.tcomm = t.tcomm;
195*1285115cSWilliam A. Kennington III                 entries.push_back(entry);
196*1285115cSWilliam A. Kennington III             }
197*1285115cSWilliam A. Kennington III             catch (const std::exception& e)
198*1285115cSWilliam A. Kennington III             {
199*1285115cSWilliam A. Kennington III                 log<level::ERR>("Could not get file descriptor stats");
200*1285115cSWilliam A. Kennington III             }
201*1285115cSWilliam A. Kennington III         }
202*1285115cSWilliam A. Kennington III     }
203*1285115cSWilliam A. Kennington III 
204*1285115cSWilliam A. Kennington III     std::sort(entries.begin(), entries.end());
205*1285115cSWilliam A. Kennington III 
206*1285115cSWilliam A. Kennington III     bool isOthers = false;
207*1285115cSWilliam A. Kennington III 
208*1285115cSWilliam A. Kennington III     // Only report the detailed fd count and cmdline for the top 10 entries,
209*1285115cSWilliam A. Kennington III     // and collapse all others into "others".
210*1285115cSWilliam A. Kennington III     constexpr int topN = 10;
211*1285115cSWilliam A. Kennington III 
212*1285115cSWilliam A. Kennington III     FdStatEntry others;
213*1285115cSWilliam A. Kennington III     others.cmdline = "(Others)";
214*1285115cSWilliam A. Kennington III     others.fdCount = 0;
215*1285115cSWilliam A. Kennington III 
216*1285115cSWilliam A. Kennington III     for (size_t i = 0; i < entries.size(); ++i)
217*1285115cSWilliam A. Kennington III     {
218*1285115cSWilliam A. Kennington III         if (i >= topN)
219*1285115cSWilliam A. Kennington III         {
220*1285115cSWilliam A. Kennington III             isOthers = true;
221*1285115cSWilliam A. Kennington III         }
222*1285115cSWilliam A. Kennington III 
223*1285115cSWilliam A. Kennington III         const FdStatEntry& entry = entries[i];
224*1285115cSWilliam A. Kennington III         if (isOthers)
225*1285115cSWilliam A. Kennington III         {
226*1285115cSWilliam A. Kennington III             others.fdCount += entry.fdCount;
227*1285115cSWilliam A. Kennington III         }
228*1285115cSWilliam A. Kennington III         else
229*1285115cSWilliam A. Kennington III         {
230*1285115cSWilliam A. Kennington III             bmcmetrics::metricproto::BmcFdStatMetric::BmcFdStat s;
231*1285115cSWilliam A. Kennington III             std::string fullCmdline = entry.cmdline;
232*1285115cSWilliam A. Kennington III             if (entry.tcomm.size() > 0)
233*1285115cSWilliam A. Kennington III             {
234*1285115cSWilliam A. Kennington III                 fullCmdline += " " + entry.tcomm;
235*1285115cSWilliam A. Kennington III             }
236*1285115cSWilliam A. Kennington III             s.set_sidx_cmdline(getStringID(fullCmdline));
237*1285115cSWilliam A. Kennington III             s.set_fd_count(entry.fdCount);
238*1285115cSWilliam A. Kennington III             *(ret.add_stats()) = s;
239*1285115cSWilliam A. Kennington III         }
240*1285115cSWilliam A. Kennington III     }
241*1285115cSWilliam A. Kennington III 
242*1285115cSWilliam A. Kennington III     if (isOthers)
243*1285115cSWilliam A. Kennington III     {
244*1285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcFdStatMetric::BmcFdStat s;
245*1285115cSWilliam A. Kennington III         s.set_sidx_cmdline(getStringID(others.cmdline));
246*1285115cSWilliam A. Kennington III         s.set_fd_count(others.fdCount);
247*1285115cSWilliam A. Kennington III         *(ret.add_stats()) = s;
248*1285115cSWilliam A. Kennington III     }
249*1285115cSWilliam A. Kennington III 
250*1285115cSWilliam A. Kennington III     return ret;
251*1285115cSWilliam A. Kennington III }
252*1285115cSWilliam A. Kennington III 
253*1285115cSWilliam A. Kennington III void BmcHealthSnapshot::serializeSnapshotToArray(
254*1285115cSWilliam A. Kennington III     const bmcmetrics::metricproto::BmcMetricSnapshot& snapshot)
255*1285115cSWilliam A. Kennington III {
256*1285115cSWilliam A. Kennington III     size_t size = snapshot.ByteSizeLong();
257*1285115cSWilliam A. Kennington III     if (size > 0)
258*1285115cSWilliam A. Kennington III     {
259*1285115cSWilliam A. Kennington III         pbDump.resize(size);
260*1285115cSWilliam A. Kennington III         if (!snapshot.SerializeToArray(pbDump.data(), size))
261*1285115cSWilliam A. Kennington III         {
262*1285115cSWilliam A. Kennington III             log<level::ERR>("Could not serialize protobuf to array");
263*1285115cSWilliam A. Kennington III         }
264*1285115cSWilliam A. Kennington III     }
265*1285115cSWilliam A. Kennington III }
266*1285115cSWilliam A. Kennington III 
267*1285115cSWilliam A. Kennington III void BmcHealthSnapshot::doWork()
268*1285115cSWilliam A. Kennington III {
269*1285115cSWilliam A. Kennington III     bmcmetrics::metricproto::BmcMetricSnapshot snapshot;
270*1285115cSWilliam A. Kennington III 
271*1285115cSWilliam A. Kennington III     // Memory info
272*1285115cSWilliam A. Kennington III     std::string meminfoBuffer = readFileIntoString("/proc/meminfo");
273*1285115cSWilliam A. Kennington III 
274*1285115cSWilliam A. Kennington III     {
275*1285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcMemoryMetric m;
276*1285115cSWilliam A. Kennington III 
277*1285115cSWilliam A. Kennington III         std::string_view sv(meminfoBuffer.data());
278*1285115cSWilliam A. Kennington III         // MemAvailable
279*1285115cSWilliam A. Kennington III         int value;
280*1285115cSWilliam A. Kennington III         bool ok = parseMeminfoValue(sv, "MemAvailable:", value);
281*1285115cSWilliam A. Kennington III         if (ok)
282*1285115cSWilliam A. Kennington III         {
283*1285115cSWilliam A. Kennington III             m.set_mem_available(value);
284*1285115cSWilliam A. Kennington III         }
285*1285115cSWilliam A. Kennington III 
286*1285115cSWilliam A. Kennington III         ok = parseMeminfoValue(sv, "Slab:", value);
287*1285115cSWilliam A. Kennington III         if (ok)
288*1285115cSWilliam A. Kennington III         {
289*1285115cSWilliam A. Kennington III             m.set_slab(value);
290*1285115cSWilliam A. Kennington III         }
291*1285115cSWilliam A. Kennington III 
292*1285115cSWilliam A. Kennington III         ok = parseMeminfoValue(sv, "KernelStack:", value);
293*1285115cSWilliam A. Kennington III         if (ok)
294*1285115cSWilliam A. Kennington III         {
295*1285115cSWilliam A. Kennington III             m.set_kernel_stack(value);
296*1285115cSWilliam A. Kennington III         }
297*1285115cSWilliam A. Kennington III 
298*1285115cSWilliam A. Kennington III         *(snapshot.mutable_memory_metric()) = m;
299*1285115cSWilliam A. Kennington III     }
300*1285115cSWilliam A. Kennington III 
301*1285115cSWilliam A. Kennington III     // Uptime
302*1285115cSWilliam A. Kennington III     std::string uptimeBuffer = readFileIntoString("/proc/uptime");
303*1285115cSWilliam A. Kennington III     double uptime = 0, idleProcessTime = 0;
304*1285115cSWilliam A. Kennington III     if (parseProcUptime(uptimeBuffer, uptime, idleProcessTime))
305*1285115cSWilliam A. Kennington III     {
306*1285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcUptimeMetric m1;
307*1285115cSWilliam A. Kennington III         m1.set_uptime(uptime);
308*1285115cSWilliam A. Kennington III         m1.set_idle_process_time(idleProcessTime);
309*1285115cSWilliam A. Kennington III         *(snapshot.mutable_uptime_metric()) = m1;
310*1285115cSWilliam A. Kennington III     }
311*1285115cSWilliam A. Kennington III     else
312*1285115cSWilliam A. Kennington III     {
313*1285115cSWilliam A. Kennington III         log<level::ERR>("Error parsing /proc/uptime");
314*1285115cSWilliam A. Kennington III     }
315*1285115cSWilliam A. Kennington III 
316*1285115cSWilliam A. Kennington III     // Storage space
317*1285115cSWilliam A. Kennington III     struct statvfs fiData;
318*1285115cSWilliam A. Kennington III     if ((statvfs("/", &fiData)) < 0)
319*1285115cSWilliam A. Kennington III     {
320*1285115cSWilliam A. Kennington III         log<level::ERR>("Could not call statvfs");
321*1285115cSWilliam A. Kennington III     }
322*1285115cSWilliam A. Kennington III     else
323*1285115cSWilliam A. Kennington III     {
324*1285115cSWilliam A. Kennington III         uint64_t kib = (fiData.f_bsize * fiData.f_bfree) / 1024;
325*1285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcDiskSpaceMetric m2;
326*1285115cSWilliam A. Kennington III         m2.set_rwfs_kib_available(static_cast<int>(kib));
327*1285115cSWilliam A. Kennington III         *(snapshot.mutable_storage_space_metric()) = m2;
328*1285115cSWilliam A. Kennington III     }
329*1285115cSWilliam A. Kennington III 
330*1285115cSWilliam A. Kennington III     // The next metrics require a sane ticks_per_sec value, typically 100 on
331*1285115cSWilliam A. Kennington III     // the BMC. In the very rare circumstance when it's 0, exit early and return
332*1285115cSWilliam A. Kennington III     // a partially complete snapshot (no process).
333*1285115cSWilliam A. Kennington III     ticksPerSec = getTicksPerSec();
334*1285115cSWilliam A. Kennington III 
335*1285115cSWilliam A. Kennington III     // FD stat
336*1285115cSWilliam A. Kennington III     *(snapshot.mutable_fdstat_metric()) = getFdStatList();
337*1285115cSWilliam A. Kennington III 
338*1285115cSWilliam A. Kennington III     if (ticksPerSec == 0)
339*1285115cSWilliam A. Kennington III     {
340*1285115cSWilliam A. Kennington III         log<level::ERR>("ticksPerSec is 0, skipping the process list metric");
341*1285115cSWilliam A. Kennington III         serializeSnapshotToArray(snapshot);
342*1285115cSWilliam A. Kennington III         done = true;
343*1285115cSWilliam A. Kennington III         return;
344*1285115cSWilliam A. Kennington III     }
345*1285115cSWilliam A. Kennington III 
346*1285115cSWilliam A. Kennington III     // Proc stat
347*1285115cSWilliam A. Kennington III     *(snapshot.mutable_procstat_metric()) = getProcStatList();
348*1285115cSWilliam A. Kennington III 
349*1285115cSWilliam A. Kennington III     // String table
350*1285115cSWilliam A. Kennington III     std::vector<std::string_view> strings(stringTable.size());
351*1285115cSWilliam A. Kennington III     for (const auto& [s, i] : stringTable)
352*1285115cSWilliam A. Kennington III     {
353*1285115cSWilliam A. Kennington III         strings[i] = s;
354*1285115cSWilliam A. Kennington III     }
355*1285115cSWilliam A. Kennington III 
356*1285115cSWilliam A. Kennington III     bmcmetrics::metricproto::BmcStringTable st;
357*1285115cSWilliam A. Kennington III     for (size_t i = 0; i < strings.size(); ++i)
358*1285115cSWilliam A. Kennington III     {
359*1285115cSWilliam A. Kennington III         bmcmetrics::metricproto::BmcStringTable::StringEntry entry;
360*1285115cSWilliam A. Kennington III         entry.set_value(strings[i].data());
361*1285115cSWilliam A. Kennington III         *(st.add_entries()) = entry;
362*1285115cSWilliam A. Kennington III     }
363*1285115cSWilliam A. Kennington III     *(snapshot.mutable_string_table()) = st;
364*1285115cSWilliam A. Kennington III 
365*1285115cSWilliam A. Kennington III     // Save to buffer
366*1285115cSWilliam A. Kennington III     serializeSnapshotToArray(snapshot);
367*1285115cSWilliam A. Kennington III     done = true;
368*1285115cSWilliam A. Kennington III }
369*1285115cSWilliam A. Kennington III 
370*1285115cSWilliam A. Kennington III // BmcBlobSessionStat (9) but passing meta as reference instead of pointer,
371*1285115cSWilliam A. Kennington III // since the metadata must not be null at this point.
372*1285115cSWilliam A. Kennington III bool BmcHealthSnapshot::stat(blobs::BlobMeta& meta)
373*1285115cSWilliam A. Kennington III {
374*1285115cSWilliam A. Kennington III     if (!done)
375*1285115cSWilliam A. Kennington III     {
376*1285115cSWilliam A. Kennington III         // Bits 8~15 are blob-specific state flags.
377*1285115cSWilliam A. Kennington III         // For this blob, bit 8 is set when metric collection is still in
378*1285115cSWilliam A. Kennington III         // progress.
379*1285115cSWilliam A. Kennington III         meta.blobState |= (1 << 8);
380*1285115cSWilliam A. Kennington III     }
381*1285115cSWilliam A. Kennington III     else
382*1285115cSWilliam A. Kennington III     {
383*1285115cSWilliam A. Kennington III         meta.blobState = 0;
384*1285115cSWilliam A. Kennington III         meta.blobState = blobs::StateFlags::open_read;
385*1285115cSWilliam A. Kennington III         meta.size = pbDump.size();
386*1285115cSWilliam A. Kennington III     }
387*1285115cSWilliam A. Kennington III     return true;
388*1285115cSWilliam A. Kennington III }
389*1285115cSWilliam A. Kennington III 
390*1285115cSWilliam A. Kennington III std::string_view BmcHealthSnapshot::read(uint32_t offset,
391*1285115cSWilliam A. Kennington III                                          uint32_t requestedSize)
392*1285115cSWilliam A. Kennington III {
393*1285115cSWilliam A. Kennington III     uint32_t size = static_cast<uint32_t>(pbDump.size());
394*1285115cSWilliam A. Kennington III     if (offset >= size)
395*1285115cSWilliam A. Kennington III     {
396*1285115cSWilliam A. Kennington III         return {};
397*1285115cSWilliam A. Kennington III     }
398*1285115cSWilliam A. Kennington III     return std::string_view(pbDump.data() + offset,
399*1285115cSWilliam A. Kennington III                             std::min(requestedSize, size - offset));
400*1285115cSWilliam A. Kennington III }
401*1285115cSWilliam A. Kennington III 
402*1285115cSWilliam A. Kennington III int BmcHealthSnapshot::getStringID(const std::string_view s)
403*1285115cSWilliam A. Kennington III {
404*1285115cSWilliam A. Kennington III     int ret = 0;
405*1285115cSWilliam A. Kennington III     auto itr = stringTable.find(s.data());
406*1285115cSWilliam A. Kennington III     if (itr == stringTable.end())
407*1285115cSWilliam A. Kennington III     {
408*1285115cSWilliam A. Kennington III         stringTable[s.data()] = stringId;
409*1285115cSWilliam A. Kennington III         ret = stringId;
410*1285115cSWilliam A. Kennington III         ++stringId;
411*1285115cSWilliam A. Kennington III     }
412*1285115cSWilliam A. Kennington III     else
413*1285115cSWilliam A. Kennington III     {
414*1285115cSWilliam A. Kennington III         ret = itr->second;
415*1285115cSWilliam A. Kennington III     }
416*1285115cSWilliam A. Kennington III     return ret;
417*1285115cSWilliam A. Kennington III }
418*1285115cSWilliam A. Kennington III 
419*1285115cSWilliam A. Kennington III } // namespace metric_blob