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"
41#include "Stroika/Foundation/Streams/MemoryStream.h"
45#include "Filesystem.h"
52using namespace Stroika::Foundation::Memory;
53using namespace Stroika::Foundation::Streams;
55using namespace Stroika::Frameworks;
56using namespace Stroika::Frameworks::SystemPerformance;
58using Characters::String2Int;
60using Instruments::Filesystem::BlockDeviceKind;
62using Instruments::Filesystem::DynamicDiskIDType;
66using Instruments::Filesystem::MountedFilesystemNameType;
84 double QL = *fQLength;
86 double pct{100.0 * (QL / (1 + QL))};
87 Require (0 <= pct and pct <= 100.0);
94#ifndef qUseWMICollectionSupport_
95#define qUseWMICollectionSupport_ qStroika_Foundation_Common_Platform_Windows
98#if qUseWMICollectionSupport_
145#if qUseWMICollectionSupport_
146 const String kDiskReadBytesPerSec_{
"Disk Read Bytes/sec"sv};
147 const String kDiskWriteBytesPerSec_{
"Disk Write Bytes/sec"sv};
148 const String kDiskReadsPerSec_{
"Disk Reads/sec"sv};
149 const String kDiskWritesPerSec_{
"Disk Writes/sec"sv};
150 const String kPctDiskReadTime_{
"% Disk Read Time"sv};
151 const String kPctDiskWriteTime_{
"% Disk Write Time"sv};
152 const String kAveDiskReadQLen_{
"Avg. Disk Read Queue Length"sv};
153 const String kAveDiskWriteQLen_{
"Avg. Disk Write Queue Length"sv};
154 const String kPctIdleTime_{
"% Idle Time"sv};
156 constexpr bool kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_{
false};
162 constexpr bool kUsePctIdleIimeForAveQLen_{
true};
167 template <
typename CONTEXT>
171#if qStroika_Foundation_Common_Platform_POSIX
177 "ext2"sv,
"ext3"sv,
"ext4"sv,
"xfs"sv,
"jfs2"sv,
180 "autofs"sv,
"binfmt_misc"sv,
"cgroup"sv,
"configfs"sv,
"debugfs"sv,
"devpts"sv,
181 "devtmpfs"sv,
"fusectl"sv,
"fuse.gvfsd-fuse"sv,
"hugetlbfs"sv,
"mqueue"sv,
183 "pstore"sv,
"proc"sv,
"rpc_pipefs"sv,
"securityfs"sv,
"selinuxfs"sv,
"sunrpc"sv,
184 "sysfs"sv,
"usbfs"sv,
191 for (
auto vi = volumes->
begin (); vi != volumes->
end (); ++vi) {
197 if (kRealDiskFS.Contains (fstype)) {
198 val2Update.fDeviceKind = BlockDeviceKind::eLocalDisk;
201 else if (kNetworkFS_.Contains (fstype)) {
202 val2Update.fDeviceKind = BlockDeviceKind::eNetworkDrive;
205 else if (fstype ==
"tmpfs"_k) {
206 val2Update.fDeviceKind = BlockDeviceKind::eTemporaryFiles;
209 else if (fstype ==
"iso9660"_k) {
210 val2Update.fDeviceKind = BlockDeviceKind::eReadOnlyEjectable;
213 else if (kSysFSList_.Contains (fstype)) {
214 val2Update.fDeviceKind = BlockDeviceKind::eSystemInformation;
218 volumes->
Update (vi, val2Update, &vi);
225#if qStroika_Foundation_Common_Platform_Linux
229 double fTimeSpentReading;
230 double fReadsCompleted;
231 double fSectorsWritten;
232 double fTimeSpentWriting;
233 double fWritesCompleted;
234 double fWeightedTimeInQSeconds;
238 optional<Mapping<dev_t, PerfStats_>> fDiskPerfStats_;
241 struct InstrumentRep_Linux_ : InstrumentRepBase_<_Context> {
243 using InstrumentRepBase_<_Context>::InstrumentRepBase_;
245 nonvirtual
Info _InternalCapture ()
247#if USE_NOISY_TRACE_IN_THIS_MODULE_
252 constexpr bool kUseProcFSForMounts_{
true};
253 if (kUseProcFSForMounts_) {
254 results.fMountedFilesystems = ReadVolumesAndUsageFromProcMountsAndstatvfs_ ();
257 results.fMountedFilesystems = RunDF_ ();
259 ApplyDiskTypes_ (&results.fMountedFilesystems);
260 if (not _fOptions.fIncludeTemporaryDevices or not _fOptions.fIncludeSystemDevices) {
262 if (not _fOptions.fIncludeTemporaryDevices and i.fValue.fDeviceKind == BlockDeviceKind::eTemporaryFiles) {
263 results.fMountedFilesystems.Remove (i.fKey);
265 else if (not not _fOptions.fIncludeSystemDevices and i.fValue.fDeviceKind == BlockDeviceKind::eSystemInformation) {
266 results.fMountedFilesystems.Remove (i.fKey);
270 if (_fOptions.fIOStatistics) {
271 ReadAndApplyProcFS_diskstats_ (&results.fMountedFilesystems);
273 _NoteCompletedCapture ();
283 String deviceName = (not mi.fDevicePaths.has_value () or mi.fDevicePaths->empty ()) ?
String{} :
String{mi.fDevicePaths->
Nth (0)};
284 if (not deviceName.empty ()) {
288 UpdateVolumeInfo_statvfs_ (mi.fMountedOn, &vi);
289 result.
Add (mi.fMountedOn, vi);
298 struct statvfs sbuf{};
299 if (::statvfs (mountedOnName.c_str (), &sbuf) == 0) {
300 uint64_t diskSize = sbuf.f_bsize * sbuf.f_blocks;
301 v->fSizeInBytes = diskSize;
303 v->fUsedSizeInBytes = diskSize - sbuf.f_bsize * sbuf.f_bfree;
306#if USE_NOISY_TRACE_IN_THIS_MODULE_
307 DbgTrace (
"statvfs ({}) return error: errno={}"_f, mountedOnName, errno);
321 if (_fContext.load ()->fDiskPerfStats_) {
323 size_t i = devNameLessSlashes.
rfind (
'/');
324 if (i != string::npos) {
325 devNameLessSlashes = devNameLessSlashes.
SubString (i + 1);
331 useDevT = sbuf.st_rdev;
337 optional<PerfStats_> oOld = _fContext.load ()->fDiskPerfStats_->Lookup (useDevT);
338 optional<PerfStats_> oNew = diskStats.
Lookup (useDevT);
339 if (oOld.has_value () and oNew.has_value ()) {
340 unsigned int sectorSizeTmpHack = GetSectorSize_ (devNameLessSlashes);
342 readStats.fBytesTransfered = (oNew->fSectorsRead - oOld->fSectorsRead) * sectorSizeTmpHack;
343 readStats.fTotalTransfers = oNew->fReadsCompleted - oOld->fReadsCompleted;
344 if (timeSinceLastMeasure > _fOptions.fMinimumAveragingInterval) {
345 readStats.fQLength = (oNew->fTimeSpentReading - oOld->fTimeSpentReading) / timeSinceLastMeasure.count ();
349 writeStats.fBytesTransfered = (oNew->fSectorsWritten - oOld->fSectorsWritten) * sectorSizeTmpHack;
350 writeStats.fTotalTransfers = oNew->fWritesCompleted - oOld->fWritesCompleted;
351 if (timeSinceLastMeasure > _fOptions.fMinimumAveragingInterval) {
352 writeStats.fQLength = (oNew->fTimeSpentWriting - oOld->fTimeSpentWriting) / timeSinceLastMeasure.count ();
356 combinedStats.fBytesTransfered = *readStats.fBytesTransfered + *writeStats.fBytesTransfered;
357 combinedStats.fTotalTransfers = *readStats.fTotalTransfers + *writeStats.fTotalTransfers;
358 combinedStats.fQLength = *readStats.fQLength + *writeStats.fQLength;
361 vi.fWriteIOStats = writeStats;
363 if (timeSinceLastMeasure > _fOptions.fMinimumAveragingInterval) {
364 combinedStats.fQLength =
365 ((oNew->fWeightedTimeInQSeconds - oOld->fWeightedTimeInQSeconds) / timeSinceLastMeasure.count ());
367 vi.fCombinedIOStats = combinedStats;
371 volumes->
Update (i, vi, &i);
373 _fContext.rwget ().rwref ()->fDiskPerfStats_ = diskStats;
376 DbgTrace (
"Exception gathering procfs disk io stats"_f);
381 static optional<filesystem::path> GetSysBlockDirPathForDevice_ (
const String& deviceName)
383 Require (not deviceName.empty ());
384 Require (not deviceName.
Contains (
"/"sv));
390 static const filesystem::path kSysBlock_{
"/sys/block"sv};
391 filesystem::path tmp{kSysBlock_ / deviceName.
As<filesystem::path> ()};
396 tmp = kSysBlock_ / deviceName.
SubString (0, -1).
As<filesystem::path> ();
404 nonvirtual uint32_t GetSectorSize_ (
const String& deviceName)
406 auto o = _fContext.load ()->fDeviceName2SectorSizeMap_.Lookup (deviceName);
407 if (not o.has_value ()) {
408 if (optional<filesystem::path> blockDeviceInfoPath = GetSysBlockDirPathForDevice_ (deviceName)) {
409 filesystem::path fn = *blockDeviceInfoPath /
"queue/hw_sector_size";
411 o = String2Int<uint32_t> (
415 _fContext.rwget ().rwref ()->fDeviceName2SectorSizeMap_.Add (deviceName, *o);
418 DbgTrace (
"Unknown error reading {}"_f, fn);
423 return o.value_or (512);
433 std::exception_ptr runException;
435 pr.Run (
nullptr, useStdOut);
438 runException = current_exception ();
442 bool skippedHeader =
false;
444 if (not skippedHeader) {
445 skippedHeader =
true;
456 if (not d.empty () and d !=
"none"sv) {
461 double szInBytes = Characters::FloatConversion::ToFloat<double> (l[1]) * 1024;
462 if (not std::isnan (szInBytes) and not std::isinf (szInBytes)) {
463 v.fSizeInBytes = szInBytes;
467 double usedSizeInBytes = FloatConversion::ToFloat<double> (l[2]) * 1024;
468 if (not std::isnan (usedSizeInBytes) and not std::isinf (usedSizeInBytes)) {
469 v.fUsedSizeInBytes = usedSizeInBytes;
472 if (v.fSizeInBytes and v.fUsedSizeInBytes) {
475 result.
Add (l[5].Trim ().As<filesystem::path> (), v);
478 if (runException and result.
empty ()) {
492 ProcessRunner pr{includeFSTypes ?
"/bin/df -k -T"sv :
"/bin/df -k"sv};
494 std::exception_ptr runException;
496 pr.Run (
nullptr, useStdOut);
499 runException = current_exception ();
503 bool skippedHeader =
false;
505 if (not skippedHeader) {
506 skippedHeader =
true;
510 if (l.
size () < (includeFSTypes ? 7 : 6)) {
515 if (includeFSTypes) {
520 if (not d.empty () and d !=
"none"_k) {
524 v.fSizeInBytes = FloatConversion::ToFloat<double> (l[includeFSTypes ? 2 : 1]) * 1024;
525 v.fUsedSizeInBytes = FloatConversion::ToFloat<double> (l[includeFSTypes ? 3 : 2]) * 1024;
527 result.
Add (l[includeFSTypes ? 6 : 5].Trim ().As<filesystem::path> (), v);
530 if (runException and result.
empty ()) {
538 return RunDF_ (
true);
541 return RunDF_ (
false);
550 static const filesystem::path kProcMemInfoFileName_{
"/proc/diskstats"sv};
553 reader.ReadMatrix (IO::FileSystem::FileInputStream::New (kProcMemInfoFileName_, IO::FileSystem::FileInputStream::eNotSeekable))) {
554#if USE_NOISY_TRACE_IN_THIS_MODULE_
555 DbgTrace (L
"***in Instruments::Filesystem::ReadProcFS_diskstats_ linesize=%d, line[0]=%s", line.size (),
556 line.empty () ? L
"" : line[0].c_str ());
571 if (line.size () >= 13) {
572 String majorDevNumber = line[1 - 1];
573 String minorDevNumber = line[2 - 1];
574 String devName = line[3 - 1];
575 String readsCompleted = line[4 - 1];
576 String sectorsRead = line[6 - 1];
577 String timeSpentReadingMS = line[7 - 1];
578 String writesCompleted = line[8 - 1];
579 String sectorsWritten = line[10 - 1];
580 String timeSpentWritingMS = line[11 - 1];
581 constexpr bool kAlsoReadQLen_{
true};
582 optional<double> weightedTimeInQSeconds;
583 if (kAlsoReadQLen_) {
584 optional<filesystem::path> sysBlockInfoPath = GetSysBlockDirPathForDevice_ (devName);
585 if (sysBlockInfoPath) {
586 for (
const Sequence<String>& ll : reader.ReadMatrix (IO::FileSystem::FileInputStream::New (
587 *sysBlockInfoPath /
"stat", IO::FileSystem::FileInputStream::eNotSeekable))) {
588 if (ll.size () >= 11) {
595 result.
Add (makedev (String2Int<unsigned int> (majorDevNumber), String2Int<unsigned int> (minorDevNumber)),
608#if qStroika_Foundation_Common_Platform_Windows
612#if qUseWMICollectionSupport_
614 WMICollector fLogicalDiskWMICollector_{
"LogicalDisk"sv,
616 { kDiskReadBytesPerSec_,
617 kDiskWriteBytesPerSec_,
620 (kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_ ? kPctDiskReadTime_ : kAveDiskReadQLen_),
621 (kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_ ? kPctDiskWriteTime_ : kAveDiskWriteQLen_),
626 struct InstrumentRep_Windows_ : InstrumentRepBase_<_Context> {
627 using InstrumentRepBase_<_Context>::InstrumentRepBase_;
629 nonvirtual
Info _InternalCapture ()
631#if USE_NOISY_TRACE_IN_THIS_MODULE_
641 di.fSizeInBytes = pd.fSizeInBytes;
642 result.
fDisks.Add (pd.fDeviceName, di);
645#if qUseWMICollectionSupport_
646 auto contextLock = scoped_lock{_fContext};
647 auto contextPtr = _fContext.rwget ().rwref ();
648 optional<Time::DurationSeconds> timeCollecting;
650 optional<Time::TimePointSeconds> timeOfPrevCollection = contextPtr->fLogicalDiskWMICollector_.GetTimeOfLastCollection ();
651 if (_fOptions.fIOStatistics) {
652 contextPtr->fLogicalDiskWMICollector_.Collect ();
654 if (timeOfPrevCollection) {
656 timeCollecting = *contextPtr->fLogicalDiskWMICollector_.GetTimeOfLastCollection () - *timeOfPrevCollection;
665 if (not physDrives.
empty ()) {
666 v.fOnPhysicalDrive = mfinfo.fDevicePaths;
673 switch (::GetDriveType (v.
fVolumeID->AsSDKString ().c_str ())) {
674 case DRIVE_REMOVABLE:
675 v.fDeviceKind = BlockDeviceKind::eRemovableDisk;
678 v.fDeviceKind = BlockDeviceKind::eLocalDisk;
681 v.fDeviceKind = BlockDeviceKind::eNetworkDrive;
684 v.fDeviceKind = BlockDeviceKind::eTemporaryFiles;
687 v.fDeviceKind = BlockDeviceKind::eReadOnlyEjectable;
694 ULARGE_INTEGER freeBytesAvailable{};
695 ULARGE_INTEGER totalNumberOfBytes{};
696 ULARGE_INTEGER totalNumberOfFreeBytes{};
697 [[maybe_unused]] DWORD ignored =
698 ::GetDiskFreeSpaceEx (mfinfo.fMountedOn.c_str (), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes);
699 v.fSizeInBytes = totalNumberOfBytes.QuadPart;
700 v.fUsedSizeInBytes = *v.fSizeInBytes - freeBytesAvailable.QuadPart;
702#if qUseWMICollectionSupport_
703 auto safePctInUse2QL_ = [] (
double pctInUse) {
706 pctInUse = clamp<double> (pctInUse, 0, 1);
707 return pctInUse / (1 - pctInUse);
709 if (_fOptions.fIOStatistics) {
711 contextPtr->fLogicalDiskWMICollector_.AddInstancesIf (wmiInstanceName);
714 if (timeCollecting) {
715 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kDiskReadBytesPerSec_)) {
716 readStats.fBytesTransfered = *o * timeCollecting->count ();
718 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kDiskReadsPerSec_)) {
719 readStats.fTotalTransfers = *o * timeCollecting->count ();
722 if (kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_) {
723 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kPctDiskReadTime_)) {
724 readStats.fInUsePercent = *o;
725 readStats.fQLength = safePctInUse2QL_ (*o);
729 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kAveDiskReadQLen_)) {
730 readStats.fInUsePercent = *o;
731 readStats.fQLength = *o;
736 if (timeCollecting) {
737 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kDiskWriteBytesPerSec_)) {
738 writeStats.fBytesTransfered = *o * timeCollecting->count ();
740 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kDiskWritesPerSec_)) {
741 writeStats.fTotalTransfers = *o * timeCollecting->count ();
744 if (kUseDiskPercentReadTime_ElseAveQLen_ToComputeQLen_) {
745 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kPctDiskWriteTime_)) {
746 writeStats.fInUsePercent = *o;
747 writeStats.fQLength = safePctInUse2QL_ (*o);
751 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kAveDiskWriteQLen_)) {
752 writeStats.fInUsePercent = *o;
753 writeStats.fQLength = *o;
758 Memory::AccumulateIf (&combinedStats.fBytesTransfered, writeStats.fBytesTransfered);
759 Memory::AccumulateIf (&combinedStats.fTotalTransfers, writeStats.fTotalTransfers);
760 Memory::AccumulateIf (&combinedStats.fQLength, writeStats.fQLength);
761 Memory::AccumulateIf (&combinedStats.fInUsePercent, writeStats.fInUsePercent);
762 if (readStats.fInUsePercent and writeStats.fInUsePercent) {
763 combinedStats.fInUsePercent = *combinedStats.fInUsePercent / 2;
766 if (kUsePctIdleIimeForAveQLen_) {
767 if (
auto o = contextPtr->fLogicalDiskWMICollector_.PeekCurrentValue (wmiInstanceName, kPctIdleTime_)) {
768 double aveCombinedQLen = safePctInUse2QL_ (100.0 - *o);
769 if (readStats.fQLength and writeStats.fQLength and *combinedStats.fQLength > 0) {
772 double correction = aveCombinedQLen / *combinedStats.fQLength;
773 Memory::AccumulateIf (&readStats.fQLength, correction, std::multiplies{});
774 Memory::AccumulateIf (&writeStats.fQLength, correction, std::multiplies{});
776 combinedStats.fQLength = aveCombinedQLen;
780 if (readStats.fBytesTransfered or readStats.fTotalTransfers or readStats.fQLength) {
783 if (writeStats.fBytesTransfered or writeStats.fTotalTransfers or writeStats.fQLength) {
784 v.fWriteIOStats = writeStats;
786 if (combinedStats.fBytesTransfered or combinedStats.fTotalTransfers or combinedStats.fQLength) {
787 v.fCombinedIOStats = combinedStats;
792 result.fMountedFilesystems.Add (mfinfo.fMountedOn, v);
794#if qUseWMICollectionSupport_
795 _NoteCompletedCapture (contextPtr->fLogicalDiskWMICollector_.GetTimeOfLastCollection ().value_or (Time::GetTickCount ()));
797 _NoteCompletedCapture ();
805 static optional<String> GetDeviceNameForVolumneName_ (
const String& volumeName)
821 tmp[tmp.
length () - 1] != L
'\\') {
828 WCHAR deviceName[MAX_PATH] = L
"";
829 if (::QueryDosDeviceW (tmp.
c_str (), deviceName, ARRAYSIZE (deviceName)) != 0) {
830 return String{deviceName};
844 struct FilesystemInstrumentRep_
845#if qStroika_Foundation_Common_Platform_Linux
846 : InstrumentRep_Linux_
847#elif qStroika_Foundation_Common_Platform_Windows
848 : InstrumentRep_Windows_
850 : InstrumentRepBase_<SystemPerformance::Support::Context>
853#if qStroika_Foundation_Common_Platform_Linux
854 using inherited = InstrumentRep_Linux_;
855#elif qStroika_Foundation_Common_Platform_Windows
856 using inherited = InstrumentRep_Windows_;
858 using inherited = InstrumentRepBase_<SystemPerformance::Support::Context>;
860 FilesystemInstrumentRep_ (
const Options& options,
const shared_ptr<_Context>& context = make_shared<_Context> ())
861 : inherited{options, context}
863 Require (_fOptions.fMinimumAveragingInterval > 0s);
870 results.fMeasurements.Add (m);
875 return Do_Capture_Raw<Info> ([
this] () {
return _InternalCapture (); }, outMeasuredAt);
877 virtual unique_ptr<IRep> Clone ()
const override
879 return make_unique<FilesystemInstrumentRep_> (_fOptions, _fContext.load ());
881 nonvirtual
Info _InternalCapture ()
883 AssertExternallySynchronizedMutex::WriteContext declareContext{*
this};
885#if qStroika_Foundation_Common_Platform_Linux or qStroika_Foundation_Common_Platform_Windows
886 Info result = inherited::_InternalCapture ();
890 if (_fOptions.fEstimateFilesystemStatsFromDiskStatsIfHelpful) {
891 result.fMountedFilesystems = ApplyDiskStatsToMissingFileSystemStats_ (result.
fDisks, result.fMountedFilesystems);
900#if USE_NOISY_TRACE_IN_THIS_MODULE_
907 using WeightingStat2UseType = double;
911 if (disksForFS.
size () > 0) {
912 WeightingStat2UseType weightForFS =
NullCoalesce (NullCoalesce (i.fValue.fCombinedIOStats).fBytesTransfered);
913 weightForFS /= disksForFS.
size ();
914 for (
const DynamicDiskIDType& di : disksForFS) {
915 totalWeights.
Add (di, totalWeights.
LookupValue (di) + weightForFS);
919#if USE_NOISY_TRACE_IN_THIS_MODULE_
922 for (
const auto& i : totalWeights) {
923 DbgTrace (L
"Disk '%s' weight %f", i.fKey.c_str (), i.fValue);
938 if (totalWeights.
size () >= 1) {
942 if (disksForFS.
size () > 0) {
943 WeightingStat2UseType weightForFS =
NullCoalesce (NullCoalesce (i.fValue.fCombinedIOStats).fBytesTransfered);
944 weightForFS /= disksForFS.
size ();
946 bool computeInuse = not cumStats.fInUsePercent.has_value ();
947 bool computeQLen = not cumStats.fQLength.has_value ();
948 bool computeTotalXFers = not cumStats.fTotalTransfers.has_value ();
950 for (
const DynamicDiskIDType& di : disksForFS) {
952 if (weightForFS > 0) {
953 double scaleFactor = weightForFS / totalWeights.
LookupValue (di);
955 scaleFactor = clamp (scaleFactor, 0.0, 1.0);
956 if (computeInuse and diskIOStats.fInUsePercent) {
957 Memory::AccumulateIf<double> (&cumStats.fInUsePercent, *diskIOStats.fInUsePercent * scaleFactor);
959 if (computeQLen and diskIOStats.fInUsePercent) {
960 Memory::AccumulateIf<double> (&cumStats.fQLength, *diskIOStats.fQLength * scaleFactor);
962 if (computeTotalXFers and diskIOStats.fTotalTransfers) {
963 Memory::AccumulateIf<double> (&cumStats.fTotalTransfers, *diskIOStats.fTotalTransfers * scaleFactor);
967#if USE_NOISY_TRACE_IN_THIS_MODULE_
969 DbgTrace (L
"Adjusted fInUsePCT for filesystem '%s' is %f", i.fKey.c_str (),
NullCoalesce (cumStats.fInUsePercent));
972 DbgTrace (L
"Adjusted fQLength for filesystem '%s' is %f", i.fKey.c_str (),
NullCoalesce (cumStats.fQLength));
975 mfi.fCombinedIOStats = cumStats;
977 newFilessytems.
Add (i.fKey, mfi);
979 return newFilessytems;
995 mapper.
Add (mapper.MakeCommonSerializer_NamedEnumerations<BlockDeviceKind> ());
998 {
"Bytes"sv, &IOStatsType::fBytesTransfered},
999 {
"Q-Length"sv, &IOStatsType::fQLength},
1000 {
"In-Use-%"sv, &IOStatsType::fInUsePercent},
1001 {
"Total-Transfers"sv, &IOStatsType::fTotalTransfers},
1005 {
"Persistence-Volume-ID"sv, &DiskInfoType::fPersistenceVolumeID},
1006 {
"Device-Kind"sv, &DiskInfoType::fDeviceKind},
1007 {
"Size"sv, &DiskInfoType::fSizeInBytes},
1008 {
"Read-IO-Stats"sv, &DiskInfoType::fReadIOStats},
1009 {
"Write-IO-Stats"sv, &DiskInfoType::fWriteIOStats},
1010 {
"Combined-IO-Stats"sv, &DiskInfoType::fCombinedIOStats},
1017 {
"Device-Kind"_k, &MountedFilesystemInfoType::fDeviceKind},
1018 {
"Filesystem-Type"_k, &MountedFilesystemInfoType::fFileSystemType},
1019 {
"Device-Name"_k, &MountedFilesystemInfoType::fDeviceOrVolumeName},
1020 {
"On-Physical-Drives"_k, &MountedFilesystemInfoType::fOnPhysicalDrive},
1021 {
"Volume-ID"_k, &MountedFilesystemInfoType::fVolumeID},
1022 {
"Total-Size"_k, &MountedFilesystemInfoType::fSizeInBytes},
1023 {
"Available-Size"_k, &MountedFilesystemInfoType::fAvailableSizeInBytes},
1024 {
"Used-Size"_k, &MountedFilesystemInfoType::fUsedSizeInBytes},
1025 {
"Read-IO-Stats"_k, &MountedFilesystemInfoType::fReadIOStats},
1026 {
"Write-IO-Stats"_k, &MountedFilesystemInfoType::fWriteIOStats},
1027 {
"Combined-IO-Stats"_k, &MountedFilesystemInfoType::fCombinedIOStats},
1032 {
"Disks"_k, &Info::fDisks},
1033 {
"Mounted-Filesystems"_k, &Info::fMountedFilesystems},
1038Instruments::Filesystem::Instrument::Instrument (
const Options& options)
1040 make_unique<FilesystemInstrumentRep_> (options),
1041 {kMountedVolumeUsage_},
1056 FilesystemInstrumentRep_* myCap =
dynamic_cast<FilesystemInstrumentRep_*
> (fCaptureRep_.get ());
1058 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 ...