#!/usr/bin/probevue /* piostat.e Summary of I/O by a single PID over a two second interval. Mark Polo William Favorite Notes: - The data from this script is TOTALLY BOGOUS and CANNOT BE TRUSTED. A PMR has been opened with IBM on this issue and is awaiting a response. - The screen width requirement for all data is painful. The show_XXXX boolean variables have been added to display only the data you are looking for. - Totals are over the interval not per-second. Adjust this with interval factor. The interval variable only changes the number of operations for read / write. It does not change any of the other numbers, and does not change the actual interval. If the value for interval is > 1 then it should be changed if the interval probe timing is changed. - stdin, stdout, and stderr are not monitored. If the watched PID uses these file descriptors then the *_f_d test should be re-written to be (*_f_d >= 0), or just removed. Dameon processes may either close these file descriptors (and re-use them) or may rely heavily on this I/O (and therefore be more relavant to performance issues). - All sizes are in bytes, all times are in milliseconds. A factor could be created to modify all sizes (This is not done in this code). Additionally a string of a single byte could be used to represent the factor. (This would seem unnessary as the factor will never change during runtime.) The alternative to milliseconds is microseconds. This is controlled via a flag in the diff_time() call. (Changing this should be obvious based upon the example in the code.) Additionally the time could be factored if necessary. - This is the divide by zero message: Probevue session has been aborted 0x0000000096284061 */ /* Function prototypes */ int read(int fd, char *buf, unsigned long size); int write(int fd, char *buf, unsigned long size); /* Globals */ long linterval; /* Interval "factor" to divide operations by */ int lprint; /* Lines (of output) we have printed */ long r_op_count; /* Count of read operations */ long r_sz_max; /* Maximum read size over interval */ long r_sz_min; /* Minimum read size over interval */ long r_sz_total; /* Total read over inteval */ long long r_tm_max; /* Maximum time spent in a read */ long long r_tm_min; /* Minimum time spent in a read */ long long r_tm_total; /* Total time spent in read calls */ long w_ra; /* Write Running Average value */ long w_op_count; /* Count of write operations */ long w_sz_max; /* Maximum write size over interval */ long w_sz_min; /* Minimum write size over interval */ long w_sz_total; /* Total written over interval */ long long w_tm_max; /* Maximum time spent in a write */ long long w_tm_min; /* Minimum time spent in a write */ long long w_tm_total; /* Total time spent in write calls */ int show_r; int show_w; int show_tm; int show_sz; int show_lines; @@BEGIN { /* Set these to determine what values are actually displayed. show_r - Show read()s for the pid show_w - Show write()s for the pid show_tm - Show show time statistics for reads/writes show_sz - Show data written / read statistics show_lines - Show some extra ASCII-eye-candy in output */ show_r = 1; show_w = 0; show_tm = 0; show_sz = 1; show_lines = 1; /* Reset all values */ r_op_count = 0; w_op_count = 0; r_sz_min = -1; r_sz_max = 0; w_sz_min = -1; w_sz_max = 0; w_sz_total = 0; r_sz_total = 0; r_tm_max = 0; r_tm_min = -1; r_tm_total = 0; w_tm_max = 0; w_tm_min = -1; w_tm_total = 0; linterval = 1; /* Note: This is tied to the second number in the interval timer probe definition. This number does NOT change the actual interval, but only how we calculate operations per-interval. By default this value is 1, which means that the number of operations per line are the number of operations in that interval, not the number of ops per second. Set this number to the number of seconds in the interval to get operations per-second. */ lprint = 0; printf("Script starting.\n"); printf("Watching I/O on PID %d.\n", $1); /* First line of output */ if ( show_r ) printf("Reads "); if (( show_r ) && ( show_sz )) printf("Size "); if (( show_r ) && ( show_tm )) printf("Time "); if ( show_w ) printf("Writes "); if (( show_w ) && ( show_sz )) printf("Size "); if (( show_w ) && ( show_tm )) printf("Time "); printf("\n"); /* Second line of output */ if ( show_lines ) { if ( show_r ) printf("---------- "); if (( show_r ) && ( show_sz )) printf("------------------------------------------- "); if (( show_r ) && ( show_tm )) printf("------------------------------------------- "); if ( show_w ) printf("---------- "); if (( show_w ) && ( show_sz )) printf("------------------------------------------- "); if (( show_w ) && ( show_tm )) printf("------------------------------------------- "); printf("\n"); } /* Third line of output */ if ( show_r ) printf("Count "); if (( show_r ) && ( show_sz )) printf("Max Min Avg Total "); if (( show_r ) && ( show_tm )) printf("Max Min Avg Total "); if ( show_w ) printf("Count "); if (( show_w ) && ( show_sz )) printf("Max Min Avg Total "); if (( show_w ) && ( show_tm )) printf("Max Min Avg Total "); printf("\n"); } @@syscall:$1:read:entry { __thread int r_f_d; __thread probev_timestamp_t r_s_t; r_s_t = timestamp(); r_f_d = __arg1; } @@syscall:$1:write:entry { __thread int wfd; __thread probev_timestamp_t w_s_t; w_s_t = timestamp(); w_f_d = __arg1; } @@syscall:$1:read:exit { __thread probev_timestamp_t r_e_t; r_e_t = timestamp(); /* This determines if we watch std-in/out/err or not */ /* if((__rv > 0) && (r_f_d > 2)) */ if (__rv > 0) { r_op_count++; if(__rv > r_sz_max) r_sz_max = __rv; if(r_sz_min == -1) r_sz_min = __rv; if(__rv < r_sz_min) r_sz_min = __rv; r_sz_total = r_sz_total + __rv; r_tm = diff_time(r_s_t, r_e_t, MILLISECONDS); r_tm_total = r_tm_total + r_tm; if(r_tm > r_tm_max) r_tm_max = r_tm; if(r_tm_min == -1) r_tm_min = r_tm; if(r_tm < r_tm_min) r_tm_min = r_tm; } } @@syscall:$1:write:exit { __thread probev_timestamp_t w_e_t; w_e_t = timestamp(); /* This determines if we watch std-in/out/err or not */ /* if ((__rv > 0) && (w_f_d > 2)) */ if (__rv > 0) { w_op_count++; if(__rv > w_sz_max) w_sz_max = __rv; if(w_sz_min == -1) w_sz_min = __rv; if(__rv < w_sz_min) w_sz_min = __rv; w_sz_total = w_sz_total + __rv; w_tm = diff_time(w_s_t, w_e_t, MILLISECONDS); w_tm_total = w_tm_total + w_tm; if(w_tm > w_tm_max) w_tm_max = w_tm; if(w_tm_min == -1) w_tm_min = w_tm; if(w_tm < w_tm_min) w_tm_min = w_tm; } } @@syscall:$1:exit:entry { exit(); } @@END { printf("Script exiting.\n"); } @@interval:*:clock:2000 { long long r_tm_avg; long long w_tm_avg; long r_sz_avg; long w_sz_avg; if(r_sz_min == -1) r_sz_min = 0; if(r_tm_min == -1) r_tm_min = 0; if(w_sz_min == -1) w_sz_min = 0; if(w_tm_min == -1) w_tm_min = 0; if ( r_op_count > 0 ) { r_sz_avg = r_sz_total / r_op_count; r_tm_avg = r_tm_total / r_op_count; } else { r_sz_avg = 0; r_tm_avg = 0; } if ( w_op_count > 0 ) { w_sz_avg = w_sz_total / w_op_count; w_tm_avg = w_tm_total / w_op_count; } else { w_sz_avg = 0; w_tm_avg = 0; } /* Refresh the header every "screen" full of data */ lprint++; if ( lprint > 19 ) { /* First line of output */ if ( show_r ) printf("Reads "); if (( show_r ) && ( show_sz )) printf("Size "); if (( show_r ) && ( show_tm )) printf("Time "); if ( show_w ) printf("Writes "); if (( show_w ) && ( show_sz )) printf("Size "); if (( show_w ) && ( show_tm )) printf("Time "); printf("\n"); /* Second line of output */ if ( show_lines ) { if ( show_r ) printf("---------- "); if (( show_r ) && ( show_sz )) printf("------------------------------------------- "); if (( show_r ) && ( show_tm )) printf("------------------------------------------- "); if ( show_w ) printf("---------- "); if (( show_w ) && ( show_sz )) printf("------------------------------------------- "); if (( show_w ) && ( show_tm )) printf("------------------------------------------- "); printf("\n"); } /* Third line of output */ if ( show_r ) printf("Count "); if (( show_r ) && ( show_sz )) printf("Max Min Avg Total "); if (( show_r ) && ( show_tm )) printf("Max Min Avg Total "); if ( show_w ) printf("Count "); if (( show_w ) && ( show_sz )) printf("Max Min Avg Total "); if (( show_w ) && ( show_tm )) printf("Max Min Avg Total "); printf("\n"); lprint = 0; } /* trace(r_op_count); */ /* Actual data output */ if ( show_r ) printf("%-10d ", r_op_count / linterval); if (( show_r ) && ( show_sz )) printf("%-10d %-10d %-10d %-10d ", r_sz_max, r_sz_min, r_sz_avg, r_sz_total); if (( show_r ) && ( show_tm )) printf("%-10d %-10d %-10d %-10d ", r_tm_max, r_tm_min, r_tm_avg, r_tm_total); if ( show_w ) printf("%-10d ", w_op_count / linterval); if (( show_w ) && ( show_sz )) printf("%-10d %-10d %-10d %-10d ", w_sz_max, w_sz_min, w_sz_avg, w_sz_total); if (( show_w ) && ( show_tm )) printf("%-10d %-10d %-10d %-10d ", w_tm_max, w_tm_min, w_tm_avg, w_tm_total); printf("\n"); /* Reset the values */ r_sz_min = -1; r_sz_max = 0; w_sz_min = -1; w_sz_max = 0; w_sz_total = 0; r_sz_total = 0; r_tm_max = 0; r_tm_min = -1; r_tm_total = 0; w_tm_max = 0; w_tm_min = -1; w_tm_total = 0; w_op_count = 0; r_op_count = 0; }