/* tprof.c */ #include #include #include #include #include "runtime.h" #include "newmacros.h" /* only for DIR_DEL macro ! */ #define MAX_HEIGHT(x,y) (x>y ? x : y) #define CMP_KEY(x,y) (x==y ? 0 : ((x Ignore _Driver */ int listedby; #define TICKSPERMOD 0 /* Default */ #define TICKS 1 #define ENTERSPERMOD 2 #define ENTERS 3 #define LISTEDBYTICKS ((listedby==TICKS)||(listedby==TICKSPERMOD)) #define LISTEDBYENTERS ((listedby==ENTERS)||(listedby==ENTERSPERMOD)) #define LISTEDBYPERMOD ((listedby==TICKSPERMOD)||(listedby==ENTERSPERMOD)) int tprof; CodePtr *ipref; int gcData; FILE *tpFILE; FILE *gdFILE; int gem_wants_the_ticks; int time_subtotal; int csubtot=0; int show_dictionary; int ticks_per_enter; double tpefactor; int enter_percentages; int assign_subfn_enters; int in_greencard; int collecting_garbage; int *last_tick; extern timer gcTime; extern timer totalTime; extern timer runTime; extern Int hpTotal; extern NodePtr hpBase; int cancel_enter = 0; int **enterPtr; typedef struct avl { struct avl *left, *right; int height; CodePtr address; char *funname; int *enters; int ticks; int g_enters; int g_ticks; } AVLnode; AVLnode *address_AVL_root; AVLnode *last_right_taken; AVLnode *lastn_tree; int **enterPtrTmp; int *in_greencard_ticks; typedef struct subtree { AVLnode **tot; AVLnode **root; } Subtree; struct sums { int total_enters; int total_ticks; int nonZeroTotalTicks; int total_g_enters; int total_g_ticks; int collect_garbage_enters; int collect_garbage_ticks; } Sums; struct mods { int premods; int usrmods; int maxmod; } Mods; static int get_height_AVL(AVLnode *tree) { if (tree == NULL) return(-1); else return(tree->height); } static void set_height_AVL(AVLnode *tree) { if (tree != NULL) tree->height = 1 + MAX_HEIGHT(get_height_AVL(tree->left), get_height_AVL(tree->right)); } static void right_rotate_AVL(AVLnode **tree) { AVLnode *old_root, *old_left, *middle; old_root = *tree; old_left = old_root->left; middle = old_left->right; old_left->right = old_root; old_root->left = middle; *tree = old_left; set_height_AVL(old_root); set_height_AVL(old_left); } static void left_rotate_AVL(AVLnode **tree) { AVLnode *old_root, *old_right, *middle; old_root = *tree; old_right = old_root->right; middle = old_right->left; old_right->left = old_root; old_root->right = middle; *tree = old_right; set_height_AVL(old_root); set_height_AVL(old_right); } static void double_right_rotate_AVL(AVLnode **tree) { left_rotate_AVL(&((*tree)->left)); right_rotate_AVL(tree); } static void double_left_rotate_AVL(AVLnode **tree) { right_rotate_AVL(&((*tree)->right)); left_rotate_AVL(tree); } static void balance_AVL(AVLnode **tree) { int left_height,right_height; AVLnode *subtree; left_height = get_height_AVL((*tree)->left); right_height = get_height_AVL((*tree)->right); if (left_height > right_height+1) { subtree = (*tree)->left; left_height = get_height_AVL(subtree->left); right_height = get_height_AVL(subtree->right); if (left_height >= right_height) right_rotate_AVL(tree); else double_right_rotate_AVL(tree); } else if (left_height+1 < right_height) { subtree = (*tree)->right; left_height = get_height_AVL(subtree->left); right_height = get_height_AVL(subtree->right); if (right_height >= left_height) left_rotate_AVL(tree); else double_left_rotate_AVL(tree); } } static void init_AVL(AVLnode **tree) { *tree = NULL; } static void insert_by_address_AVL(AVLnode **tree, CodePtr address, char *funname, int insert_mode, int setup) { AVLnode *newtree; int cmp; if (*tree==NULL) { if (insert_mode) { if(NULL == (newtree = (AVLnode*) malloc(sizeof(AVLnode)))) { fprintf(stderr,"Not enough memory for tprof.\n"); exit(-1); } newtree->left = NULL; newtree->right = NULL; newtree->height = 0; (newtree->address) = address; newtree->funname = funname; if (setup) newtree->enters = *enterPtrTmp; else { if(NULL == (newtree->enters = (int*) malloc(sizeof(int)))) { fprintf(stderr,"Not enough memory for tprof.\n"); exit(-1); } *enterPtrTmp = newtree->enters; *(newtree->enters) = 1; } newtree->g_enters = 0; newtree->ticks = 0; newtree->g_ticks = 0; *tree = newtree; } else { if (last_right_taken == NULL) fprintf(stderr,"Trying to record tick into an empty tprof tree.\n"); else { if (in_greencard) { last_right_taken->g_enters++; in_greencard_ticks = &(last_right_taken->g_ticks); if (cancel_enter) last_tick = &(last_right_taken->g_ticks); } else { last_right_taken->ticks++; if (cancel_enter) last_tick = &(last_right_taken->ticks); } } } } else { cmp = CMP_KEY(address,(*tree)->address); if (cmp==0) if (in_greencard) { (*tree)->g_enters++; in_greencard_ticks = &((*tree)->g_ticks); } else (*tree)->ticks++; else { if (cmp==-1) insert_by_address_AVL(&((*tree)->left), address, funname, insert_mode, setup); else { if (!insert_mode) last_right_taken = *tree; insert_by_address_AVL(&((*tree)->right), address, funname, insert_mode, setup); } set_height_AVL(*tree); balance_AVL(tree); } } } static void insert_by_key_AVL(AVLnode **tree, AVLnode **node) { int cmp = 0; if (*tree == NULL) { *tree = *node; } else { if (LISTEDBYTICKS) { /* listed by time */ if (cmp == 0) { /* Order by ticks (normal+g) */ cmp = CMP_KEY((*tree)->ticks+(*tree)->g_ticks,(*node)->ticks+(*node)->g_ticks); if (cmp == 0) { /* Order by enters */ cmp = CMP_KEY((*((*tree)->enters)),(*((*node)->enters))); if (cmp == 0) /* Order by funname */ cmp = strcmp((*node)->funname,(*tree)->funname); } } } else { /* listed by enters */ if (cmp == 0) { /* Order by enters */ cmp = CMP_KEY((*((*tree)->enters)),(*((*node)->enters))); if (cmp == 0) { /* Order by ticks (normal+g) */ cmp = CMP_KEY((*tree)->ticks+(*tree)->g_ticks,(*node)->ticks+(*node)->g_ticks); if (cmp == 0) /* Order by funname */ cmp = strcmp((*node)->funname,(*tree)->funname); } } } if (cmp < 0) insert_by_key_AVL(&((*tree)->left), node); else insert_by_key_AVL(&((*tree)->right), node); } } static void print_AVL_raw(AVLnode *tree, FILE *fp, int tab) { int i; if (tree != NULL) { print_AVL_raw(tree->left, fp, tab+1); for (i=0; iaddress, tree->funname, tree->ticks, *(tree->enters), tree->g_enters, tree->g_ticks); print_AVL_raw(tree->right, fp, tab+1); } return; } static void print_AVL_info(AVLnode *tree, char *module, FILE *fp) { int dotpos = -1; if (LISTEDBYTICKS) { fprintf(fp, " %5.1f ", 100*((float) (tree->ticks+tree->g_ticks))/Sums.nonZeroTotalTicks); if (gem_wants_the_ticks) fprintf(fp, "[%d] ", tree->ticks+tree->g_ticks); if (time_subtotal) { csubtot += tree->ticks+tree->g_ticks; fprintf(fp, "%5.1f ", 100*((float)csubtot)/Sums.nonZeroTotalTicks); } } if (tree->g_enters) fprintf(fp, "%10d ", tree->g_enters); else fprintf(fp, "%10d ", *(tree->enters)); if (LISTEDBYENTERS) { fprintf(fp, " %5.1f ", 100*((float) (tree->ticks+tree->g_ticks))/Sums.nonZeroTotalTicks); if (gem_wants_the_ticks) fprintf(fp, "[%10d] ", tree->ticks+tree->g_ticks); if (time_subtotal) { csubtot += tree->ticks+tree->g_ticks; fprintf(fp, "%5.1f ", 100*((float)csubtot)/Sums.nonZeroTotalTicks); } } if (ticks_per_enter) fprintf(fp, "%10d ", (int)(tpefactor*(tree->ticks+tree->g_ticks)/((tree->g_enters)?(tree->g_enters):*(tree->enters)))); if (tree->g_enters) fprintf(fp, "*"); else fprintf(fp, " "); if (LISTEDBYPERMOD) { dotpos = strlen(module); if ((strncmp(tree->funname,module,dotpos)!=0) || (*(tree->funname+dotpos)!='.')) dotpos = -1; } fprintf(fp, "%s\n", (tree->funname)+dotpos+1); } static char* print_AVL_node(AVLnode *tree, Subtree *subtree, char *module, int norc, FILE *fp) { char *fnp; char sp; char *mod = module; if (tree != NULL) { mod = print_AVL_node(tree->left, subtree, mod, norc, fp); fnp = tree->funname; if (norc) { int dispn = (*fnp=='+') && (LISTEDBYPERMOD); mod = fnp+3; if(strlen(mod)<7) sp='\t'; else sp=' '; if (dispn) fprintf(fp, "\n----------------------------------------------------------"); if (dispn || (*fnp=='-')) { if(LISTEDBYENTERS) { fprintf(fp, "\n%s%c\t %10d calls", mod, sp, *(tree->enters)); if(enter_percentages) fprintf(fp, " %5.1f%% calls", 100*((float) *(tree->enters))/Sums.total_enters); fprintf(fp, "\t%5.1f%% time", 100*((float) tree->ticks)/Sums.nonZeroTotalTicks); if (gem_wants_the_ticks) fprintf(fp, "\t[%d]",tree->ticks); if (ticks_per_enter) fprintf(fp, "\t%10d tpe", (int)(tpefactor*(tree->ticks)/(*(tree->enters)))); fprintf(fp, "\n"); } else { fprintf(fp, "\n%s%c\t %5.1f%% time", mod, sp, 100*((float) tree->ticks)/Sums.nonZeroTotalTicks); if (gem_wants_the_ticks) fprintf(fp, "\t[%d]",tree->ticks); fprintf(fp, "\t%10d calls", *(tree->enters)); if(enter_percentages) fprintf(fp, " %5.1f%% calls", 100*((float) *(tree->enters))/Sums.total_enters); if (ticks_per_enter) fprintf(fp, "\t%10d tpe", (int)(tpefactor*(tree->ticks)/(*(tree->enters)))); fprintf(fp, "\n"); } if (dispn) { fprintf(fp, "----------------------------------------------------------\n"); if(LISTEDBYENTERS) { fprintf(fp, " # calls %% time "); if (time_subtotal) fprintf(fp, " ctot "); } else { fprintf(fp, " %% time "); if (time_subtotal) fprintf(fp, " ctot "); fprintf(fp, " # calls "); } if (ticks_per_enter) fprintf(fp, " tpe"); fprintf(fp, "\n"); } } if (*fnp=='+') { csubtot = 0; print_AVL_node(*(subtree[tree->height].root), subtree, mod, 0, fp); } } else print_AVL_info(tree, mod, fp); mod = print_AVL_node(tree->right, subtree, mod, norc, fp); } return mod; } int rearrange_AVL(AVLnode **address_tree, int mod, Subtree *subtree) { AVLnode **lft, **rht; char *fnp; if (*address_tree != NULL) { if(NULL == (lft = (AVLnode**) malloc(sizeof(AVLnode*)))) { fprintf(stderr,"Not enough memory for tprof.\n"); exit(-1); } if(NULL == (rht = (AVLnode**) malloc(sizeof(AVLnode*)))) { fprintf(stderr,"Not enough memory for tprof.\n"); exit(-1); } *lft = (*address_tree)->left; *rht = (*address_tree)->right; ((*address_tree)->left) = NULL; ((*address_tree)->right) = NULL; if (*lft != NULL) mod = rearrange_AVL(lft, mod, subtree); free(lft); fnp = (*address_tree)->funname; if ((*fnp=='+') || (*fnp=='-')) { if ((*(fnp+1)=='+') || (*(fnp+1)=='-')) mod = Mods.maxmod++; else mod = 10*(*(fnp+1)-48)+(*(fnp+2)-48); if ((*fnp=='+') && !(LISTEDBYPERMOD) && (mod>0)) mod = Mods.premods; (*address_tree)->height = mod; if (*fnp=='+') { /* '+' */ if (*(subtree[mod].tot) == NULL) { *((*address_tree)->enters) = 0; *subtree[mod].tot = *address_tree; } lastn_tree = *(subtree[mod].tot); } else { /* '-' */ if (*(subtree[mod].tot) == NULL) { *subtree[mod].tot = *address_tree; } else { (*subtree[mod].tot)->ticks += (*address_tree)->ticks; (*subtree[mod].tot)->g_enters += (*address_tree)->g_enters; (*subtree[mod].tot)->g_ticks += (*address_tree)->g_ticks; } } } else { int e = *((*address_tree)->enters); int ge = (*address_tree)->g_enters; if ((*fnp=='P') && (!show_dictionary)) { char *lastdot = strrchr(fnp,'.'); if ((lastdot!=NULL) && (*(lastdot+1)>='A') && (*(lastdot+1)<='Z')) { e=0; ge=0; } } if (e+ge>0) { *(lastn_tree->enters) += e; lastn_tree->ticks += (*address_tree)->ticks; lastn_tree->g_enters += ge; lastn_tree->g_ticks += (*address_tree)->g_ticks; insert_by_key_AVL(subtree[mod].root, address_tree); } } if (*rht != NULL) mod = rearrange_AVL(rht, mod, subtree); free(rht); } return mod; } void output_AVL_as_orderd_table(AVLnode **tree, FILE *fp) { AVLnode *c_ticks_AVL_root; AVLnode *n_ticks_AVL_root; Subtree subtree[Mods.premods+Mods.usrmods+1]; int i; char *c; if (*tree != NULL) { init_AVL(&c_ticks_AVL_root); init_AVL(&n_ticks_AVL_root); for (i=0;ienters)+(*tmp)->g_enters>0) { if (*((*tmp)->funname)=='+') insert_by_key_AVL(&n_ticks_AVL_root, tmp); else insert_by_key_AVL(&c_ticks_AVL_root, tmp); Sums.total_ticks += (*tmp)->ticks + (*tmp)->g_ticks; Sums.total_enters += *((*tmp)->enters) + (*tmp)->g_enters; Sums.total_g_ticks += (*tmp)->g_ticks; Sums.total_g_enters += (*tmp)->g_enters; } } if (Sums.total_ticks) Sums.nonZeroTotalTicks = Sums.total_ticks; else Sums.nonZeroTotalTicks = 1; if (ticks_per_enter) tpefactor = 100000 * pow(10, (int)log10(Sums.total_enters)) / Sums.nonZeroTotalTicks; c = print_AVL_node(n_ticks_AVL_root, subtree, "", 1, fp); c = print_AVL_node(c_ticks_AVL_root, subtree, "", 1, fp); fprintf(fp, "\n"); if(LISTEDBYENTERS) { if(Sums.total_g_enters) { fprintf(fp, "foreign lang\t %10d calls", Sums.total_g_enters); if(enter_percentages) fprintf(fp, " %5.1f%% calls", 100*((float) Sums.total_g_enters)/Sums.total_enters); fprintf(fp, "\t%5.1f%% time", 100*((float) Sums.total_g_ticks)/Sums.nonZeroTotalTicks); if (ticks_per_enter) fprintf(fp, "\t%10d tpe", (int)(tpefactor*(Sums.total_g_ticks)/(Sums.total_g_enters))); fprintf(fp, "\n\n"); } fprintf(fp, "garbage collect\t %10d calls", Sums.collect_garbage_enters); if(enter_percentages) fprintf(fp, " %5.1f%% calls", 100*((float) Sums.collect_garbage_enters)/Sums.total_enters); fprintf(fp, "\t%5.1f%% time", 100*((float) Sums.collect_garbage_ticks)/Sums.nonZeroTotalTicks); if (ticks_per_enter) fprintf(fp, "\t%10d tpe", (int)(tpefactor*(Sums.collect_garbage_ticks) / (Sums.collect_garbage_enters))); fprintf(fp, "\n\nTime figures based on %d samples\n\n", Sums.total_ticks); } else { if(Sums.total_g_enters) { fprintf(fp, "foreign lang\t %5.1f%% time\t%10d calls", 100*((float) Sums.total_g_ticks)/Sums.nonZeroTotalTicks, Sums.total_g_enters); if(enter_percentages) fprintf(fp, " %5.1f%% calls", 100*((float) Sums.total_g_enters)/Sums.total_enters); if (ticks_per_enter) fprintf(fp, "\t%10d tpe", (int)(tpefactor*(Sums.total_g_ticks)/(Sums.total_g_enters))); fprintf(fp, "\n\n"); } fprintf(fp, "garbage collect\t %5.1f%% time\t%10d calls", 100*((float) Sums.collect_garbage_ticks)/Sums.nonZeroTotalTicks, Sums.collect_garbage_enters); if(enter_percentages) fprintf(fp, " %5.1f%% calls", 100*((float) Sums.collect_garbage_enters)/Sums.total_enters); if (ticks_per_enter) fprintf(fp, "\t%10d tpe", (int)(tpefactor*(Sums.collect_garbage_ticks) / (Sums.collect_garbage_enters))); fprintf(fp, "\n\nTime figures based on %d samples\n\n", Sums.total_ticks); } } } /****************************************************** tprof stuff */ void tprofStart(void) { if(!timeSample && !profileInterval) { timeSample=1; profileInterval = (double) 0.1; /* 100ms */ } if(timeSample) { #if defined(__arm) || defined(__CYGWIN32__) || defined(__MINGW32__) fprintf(stderr,"No timed profiling availible on this machine.\n"); exit(-1); #else setuptimer(); #endif } init_AVL(&address_AVL_root); if (assign_subfn_enters) { tprofTMIncludePrelSubfn(); tprofTMIncludeUsrSubfn(); } Mods.usrmods = tprofTMInitTreeUsr(); Mods.premods = tprofTMInitTreePrel3(); Mods.premods = tprofTMInitTreePrel2(); Mods.premods = tprofTMInitTreePrel1(); return; } void tprofInclude(char *module) { int mod_len,i,j; int listpermod=0; char *args; mod_len = strlen(module); args = module; for(i=0;i