3633
buffer[result] = '\0';
3634
3635
//
3636
- // Format: "cpu user nice system idle iowait irq softirq steal ...". Fields after steal are ignored.
3636
+ // Format: "cpu user nice system idle iowait irq softirq steal ...". The user, nice, system, idle,
3637
+ // and iowait fields are required; irq, softirq, and steal are optional and any fields after steal
3638
+ // are ignored.
3639
//
3640
3639
- if (strncmp(buffer, "cpu ", 4) != 0)
3641
+ static const std::regex cpuLine{R"(^cpu[ \t]+(\d+)[ \t]+(\d+)[ \t]+(\d+)[ \t]+(\d+)[ \t]+(\d+)(?:[ \t]+(\d+))?(?:[ \t]+(\d+))?(?:[ \t]+(\d+))?)"};
3642
+ std::cmatch match;
3643
+ if (!std::regex_search(buffer, match, cpuLine))
3644
{
3641
- LOG_ERROR("/proc/stat first line missing cpu label");
3645
+ LOG_ERROR("failed to parse /proc/stat cpu line");
3646
return false;
3647
}
3648
3649
unsigned long long fields[8] = {};
3646
- const char* cursor = buffer + 3;
3647
- int parsed = 0;
3648
- for (; parsed < static_cast<int>(COUNT_OF(fields)); parsed += 1)
3650
+ for (size_t index = 0; index < COUNT_OF(fields); index += 1)
3651
{
3650
- char* end = nullptr;
3651
- const unsigned long long value = strtoull(cursor, &end, 10);
3652
- if (end == cursor)
3652
+ if (match[index + 1].matched)
3653
{
3654
- break;
3654
+ fields[index] = strtoull(match[index + 1].first, nullptr, 10);
3655
}
3656
-
3657
- fields[parsed] = value;
3658
- cursor = end;
3659
- }
3660
-
3661
- if (parsed < 5)
3662
- {
3663
- LOG_ERROR("failed to parse /proc/stat cpu line (parsed {})", parsed);
3664
- return false;
3656
}
3657
3658
Idle = fields[3] + fields[4];
3668
- Busy = 0;
3669
- for (int index = 0; index < parsed; index += 1)
3670
- {
3671
- if (index != 3 && index != 4)
3672
- {
3673
- Busy += fields[index];
3674
- }
3675
- }
3659
+ Busy = fields[0] + fields[1] + fields[2] + fields[5] + fields[6] + fields[7];
3660
3661
return true;
3662
}
3941
}
3942
else if (!droppedThisIdlePeriod)
3943
{
3960
- if (WriteToFile("/proc/sys/vm/drop_caches", "1\n") == 0)
3944
+ //
3945
+ // drop_caches=3 frees the page cache along with reclaimable slab (dentries and
3946
+ // inodes), matching the SReclaimable slab counted by GetReclaimableCacheBytes.
3947
+ //
3948
+
3949
+ if (WriteToFile("/proc/sys/vm/drop_caches", "3\n") == 0)
3950
{
3951
droppedThisIdlePeriod = true;
3952
reclaimed = true;