4#include "Stroika/Frameworks/StroikaPreComp.h"
9#if qStroika_Foundation_Common_Platform_POSIX
11#include <sys/statvfs.h>
14#elif qStroika_Foundation_Common_Platform_Windows
19#if qStroika_Foundation_Common_Platform_Linux
20#include <sys/sysmacros.h>
24#include "Stroika/Foundation/Characters/FloatConversion.h"
25#include "Stroika/Foundation/Characters/String2Int.h"
27#include "Stroika/Foundation/Containers/Mapping.h"
28#include "Stroika/Foundation/Containers/Sequence.h"
29#include "Stroika/Foundation/Containers/Set.h"
34#include "Stroika/Foundation/Execution/Exceptions.h"
35#include "Stroika/Foundation/Execution/ProcessRunner.h"
42#include "Stroika/Foundation/Streams/MemoryStream.h"
46#include "Filesystem.h"
53using namespace Stroika::Foundation::Memory;
54using namespace Stroika::Foundation::Streams;
56using namespace Stroika::Frameworks;
57using namespace Stroika::Frameworks::SystemPerformance;
59using Characters::String2Int;
61using Instruments::Filesystem::BlockDeviceKind;
63using Instruments::Filesystem::DynamicDiskIDType;
67using Instruments::Filesystem::MountedFilesystemNameType;
85 double QL = *fQLength;
87 double pct{100.0 * (QL / (1 + QL))};
88 Require (0 <= pct and pct <= 100.0);
95#ifndef qUseWMICollectionSupport_
96#define qUseWMICollectionSupport_ qStroika_Foundation_Common_Platform_Windows
99#if qUseWMICollectionSupport_
146#if qUseWMICollectionSupport_
147 const String kDiskReadBytesPerSec_{
"Disk Read Bytes/sec"sv};
148 const String kDiskWriteBytesPerSec_{
"Disk Write Bytes/sec"sv};
149 const String kDiskReadsPerSec_{
"Disk Reads/sec"sv};
150 const String kDiskWritesPerSec_{
"Disk Writes/sec"sv};
151 const String kPctDiskReadTime_{
"% Disk Read Time"sv};
152 const String kPctDiskWriteTime_{
"% Disk Write Time"sv};
153 const String kAveDiskReadQLen_{
"Avg. Disk Read Queue Length"sv};
154 const String kAveDiskWriteQLen_{
"Avg. Disk Write Queue Length"sv};
155 const String kPctIdleTime_{
"% Idle Time"sv};
157 constexpr bool kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_{
false};
163 constexpr bool kUsePctIdleIimeForAveQLen_{
true};
168 template <
typename CONTEXT>
172#if qStroika_Foundation_Common_Platform_POSIX
178 "ext2"sv,
"ext3"sv,
"ext4"sv,
"xfs"sv,
"jfs2"sv,
181 "autofs"sv,
"binfmt_misc"sv,
"cgroup"sv,
"configfs"sv,
"debugfs"sv,
"devpts"sv,
182 "devtmpfs"sv,
"fusectl"sv,
"fuse.gvfsd-fuse"sv,
"hugetlbfs"sv,
"mqueue"sv,
184 "pstore"sv,
"proc"sv,
"rpc_pipefs"sv,
"securityfs"sv,
"selinuxfs"sv,
"sunrpc"sv,
185 "sysfs"sv,
"usbfs"sv,
192 for (
auto vi = volumes->
begin (); vi != volumes->
end (); ++vi) {
198 if (kRealDiskFS.Contains (fstype)) {
199 val2Update.fDeviceKind = BlockDeviceKind::eLocalDisk;
202 else if (kNetworkFS_.Contains (fstype)) {
203 val2Update.fDeviceKind = BlockDeviceKind::eNetworkDrive;
206 else if (fstype ==
"tmpfs"_k) {
207 val2Update.fDeviceKind = BlockDeviceKind::eTemporaryFiles;
210 else if (fstype ==
"iso9660"_k) {
211 val2Update.fDeviceKind = BlockDeviceKind::eReadOnlyEjectable;
214 else if (kSysFSList_.Contains (fstype)) {
215 val2Update.fDeviceKind = BlockDeviceKind::eSystemInformation;
219 volumes->
Update (vi, val2Update, &vi);
226#if qStroika_Foundation_Common_Platform_Linux
230 double fTimeSpentReading;
231 double fReadsCompleted;
232 double fSectorsWritten;
233 double fTimeSpentWriting;
234 double fWritesCompleted;
235 double fWeightedTimeInQSeconds;
239 optional<Mapping<dev_t, PerfStats_>> fDiskPerfStats_;
242 struct InstrumentRep_Linux_ : InstrumentRepBase_<_Context> {
244 using InstrumentRepBase_<_Context>::InstrumentRepBase_;
246 nonvirtual
Info _InternalCapture ()
248#if USE_NOISY_TRACE_IN_THIS_MODULE_
253 constexpr bool kUseProcFSForMounts_{
true};
254 if (kUseProcFSForMounts_) {
255 results.fMountedFilesystems = ReadVolumesAndUsageFromProcMountsAndstatvfs_ ();
258 results.fMountedFilesystems = RunDF_ ();
260 ApplyDiskTypes_ (&results.fMountedFilesystems);
261 if (not _fOptions.fIncludeTemporaryDevices or not _fOptions.fIncludeSystemDevices) {
263 if (not _fOptions.fIncludeTemporaryDevices and i.fValue.fDeviceKind == BlockDeviceKind::eTemporaryFiles) {
264 results.fMountedFilesystems.Remove (i.fKey);
266 else if (not not _fOptions.fIncludeSystemDevices and i.fValue.fDeviceKind == BlockDeviceKind::eSystemInformation) {
267 results.fMountedFilesystems.Remove (i.fKey);
271 if (_fOptions.fIOStatistics) {
272 ReadAndApplyProcFS_diskstats_ (&results.fMountedFilesystems);
274 _NoteCompletedCapture ();
284 String deviceName = (not mi.fDevicePaths.has_value () or mi.fDevicePaths->empty ()) ?
String{} :
String{mi.fDevicePaths->
Nth (0)};
285 if (not deviceName.empty ()) {
289 UpdateVolumeInfo_statvfs_ (mi.fMountedOn, &vi);
290 result.
Add (mi.fMountedOn, vi);
299 struct statvfs sbuf{};
300 if (::statvfs (mountedOnName.c_str (), &sbuf) == 0) {
301 uint64_t diskSize = sbuf.f_bsize * sbuf.f_blocks;
302 v->fSizeInBytes = diskSize;
304 v->fUsedSizeInBytes = diskSize - sbuf.f_bsize * sbuf.f_bfree;
307#if USE_NOISY_TRACE_IN_THIS_MODULE_
308 DbgTrace (
"statvfs ({}) return error: errno={}"_f, mountedOnName, errno);
322 if (_fContext.load ()->fDiskPerfStats_) {
324 size_t i = devNameLessSlashes.
rfind (
'/');
325 if (i != string::npos) {
326 devNameLessSlashes = devNameLessSlashes.
SubString (i + 1);
332 useDevT = sbuf.st_rdev;
338 optional<PerfStats_> oOld = _fContext.load ()->fDiskPerfStats_->Lookup (useDevT);
339 optional<PerfStats_> oNew = diskStats.
Lookup (useDevT);
340 if (oOld.has_value () and oNew.has_value ()) {
341 unsigned int sectorSizeTmpHack = GetSectorSize_ (devNameLessSlashes);
343 readStats.fBytesTransferred = (oNew->fSectorsRead - oOld->fSectorsRead) * sectorSizeTmpHack;
344 readStats.fTotalTransfers = oNew->fReadsCompleted - oOld->fReadsCompleted;
345 if (timeSinceLastMeasure > _fOptions.fMinimumAveragingInterval) {
346 readStats.fQLength = (oNew->fTimeSpentReading - oOld->fTimeSpentReading) / timeSinceLastMeasure.count ();
350 writeStats.fBytesTransferred = (oNew->fSectorsWritten - oOld->fSectorsWritten) * sectorSizeTmpHack;
351 writeStats.fTotalTransfers = oNew->fWritesCompleted - oOld->fWritesCompleted;
352 if (timeSinceLastMeasure > _fOptions.fMinimumAveragingInterval) {
353 writeStats.fQLength = (oNew->fTimeSpentWriting - oOld->fTimeSpentWriting) / timeSinceLastMeasure.count ();
357 combinedStats.fBytesTransferred = *readStats.fBytesTransferred + *writeStats.fBytesTransferred;
358 combinedStats.fTotalTransfers = *readStats.fTotalTransfers + *writeStats.fTotalTransfers;
359 combinedStats.fQLength = *readStats.fQLength + *writeStats.fQLength;
362 vi.fWriteIOStats = writeStats;
364 if (timeSinceLastMeasure > _fOptions.fMinimumAveragingInterval) {
365 combinedStats.fQLength =
366 ((oNew->fWeightedTimeInQSeconds - oOld->fWeightedTimeInQSeconds) / timeSinceLastMeasure.count ());
368 vi.fCombinedIOStats = combinedStats;
372 volumes->
Update (i, vi, &i);
374 _fContext.rwget ().rwref ()->fDiskPerfStats_ = diskStats;
377 DbgTrace (
"Exception gathering procfs disk io stats: {}"_f, current_exception ());
382 static optional<filesystem::path> GetSysBlockDirPathForDevice_ (
const String& deviceName)
384 Require (not deviceName.empty ());
385 Require (not deviceName.
Contains (
"/"sv));
391 static const filesystem::path kSysBlock_{
"/sys/block"sv};
392 filesystem::path tmp{kSysBlock_ / deviceName.
As<filesystem::path> ()};
397 tmp = kSysBlock_ / deviceName.
SubString (0, -1).
As<filesystem::path> ();
405 nonvirtual uint32_t GetSectorSize_ (
const String& deviceName)
407 auto o = _fContext.load ()->fDeviceName2SectorSizeMap_.Lookup (deviceName);
408 if (not o.has_value ()) {
409 if (optional<filesystem::path> blockDeviceInfoPath = GetSysBlockDirPathForDevice_ (deviceName)) {
410 filesystem::path fn = *blockDeviceInfoPath /
"queue/hw_sector_size";
412 o = String2Int<uint32_t> (
416 _fContext.rwget ().rwref ()->fDeviceName2SectorSizeMap_.Add (deviceName, *o);
419 DbgTrace (
"Unknown error reading {}"_f, fn);
424 return o.value_or (512);
434 std::exception_ptr runException;
436 pr.Run (
nullptr, useStdOut);
439 runException = current_exception ();
443 bool skippedHeader =
false;
445 if (not skippedHeader) {
446 skippedHeader =
true;
457 if (not d.empty () and d !=
"none"sv) {
462 double szInBytes = Characters::FloatConversion::ToFloat<double> (l[1]) * 1024;
463 if (not std::isnan (szInBytes) and not std::isinf (szInBytes)) {
464 v.fSizeInBytes = szInBytes;
468 double usedSizeInBytes = FloatConversion::ToFloat<double> (l[2]) * 1024;
469 if (not std::isnan (usedSizeInBytes) and not std::isinf (usedSizeInBytes)) {
470 v.fUsedSizeInBytes = usedSizeInBytes;
473 if (v.fSizeInBytes and v.fUsedSizeInBytes) {
476 result.
Add (l[5].Trim ().As<filesystem::path> (), v);
479 if (runException and result.
empty ()) {
480 Execution::ReThrow (runException);
493 ProcessRunner pr{includeFSTypes ?
"/bin/df -k -T"sv :
"/bin/df -k"sv};
495 std::exception_ptr runException;
497 pr.Run (
nullptr, useStdOut);
500 runException = current_exception ();
504 bool skippedHeader =
false;
506 if (not skippedHeader) {
507 skippedHeader =
true;
511 if (l.
size () < (includeFSTypes ? 7 : 6)) {
516 if (includeFSTypes) {
521 if (not d.empty () and d !=
"none"_k) {
525 v.fSizeInBytes = FloatConversion::ToFloat<double> (l[includeFSTypes ? 2 : 1]) * 1024;
526 v.fUsedSizeInBytes = FloatConversion::ToFloat<double> (l[includeFSTypes ? 3 : 2]) * 1024;
528 result.
Add (l[includeFSTypes ? 6 : 5].Trim ().As<filesystem::path> (), v);
531 if (runException and result.
empty ()) {
532 Execution::ReThrow (runException);
539 return RunDF_ (
true);
542 return RunDF_ (
false);
551 static const filesystem::path kProcMemInfoFileName_{
"/proc/diskstats"sv};
554 reader.ReadMatrix (IO::FileSystem::FileInputStream::New (kProcMemInfoFileName_, IO::FileSystem::FileInputStream::eNotSeekable))) {
555#if USE_NOISY_TRACE_IN_THIS_MODULE_
556 DbgTrace (L
"***in Instruments::Filesystem::ReadProcFS_diskstats_ linesize=%d, line[0]=%s", line.size (),
557 line.empty () ? L
"" : line[0].c_str ());
572 if (line.size () >= 13) {
573 String majorDevNumber = line[1 - 1];
574 String minorDevNumber = line[2 - 1];
575 String devName = line[3 - 1];
576 String readsCompleted = line[4 - 1];
577 String sectorsRead = line[6 - 1];
578 String timeSpentReadingMS = line[7 - 1];
579 String writesCompleted = line[8 - 1];
580 String sectorsWritten = line[10 - 1];
581 String timeSpentWritingMS = line[11 - 1];
582 constexpr bool kAlsoReadQLen_{
true};
583 optional<double> weightedTimeInQSeconds;
584 if (kAlsoReadQLen_) {
585 optional<filesystem::path> sysBlockInfoPath = GetSysBlockDirPathForDevice_ (devName);
586 if (sysBlockInfoPath) {
587 for (
const Sequence<String>& ll : reader.ReadMatrix (IO::FileSystem::FileInputStream::New (
588 *sysBlockInfoPath /
"stat", IO::FileSystem::FileInputStream::eNotSeekable))) {
589 if (ll.size () >= 11) {
596 result.
Add (makedev (String2Int<unsigned int> (majorDevNumber), String2Int<unsigned int> (minorDevNumber)),
609#if qStroika_Foundation_Common_Platform_Windows
613#if qUseWMICollectionSupport_
615 WMICollector fLogicalDiskWMICollector_{
"LogicalDisk"sv,
617 { kDiskReadBytesPerSec_,
618 kDiskWriteBytesPerSec_,
621 (kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_ ? kPctDiskReadTime_ : kAveDiskReadQLen_),
622 (kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_ ? kPctDiskWriteTime_ : kAveDiskWriteQLen_),
627 struct InstrumentRep_Windows_ : InstrumentRepBase_<_Context> {
628 using InstrumentRepBase_<_Context>::InstrumentRepBase_;
630 nonvirtual
Info _InternalCapture ()
632#if USE_NOISY_TRACE_IN_THIS_MODULE_
642 di.fSizeInBytes = pd.fSizeInBytes;
643 result.
fDisks.Add (pd.fDeviceName, di);
646#if qUseWMICollectionSupport_
647 auto contextLock = scoped_lock{_fContext};
648 auto contextPtr = _fContext.rwget ().rwref ();
649 optional<Time::DurationSeconds> timeCollecting;
651 optional<Time::TimePointSeconds> timeOfPrevCollection = contextPtr->fLogicalDiskWMICollector_.GetTimeOfLastCollection ();
652 if (_fOptions.fIOStatistics) {
653 contextPtr->fLogicalDiskWMICollector_.Collect ();
655 if (timeOfPrevCollection) {
657 timeCollecting = *contextPtr->fLogicalDiskWMICollector_.GetTimeOfLastCollection () - *timeOfPrevCollection;
666 if (not physDrives.
empty ()) {
667 v.fOnPhysicalDrive = mfinfo.fDevicePaths;
674 switch (::GetDriveType (v.
fVolumeID->AsSDKString ().c_str ())) {
675 case DRIVE_REMOVABLE:
676 v.fDeviceKind = BlockDeviceKind::eRemovableDisk;
679 v.fDeviceKind = BlockDeviceKind::eLocalDisk;
682 v.fDeviceKind = BlockDeviceKind::eNetworkDrive;
685 v.fDeviceKind = BlockDeviceKind::eTemporaryFiles;
688 v.fDeviceKind = BlockDeviceKind::eReadOnlyEjectable;
695 ULARGE_INTEGER freeBytesAvailable{};
696 ULARGE_INTEGER totalNumberOfBytes{};
697 ULARGE_INTEGER totalNumberOfFreeBytes{};
698 [[maybe_unused]] DWORD ignored =
699 ::GetDiskFreeSpaceEx (mfinfo.fMountedOn.c_str (), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes);
700 v.fSizeInBytes = totalNumberOfBytes.QuadPart;
701 v.fUsedSizeInBytes = *v.fSizeInBytes - freeBytesAvailable.QuadPart;
703#if qUseWMICollectionSupport_
704 auto safePctInUse2QL_ = [] (
double pctInUse) {
707 pctInUse = clamp<double> (pctInUse, 0, 1);
708 return pctInUse / (1 - pctInUse);
710 if (_fOptions.fIOStatistics) {
712 contextPtr->fLogicalDiskWMICollector_.AddInstancesIf (wmiInstanceName);
715 if (timeCollecting) {
716 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kDiskReadBytesPerSec_)) {
717 readStats.fBytesTransferred = *o * timeCollecting->count ();
719 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kDiskReadsPerSec_)) {
720 readStats.fTotalTransfers = *o * timeCollecting->count ();
723 if (kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_) {
724 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kPctDiskReadTime_)) {
725 readStats.fInUsePercent = *o;
726 readStats.fQLength = safePctInUse2QL_ (*o);
730 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kAveDiskReadQLen_)) {
731 readStats.fInUsePercent = *o;
732 readStats.fQLength = *o;
737 if (timeCollecting) {
738 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kDiskWriteBytesPerSec_)) {
739 writeStats.fBytesTransferred = *o * timeCollecting->count ();
741 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kDiskWritesPerSec_)) {
742 writeStats.fTotalTransfers = *o * timeCollecting->count ();
745 if (kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_) {
746 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kPctDiskWriteTime_)) {
747 writeStats.fInUsePercent = *o;
748 writeStats.fQLength = safePctInUse2QL_ (*o);
752 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kAveDiskWriteQLen_)) {
753 writeStats.fInUsePercent = *o;
754 writeStats.fQLength = *o;
759 Memory::AccumulateIf (&combinedStats.fBytesTransferred, writeStats.fBytesTransferred);
760 Memory::AccumulateIf (&combinedStats.fTotalTransfers, writeStats.fTotalTransfers);
761 Memory::AccumulateIf (&combinedStats.fQLength, writeStats.fQLength);
762 Memory::AccumulateIf (&combinedStats.fInUsePercent, writeStats.fInUsePercent);
763 if (readStats.fInUsePercent and writeStats.fInUsePercent) {
764 combinedStats.fInUsePercent = *combinedStats.fInUsePercent / 2;
767 if (kUsePctIdleIimeForAveQLen_) {
768 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kPctIdleTime_)) {
769 double aveCombinedQLen = safePctInUse2QL_ (100.0 - *o);
770 if (readStats.fQLength and writeStats.fQLength and *combinedStats.fQLength > 0) {
773 double correction = aveCombinedQLen / *combinedStats.fQLength;
774 Memory::AccumulateIf (&readStats.fQLength, correction, std::multiplies{});
775 Memory::AccumulateIf (&writeStats.fQLength, correction, std::multiplies{});
777 combinedStats.fQLength = aveCombinedQLen;
781 if (readStats.fBytesTransferred or readStats.fTotalTransfers or readStats.fQLength) {
784 if (writeStats.fBytesTransferred or writeStats.fTotalTransfers or writeStats.fQLength) {
785 v.fWriteIOStats = writeStats;
787 if (combinedStats.fBytesTransferred or combinedStats.fTotalTransfers or combinedStats.fQLength) {
788 v.fCombinedIOStats = combinedStats;
793 result.fMountedFilesystems.Add (mfinfo.fMountedOn, v);
795#if qUseWMICollectionSupport_
796 _NoteCompletedCapture (contextPtr->fLogicalDiskWMICollector_.GetTimeOfLastCollection ().value_or (Time::GetTickCount ()));
798 _NoteCompletedCapture ();
806 static optional<String> GetDeviceNameForVolumneName_ (
const String& volumeName)
822 tmp[tmp.
length () - 1] != L
'\\') {
829 WCHAR deviceName[MAX_PATH] = L
"";
830 if (::QueryDosDeviceW (tmp.
c_str (), deviceName, ARRAYSIZE (deviceName)) != 0) {
831 return String{deviceName};
845 struct FilesystemInstrumentRep_
846#if qStroika_Foundation_Common_Platform_Linux
847 : InstrumentRep_Linux_
848#elif qStroika_Foundation_Common_Platform_Windows
849 : InstrumentRep_Windows_
851 : InstrumentRepBase_<SystemPerformance::Support::Context>
854#if qStroika_Foundation_Common_Platform_Linux
855 using inherited = InstrumentRep_Linux_;
856#elif qStroika_Foundation_Common_Platform_Windows
857 using inherited = InstrumentRep_Windows_;
859 using inherited = InstrumentRepBase_<SystemPerformance::Support::Context>;
861 FilesystemInstrumentRep_ (
const Options& options,
const shared_ptr<_Context>& context = Memory::MakeSharedPtr<_Context> ())
862 : inherited{options, context}
864 Require (_fOptions.fMinimumAveragingInterval > 0s);
871 results.fMeasurements.Add (m);
876 return Do_Capture_Raw<Info> ([
this] () {
return _InternalCapture (); }, outMeasuredAt);
878 virtual unique_ptr<IRep> Clone ()
const override
880 return make_unique<FilesystemInstrumentRep_> (_fOptions, _fContext.load ());
882 nonvirtual
Info _InternalCapture ()
884 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
886#if qStroika_Foundation_Common_Platform_Linux or qStroika_Foundation_Common_Platform_Windows
887 Info result = inherited::_InternalCapture ();
891 if (_fOptions.fEstimateFilesystemStatsFromDiskStatsIfHelpful) {
892 result.fMountedFilesystems = ApplyDiskStatsToMissingFileSystemStats_ (result.
fDisks, result.fMountedFilesystems);
901#if USE_NOISY_TRACE_IN_THIS_MODULE_
908 using WeightingStat2UseType = double;
912 if (disksForFS.
size () > 0) {
913 WeightingStat2UseType weightForFS =
NullCoalesce (NullCoalesce (i.fValue.fCombinedIOStats).fBytesTransferred);
914 weightForFS /= disksForFS.
size ();
915 for (
const DynamicDiskIDType& di : disksForFS) {
916 totalWeights.
Add (di, totalWeights.
LookupValue (di) + weightForFS);
920#if USE_NOISY_TRACE_IN_THIS_MODULE_
923 for (
const auto& i : totalWeights) {
924 DbgTrace (
"Disk '{}' weight {}"_f, i.fKey.c_str (), i.fValue);
939 if (totalWeights.
size () >= 1) {
943 if (disksForFS.
size () > 0) {
944 WeightingStat2UseType weightForFS =
NullCoalesce (NullCoalesce (i.fValue.fCombinedIOStats).fBytesTransferred);
945 weightForFS /= disksForFS.
size ();
947 bool computeInuse = not cumStats.fInUsePercent.has_value ();
948 bool computeQLen = not cumStats.fQLength.has_value ();
949 bool computeTotalXFers = not cumStats.fTotalTransfers.has_value ();
951 for (
const DynamicDiskIDType& di : disksForFS) {
953 if (weightForFS > 0) {
954 double scaleFactor = weightForFS / totalWeights.
LookupValue (di);
956 scaleFactor = clamp (scaleFactor, 0.0, 1.0);
957 if (computeInuse and diskIOStats.fInUsePercent) {
958 Memory::AccumulateIf<double> (&cumStats.fInUsePercent, *diskIOStats.fInUsePercent * scaleFactor);
960 if (computeQLen and diskIOStats.fInUsePercent) {
961 Memory::AccumulateIf<double> (&cumStats.fQLength, *diskIOStats.fQLength * scaleFactor);
963 if (computeTotalXFers and diskIOStats.fTotalTransfers) {
964 Memory::AccumulateIf<double> (&cumStats.fTotalTransfers, *diskIOStats.fTotalTransfers * scaleFactor);
968#if USE_NOISY_TRACE_IN_THIS_MODULE_
970 DbgTrace (
"Adjusted fInUsePCT for filesystem '{}' is {}"_f, i.fKey.c_str (),
NullCoalesce (cumStats.fInUsePercent));
973 DbgTrace (
"Adjusted fQLength for filesystem '{}' is {}"_f, i.fKey.c_str (),
NullCoalesce (cumStats.fQLength));
976 mfi.fCombinedIOStats = cumStats;
978 newFilessytems.
Add (i.fKey, mfi);
980 return newFilessytems;
996 mapper.
Add (mapper.MakeCommonSerializer_NamedEnumerations<BlockDeviceKind> ());
999 {
"Bytes"sv, &IOStatsType::fBytesTransferred},
1000 {
"Q-Length"sv, &IOStatsType::fQLength},
1001 {
"In-Use-%"sv, &IOStatsType::fInUsePercent},
1002 {
"Total-Transfers"sv, &IOStatsType::fTotalTransfers},
1006 {
"Persistence-Volume-ID"sv, &DiskInfoType::fPersistenceVolumeID},
1007 {
"Device-Kind"sv, &DiskInfoType::fDeviceKind},
1008 {
"Size"sv, &DiskInfoType::fSizeInBytes},
1009 {
"Read-IO-Stats"sv, &DiskInfoType::fReadIOStats},
1010 {
"Write-IO-Stats"sv, &DiskInfoType::fWriteIOStats},
1011 {
"Combined-IO-Stats"sv, &DiskInfoType::fCombinedIOStats},
1018 {
"Device-Kind"_k, &MountedFilesystemInfoType::fDeviceKind},
1019 {
"Filesystem-Type"_k, &MountedFilesystemInfoType::fFileSystemType},
1020 {
"Device-Name"_k, &MountedFilesystemInfoType::fDeviceOrVolumeName},
1021 {
"On-Physical-Drives"_k, &MountedFilesystemInfoType::fOnPhysicalDrive},
1022 {
"Volume-ID"_k, &MountedFilesystemInfoType::fVolumeID},
1023 {
"Total-Size"_k, &MountedFilesystemInfoType::fSizeInBytes},
1024 {
"Available-Size"_k, &MountedFilesystemInfoType::fAvailableSizeInBytes},
1025 {
"Used-Size"_k, &MountedFilesystemInfoType::fUsedSizeInBytes},
1026 {
"Read-IO-Stats"_k, &MountedFilesystemInfoType::fReadIOStats},
1027 {
"Write-IO-Stats"_k, &MountedFilesystemInfoType::fWriteIOStats},
1028 {
"Combined-IO-Stats"_k, &MountedFilesystemInfoType::fCombinedIOStats},
1033 {
"Disks"_k, &Info::fDisks},
1034 {
"Mounted-Filesystems"_k, &Info::fMountedFilesystems},
1039Instruments::Filesystem::Instrument::Instrument (
const Options& options)
1041 make_unique<FilesystemInstrumentRep_> (options),
1042 {kMountedVolumeUsage_},
1057 FilesystemInstrumentRep_* myCap =
dynamic_cast<FilesystemInstrumentRep_*
> (fCaptureRep_.get ());
1059 return myCap->Capture_Raw (measurementTimeOut);
#define RequireNotNull(p)
wstring Capture(const Options &options={})
const OT & NullCoalesce(const OT &l, const OT &r)
return one of l, or r, with first preference for which is engaged, and second preference for left-to-...
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual bool Contains(Character c, CompareOptions co=eWithCase) const
nonvirtual size_t length() const noexcept
nonvirtual tuple< const wchar_t *, wstring_view > c_str(Memory::StackBuffer< wchar_t > *possibleBackingStore) const
nonvirtual size_t rfind(Character c) const
nonvirtual String SubString(SZ from) const
nonvirtual String RTrim(bool(*shouldBeTrimmed)(Character)=Character::IsWhitespace) const
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
nonvirtual void Update(const Iterator< value_type > &i, ArgByValueType< mapped_type > newValue, Iterator< value_type > *nextI=nullptr)
nonvirtual mapped_type LookupValue(ArgByValueType< key_type > key, ArgByValueType< mapped_type > defaultValue=mapped_type{}) const
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
An Atom is like a String, except that its much cheaper to copy/store/compare, and the semantics of co...
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
nonvirtual void AddClass(const Traversal::Iterable< StructFieldInfo > &fieldDescriptions, const ClassMapperOptions< CLASS > &mapperOptions={})
nonvirtual void AddCommonType(ARGS &&... args)
nonvirtual VariantValue FromObject(const T &from) const
nonvirtual void Add(const TypeMappingDetails &s)
This COULD be easily used to read CSV files, or tab-delimited files, for example.
nonvirtual String WriteAsString(const VariantValue &v) const
Run the given command, and optionally support stdin/stdout/stderr as streams (either sync with Run,...
nonvirtual bool Access(const filesystem::path &fileFullPath, AccessMode accessMode=AccessMode::eRead) const noexcept
nonvirtual size_t size() const
Returns the number of items contained.
nonvirtual T Nth(ptrdiff_t n) const
Find the Nth element of the Iterable<>
nonvirtual Iterator< T > begin() const
Support for ranged for, and STL syntax in general.
nonvirtual bool empty() const
Returns true iff size() == 0.
static constexpr default_sentinel_t end() noexcept
Support for ranged for, and STL syntax in general.
An Iterator<T> is a copyable object which allows traversing the contents of some container....
T ToFloat(span< const CHAR_T > s)
Containers::KeyedCollection< MountedFilesystemType, filesystem::path > GetMountedFilesystems()
Containers::KeyedCollection< DiskInfoType, filesystem::path > GetAvailableDisks()
Ptr New(const InputStream::Ptr< byte > &src, optional< AutomaticCodeCvtFlags > codeCvtFlags={}, optional< SeekableFlag > seekable={}, ReadAhead readAhead=eReadAheadAllowed)
Create an InputStream::Ptr<Character> from the arguments (usually binary source) - which can be used ...