I have an elaborate script which I'm writing to dynamically allocate new threads to handle a particular task. I've written a bit of the script to try and detect available memory and the current system load average so that it will wait if the system is too busy so that it doesn't overwhelm the server on which it runs. This wait loop repeatedly detects the memory by using php's [man]exec[/man] function and calling 'free' and 'uptime' and parsing the results. The problem I'm having is that when it enters the loop, these exec calls oftentimes return the same values over and over and these values do not reflect the actual values on the system.
here's the loop:
$la = self::getLoadAverage();
$mem = self::getFreeMemory();
$wait_multiplier = 1; // this can be incremented with each wait loop to reduce thrashing but at the cost
// of lengthy termination times
while (($mem['free'] < $this->minimum_memory_bytes) || ($la['la_1'] > $this->maximum_load_average)){
// first, check for termination signal
if ($this->bTerminate || $nSignalReceived) {
continue 2; // skip this wait loop and the main loop
}
//$wait_multiplier++;
$sleep_time_microseconds = $wait_multiplier * $this->resource_shortage_sleep_time_us;
$status = "Waiting " . number_format($sleep_time_microseconds/1000000, 2) . "s for resources. Free memory=" . number_format($mem['free']) . ", load avg=" . $la['la_1'];
MTLog::getInstance()->info($status);
usleep($sleep_time_microseconds);
}
The functions to fetch the free memory and load average are here:
/**
* A function that uses exec() to obtain the system
* load average and returns an array containing
* 1, 5, and 15 minute values
* TODO: Make sure this works on other operating systems aside from Ubuntu
* @access public
* @static
* @throws Exception
* @return array a 3-element array containing the one, five, and 15-minute load averages
*/
public static function getLoadAverage() {
// check the load average
$output = NULL;
$return_var = NULL;
$last_line = exec('uptime', $output, $return_var);
if ($return_var) {
throw New Exception("Unable to get load average");
}
if (!is_array($output)) {
throw new Exception("Load average result is not an array");
}
$matches = NULL;
if (!preg_match('/load average:\s+(\d+\.\d{2}),\s+(\d+\.\d{2}),\s+(\d+\.\d{2})/i', $output[0], $matches)) {
throw New Exception('Uptime output failed to match pattern. output=' . $output[0]);
}
$result = array(
'la_1' => floatval($matches[1]),
'la_5' => floatval($matches[2]),
'la_15' => floatval($matches[3])
);
return $result;
} // getLoadAverage()
/**
* A function that uses exec() to obtain the system
* load average and returns an array containing
* 1, 5, and 15 minute values
* TODO: Make sure this works on other operating systems aside from Ubuntu
* @access public
* @static
* @throws Exception
* @return array a 3-element array containing the one, five, and 15-minute load averages
*/
public static function getFreeMemory() {
// check free memory
$output = NULL;
$return_var = NULL;
$last_line = exec('free -b', $output, $return_var);
if ($return_var) {
throw New Exception("Unable to get free memory");
}
if (!is_array($output)) {
throw new Exception("Free memory result is not an array");
}
$matches = NULL;
if (!preg_match('/mem:\s+(\d+)\s+(\d+)\s+(\d+)/i', $output[1], $matches)) {
throw New Exception('Free memory output failed to match pattern. output=' . $output[0]);
}
$result = array(
'total' => floatval($matches[1]),
'used' => floatval($matches[2]),
'free' => floatval($matches[3])
);
return $result;
} // getFreeMemory()
Here's some sample output which shows a load average and/or memory outside the nominal ranges. However, I know that these values don't reflect the actual system values at the time because I had another terminal window open so I could monitor the system using the top command:
2011-07-07 01:50:19 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:20 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:20 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:21 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:21 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:22 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:22 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:23 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:23 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:24 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:24 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:25 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
2011-07-07 01:50:25 [20748] INFO : Waiting 0.50s for resources. Free memory=177,143,808, load avg=2.25
I know that as these log entries were entered the system load average was about 0.75 and the free memory was about 400 MB. Does the system cache these values? Is there any way to flush this cache and/or force an update of these values?