codit_memorytracker() - Tracking Memory use in a Drupal Script

Drupal Documentation
This function appears in the Codit Module

Devel has some output that you can turn on to inspect script memory useage. In some cases (like batch processes) they may not give you what you need. Especially if you want to watch it while it is happening.

Here is a function that is part of the Codit module. Here are some sample ways to call this function.

<?php
//Standard just send a memory snapshot to the server error log
 
codit_memorytracker();

//Do above WITH a custom message.
 
codit_memorytracker('I just started the big process of XYZ');

//Do above  ONLY if the memory usage has gone above a defined threshold of 56Mb.
 
codit_memorytracker('In the middle of processXYZ now', 56);

//Do the above case  AND do something in php with the results
 
$aMemoryStatus = codit_memorytracker('In the middle of processXYZ now', 56);
if(
$aMemoryStatus['threshold_exceeded']) {
  
//something has gone badly, set an abort flag so the next iteration of the loop is not run.
  
$bAbortFlag = TRUE;
  
dpm($aMemoryStatus);
}
?>

Sample Log Output

[Thu Apr 04 23:34:48] [error] [client 174.58.5.4] RAM CHECK | NOW: 32.4mb | PEAK: 38.5MB in mmg_grids_build_filtered_grids line 38 of var/www/somesite.com/drupal/modules/mmg_grids_builder/mmg_grids_builder.inc  -----Message: In the middle of processXYZ now referrer: http//some.page.you.just.came.from

Sample Function Return

Array
(
    [threshold_exceeded] =>
    [logged] => 1
    [memory_in_use] => 49020928
    [memory_in_use_friendly] => 46.75 mb
    [memory_use_peak] => 50069504
    [memory_use_peak_friendly] => 47.75 mb
    [from_file] => /var/www/drupal-7.16/sites/all/modules/contrib/devel/devel.module
    [from_function] => devel_execute_form_submit
    [from_line] => 1285
)

Interesting side effect, the actual calling of this function triggers a php garbage collection on memory, so the very act of calling this can actually reduce the RAM being used.

The function code

This function resides in codit/codit_functions_for_coders.inc so look there for the most current version.

<?php
/**
 * When called, this function writes a memory report to the error log and returns the raw value in case you want to do something with it.
 * @param $sMessage a string containing any message you want sent to the log
 *
 * @param $iMBThreshold the threshhold in MB that if exceeded will write to the log (default=NULL) so if unspecified, it will always write to log
 *
 * @return an array containing the following elements
 *    ['memory_in_use'] - the memory used in bytes at the instant this was called
 *    ['memory_in_use_friendly'] - The amount of memory in use in specfic appropriate quantities like mb or b, kb..
 *    ['memory_use_peak'] - The peak memory used in bytes by the script
 *    ['memory_use_peak_friendly'] - The peak memory used by the script in specfic appropriate quantities like mb or b, kb..
 *    ['threshold_exceeded'] - boolean TRUE if the threshold was exceeded, FALSE if not exceeded or NULL if not set
 *    ['logged'] - boolean TRUE if an error message was logged
 *    ['from_file'] - The file this funciton was called from
 *    ['from_function'] - The function this funciton was called from
 *     ['from_line'] -  The line this function was called from
 *
 * @author  Steve Wirt
 */
function codit_memorytracker($sMessage = '', $iMBThreshold = NULL)
 {
   
$aReturn = array();  
   
$aUnits = array('b','kb','mb','gb','tb','pb');
   
//convert threshold to bytes
   
$iMBThreshold = (!empty($iMBThreshold) && (is_numeric($iMBThreshold))) ? $iMBThreshold * 1049000 : NULL ;
   
$iMemInUse = memory_get_usage(TRUE);
   
$sFriendlyMemInUse = round($iMemInUse/pow(1024,($i=floor(log($iMemInUse,1024)))),2).' '.$aUnits[$i];
   
$iMemPeakUse = memory_get_peak_usage(TRUE);
   
$sFriendlyMemPeakUse = round($iMemPeakUse/pow(1024,($i=floor(log($iMemPeakUse,1024)))),2).' '.$aUnits[$i];
   
// determine what file, function and line called for this check
   
$sFile = 'n/a';
   
$sFunction = 'n/a';
   
$nLine = 'n/a';
   
$debugTrace = debug_backtrace(FALSE);
    if (isset(
$debugTrace[1])) {
       
$sFile = $debugTrace[1]['file'] ? $debugTrace[1]['file'] : 'n/a';
       
$nLine = $debugTrace[1]['line'] ? $debugTrace[1]['line'] : 'n/a';
    }
    if (isset(
$debugTrace[2])) $sFunction = $debugTrace[2]['function'] ? $debugTrace[2]['function'] : 'n/a';
   
   
$sMessageToLog = "RAM CHECK| NOW: $sFriendlyMemInUse | PEAK: $sFriendlyMemPeakUse  in $sFunction line $nLine \n of $sFile \n ----Message: $sMessage";
   
//check to see if memory use is above the threshold
   
if ($iMemInUse > $iMBThreshold) {
       
//threshold exceeded
       
error_log($sMessageToLog, 0);
       
$aReturn['threshold_exceeded'] = ($iMBThreshold === NULL) ? NULL : TRUE ;
       
$aReturn['logged'] = TRUE;
    } else {
       
//threshold not exceeded - nothing logged
       
$aReturn['threshold_exceeded'] = FALSE;
       
$aReturn['logged'] = FALSE;
    }
   
   
$aReturn['memory_in_use'] = $iMemInUse;
   
$aReturn['memory_in_use_friendly'] = $sFriendlyMemInUse;
   
$aReturn['memory_use_peak'] = $iMemPeakUse;
   
$aReturn['memory_use_peak_friendly'] = $sFriendlyMemPeakUse;
   
$aReturn['from_file'] = $sFile;
   
$aReturn['from_function'] = $sFunction;
   
$aReturn['from_line'] = $nLine;
   
    return
$aReturn;
 }
//function codit_memorytracker
?>

section:

modules: