c++performancecounterresource-monitor

How to control reading from file using performance counters?


There are several operations being done on drive G. My program should read data from file. When the disk usage is very high(>90%) the program should slow down the reading so it won't interfere with other processes that uses the disk.
Obviously, I guess, that checking the Disk Time after calling get_data_from_file() will cause the counter to return very high percentage because the disk was just used. You can see that on the image.

Any suggestions on how I can check correctly the Disk Time?

PDH_HQUERY query;
PDH_HCOUNTER counter;
PdhOpenQuery(NULL, 0, &query);
PdhAddCounterA(query, "\\LogicalDisk(G:)\\% Disk Time", 0, &counter);
PdhCollectQueryData(query);

auto getDiskTime = [&]()->double
{
    PDH_FMT_COUNTERVALUE fmtCounter;
    PdhCollectQueryData(query); 
    PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, 0, &fmtCounter);       

    return fmtCounter.doubleValue;
};

for(...)
{
   get_data_from_file();

   print_done_percentage();

   double diskUsage = getDiskTime();
   if(diskUsage >= 90)
   {            
       std::cout << "The disk usage is over << diskUsage << "%. I'll wait...                
       while(diskUsage >= 90)
       {
           diskUsage = getDiskTime();
           Sleep(500);
       }
   }
}

Solution

  • A distinct monitoring thread could help you measure disk usage with more independence from the writing.

    The function executed by the thread would look like this:

    void diskmonitor(atomic<double>& du, const atomic<bool>& finished) {
        while (!finished) {         // stop looping as soon as main process has finished job
            du = getDiskTime();     // measure disk
            this_thread::sleep_for(chrono::milliseconds(500)); //wait
        }
    }
    

    It communicates with the main thread through atomic (i.e. to avoid data races) variables passed by reference.

    Your processing loop would look as follows:

    atomic<bool> finished=false;            // tell diskmonitor that the processing is ongoing
    atomic<double> diskusage=0;             // last disk usage read by diskmonitor
    thread t(diskmonitor, ref(diskusage), ref(finished));   // launch monitor
    for (int i = 0; i < 1000; i++)
    {
        ...
        print_done_percentage();
    
        while (diskusage >= 90) {    // disk usage is filled in background
            std::cout << "The disk usage is over " << diskusage << ".I'll wait...\n";
            this_thread::sleep_for(chrono::milliseconds(500));
            }
        ...
    }
    finished = false;           // tell diskmonitor that i't's finished, so that it ends the loop
    t.join();                   // wait until diskmonitor is finished. 
    

    This example is with standard C++ threads. Of course you could code something similar with OS specific threads.