/* * Title: analog.h - header file for log analyzer * * Description: This file provides structures and macros for log analyzer. * * Types: * PoolLogRec Poolsnap structure * MemLogRec Memsnap structure * LogType Enumeration of known log types * * Macros: * * GET_DELTA Computes the difference between first & last entry * GREATER_LESS_OR_EQUAL Increments trend if cur>prv, decrements if cur<prv * PRINT_IF_TREND Prints definite or probable leaks based on trend * MAX Returns the larger value * * Copyright (c) 1998 Microsoft Corporation * * Revision history: LarsOp (created) 12/8/98 * */ // // Structure for poolsnap logs // typedef struct _PoolLogRec { char Name[32]; char Type[32]; long Allocs; long Frees; long Diff; long Bytes; long PerAlloc; } PoolLogRec; // // Structure for memsnap logs // typedef struct _MemLogRec { DWORD Pid; char Name[64]; long WorkingSet; long PagedPool; long NonPagedPool; long PageFile; long Commit; long Handles; long Threads; } MemLogRec; // // Enumeration of the known log types // typedef enum { MEM_LOG=0, // must be zero (see LogTypeLabels) POOL_LOG, // must be 1 (see LogTypeLabels) UNKNOWN_LOG_TYPE } LogType; // // Array of labels to simplify printing the enumerated type // char *LogTypeLabels[]={"MemSnap", "PoolSnap", "Unknown"}; // // Arbitrary buffer length // #define BUF_LEN 256 #define PERCENT_TO_PRINT 10 // // GET_DELTA simply records the difference (end-begin) for specified field // // Args: // delta - record to receive result values // ptr - array of records (used to compare first and last) // max - number of entries in the array // field - field name to compute // // Returns: nothing (treat like void function) // #define GET_DELTA(delta, ptr, max, field) delta.field = ptr[max-1].field - ptr[0].field // // GREATER_LESS_OR_EQUAL calculates TrendInfo. // // Args: // trend - record containing running tally // ptr - array of records (used to compare curr and prev) // i - index of current entry in the array // field - field name to compare // // Returns: nothing (treat like void function) // // TrendInfo is a running tally of the periods a value went up vs. // the periods it went down. See macro in analog.h // // if (curval>oldval) { // trend++; // } else if (curval<oldval) { // trend--; // } else { // trend=trend; // stay same // } // #define GREATER_LESS_OR_EQUAL(trend, ptr, i, field) \ if (ptr[i].field - ptr[i-1].field) \ trend.field += (((ptr[i].field - ptr[i-1].field) > 0) ? 1 : -1); // // MAX returns the larger value of the two // // Args: x,y: arguments of the same type where '>' is defined. // // Returns: the larger value // #define MAX(x, y) (x>y?x:y) // // PERCENT returns the percentage // // Args: // delta - value of increase // base - initial value // // Returns: the percent if base!=0, else 0 // #define PERCENT(delta, base) (base!=0?(100*delta)/base:0) #define VAL_AND_PERCENT(delta, ptr, field) delta.field, PERCENT(delta.field, ptr[0].field) // // PRINT_IF_TREND reports probable or definite leaks for any field. // // Args: // ptr - array of records (used to display first and last) // trend - record containing running tally // delta - record containing raw differences of first and last // max - number of entries in the array // field - field name to compare // // Returns: nothing (treat like void function) // // Definite leak is where the value goes up every period // Probable leak is where the value goes up most of the time // // // PRINT_HEADER and PRINT_IF_TREND must agree on field widths. // #define PRINT_HEADER() { \ TableHeader(); \ if( bHtmlStyle ) { \ TableStart(); \ printf("<TH COLSPAN=2> %s </TH>\n",g_pszComputerName); \ printf("<TH COLSPAN=6>\n"); \ if( g_fShowExtraInfo ) { \ printf("BuildNumber=%s\n",g_pszBuildNumber); \ printf("<BR>BuildType=%s\n",g_pszBuildType); \ printf("<BR>Last SystemTime=%s\n",g_pszSystemTime); \ printf("<BR>%s\n",g_pszComments); \ } \ printf("</TH>\n"); \ TableEnd(); \ } \ TableStart(); \ TableField("%-15s", "Name" ); \ TableField("%-12s", "Probability"); \ TableField("%-12s", "Object" ); \ TableField("%10s", "Change" ); \ TableField("%10s", "Start" ); \ TableField("%10s", "End" ); \ TableField("%8s", "Percent"); \ TableField("%10s", "Rate/hour" ); \ TableEnd(); } #define PRINT_TRAILER() { \ TableTrailer(); } #define PRINT_IF_TREND(ptr, trend, delta, max, field) \ if (trend.field >= max/2) { \ BOOL bDefinite= (trend.field==max-1) ? 1 : 0; \ if( bDefinite || (g_ReportLevel>0) ) { \ TableStart(); \ TableField("%-15s", ptr[0].Name); \ TableField("%-12s", bDefinite ? "Definite" : "Probable"); \ TableField("%-12s", #field); \ TableNum("%10ld", delta.field); \ TableNum("%10ld", ptr[0].field); \ TableNum("%10ld", ptr[max-1].field); \ TableNum("%8ld", PERCENT(delta.field,ptr[0].field)); \ if( g_dwElapseTickCount ) { \ TableNum("%10d",Trick( delta.field ,g_dwElapseTickCount) ); \ } else { \ TableField("%-10s"," "); \ }; \ TableEnd(); \ } \ } #define ANY_PERCENT_GREATER(delta, ptr) (\ (PERCENT(delta.WorkingSet , ptr[0].WorkingSet ) > PERCENT_TO_PRINT) || \ (PERCENT(delta.PagedPool , ptr[0].PagedPool ) > PERCENT_TO_PRINT) || \ (PERCENT(delta.NonPagedPool , ptr[0].NonPagedPool) > PERCENT_TO_PRINT) || \ (PERCENT(delta.PageFile , ptr[0].PageFile ) > PERCENT_TO_PRINT) || \ (PERCENT(delta.Commit , ptr[0].Commit ) > PERCENT_TO_PRINT) || \ (PERCENT(delta.Handles , ptr[0].Handles ) > PERCENT_TO_PRINT) || \ (PERCENT(delta.Threads , ptr[0].Threads ) > PERCENT_TO_PRINT))