"Fossies" - the Fresh Open Source Software Archive

Member "FunctionCheck-3.2.0/src/fcmanager/fc_context.c" (26 May 2012, 17534 Bytes) of package /linux/privat/old/FunctionCheck-3.2.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * FunctionCheck profiler
    3  * (C) Copyright 2000-2012 Yannick Perret
    4  * 
    5  *  This program is free software; you can redistribute it and/or
    6  *  modify it under the terms of the GNU General Public License as
    7  *  published by the Free Software Foundation; either version 2 of the
    8  *  License, or (at your option) any later version.
    9  *
   10  *  This program is distributed in the hope that it will be useful,
   11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13  *  General Public License for more details.
   14  *
   15  *  You should have received a copy of the GNU General Public License
   16  *  along with this program; if not, write to the Free Software
   17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  */
   19 /* fc_context.c: manage contexts for profile stats */
   20 
   21 #include <time.h>
   22 #include <limits.h>
   23 #include "fc_context.h"
   24 #include "fc_functions.h"
   25 #include "fc_com.h"
   26 #include "fc_com_manager.h"
   27 #include "fc_global.h"
   28 
   29 /* the active context */
   30 FC_Context *fc_current_context = NULL;
   31 int fc_current_context_id = 0;
   32 
   33 /* default values for stack, func et graph sizes */
   34 int fc_ctx_stack_size = 128;
   35 int fc_ctx_func_size = 256;
   36 int fc_ctx_graph_size = 512;
   37 int fc_ctx_memory_size = 512;
   38 char fc_ctx_name[512] = {'b', 'a', 'd', '_', 'i', 'n', 'i', 't', '\0'};
   39 char fc_ctx_path[512] = {'\0'};
   40 int fc_ctx_usepid = 0;
   41 
   42 /* starting and ending time */
   43 struct tm fc_ctx_start_time;
   44 struct tm fc_ctx_stop_time;
   45 
   46 /* unique ID for this particular execution */
   47 char fc_ctx_unique_id[256] = "ndef";
   48 
   49 /* mode of the profile */
   50 int fc_ctx_pmode = FC_MODE_SINGLE;
   51 
   52 /* list of existing contexts (for management purpose) */
   53 FC_Context **fc_context_list = NULL;
   54 int fc_nb_context_list = 0;
   55 int fc_nb_context_max = 0;
   56 
   57 /** current list of dynamic libraries **/
   58 FC_LDYN *fc_list_ldyn = NULL;
   59 int fc_nb_list_ldyn = 0;
   60 
   61 /* set the current profile mode */
   62 void fc_context_set_mode(int mode)
   63 {
   64     fc_ctx_pmode = mode;
   65 }
   66 
   67 /* add an entry in the ldyn list */
   68 int fc_ldyn_add(FC_LDYN *ldyn)
   69 {
   70     int i;
   71 
   72     /* first check if the entry still exists */
   73     for (i = 0; i < fc_nb_list_ldyn; i++)
   74     {
   75         if (fc_list_ldyn[i].addr == ldyn->addr)
   76             return (1);
   77     }
   78 
   79     /* reallocate the table */
   80     if (fc_nb_list_ldyn == 0)
   81     {
   82         fc_nb_list_ldyn = 1;
   83         fc_list_ldyn = malloc(sizeof (FC_LDYN) * fc_nb_list_ldyn);
   84     }
   85     else
   86     {
   87         fc_nb_list_ldyn++;
   88         fc_list_ldyn = realloc(fc_list_ldyn, sizeof (FC_LDYN) * fc_nb_list_ldyn);
   89     }
   90 
   91     if (fc_list_ldyn == NULL)
   92     {
   93         fc_nb_list_ldyn = 0;
   94         fc_message("cannot (re)allocate %d bytes for dynamic lib list.",
   95                    sizeof (FC_LDYN) * fc_nb_list_ldyn);
   96         return (0);
   97     }
   98 
   99     /* add the element */
  100     fc_list_ldyn[fc_nb_list_ldyn - 1] = *ldyn;
  101     return (1);
  102 }
  103 
  104 /* loop on contexts */
  105 int fc_context_loops = 0;
  106 
  107 FC_Context *fc_context_first()
  108 {
  109     fc_context_loops = 0;
  110     if (fc_nb_context_list == 0)
  111         return (NULL);
  112     return (fc_context_list[fc_context_loops]);
  113 }
  114 
  115 FC_Context *fc_context_next()
  116 {
  117     fc_context_loops++;
  118     if (fc_context_loops >= fc_nb_context_list)
  119     {
  120         fc_context_loops = 0;
  121         return (NULL);
  122     }
  123     return (fc_context_list[fc_context_loops]);
  124 }
  125 
  126 /* register a new context in the list */
  127 void fc_context_register(FC_Context *ctx)
  128 {
  129     if (fc_context_list == NULL)
  130     {/* allocate the table */
  131         fc_context_list = malloc(sizeof (FC_Context*)*64);
  132         if (fc_context_list == NULL)
  133         {
  134             fc_message("cannot allocate initial context list!");
  135             fc_message_fatal(FC_ERR_MEM, "all data lost!");
  136         }
  137         fc_nb_context_max = 64;
  138     }
  139 
  140     fc_context_list[fc_nb_context_list++] = ctx;
  141     fc_debug("register context %d", fc_nb_context_list - 1);
  142     if (fc_nb_context_list == fc_nb_context_max)
  143     {/* reallocate the table */
  144         fc_context_list = realloc(fc_context_list, sizeof (FC_Context*)*
  145                                   (fc_nb_context_max + 64));
  146         if (fc_context_list == NULL)
  147         {
  148             fc_message("cannot reallocate context list!");
  149             fc_message_fatal(FC_ERR_MEM, "all data lost!");
  150         }
  151         fc_nb_context_max += 64;
  152     }
  153 }
  154 
  155 /* create a new context */
  156 FC_Context *fc_context_create(int id, unsigned int first, int stack_size,
  157         int func_size, int graph_size, int memory_size)
  158 {
  159     int i;
  160     FC_Context *tmp;
  161 
  162     tmp = malloc(sizeof (FC_Context));
  163     if (tmp == NULL)
  164     {
  165         fc_message("cannot allocate %d bytes for a context.", sizeof (FC_Context));
  166         return (NULL);
  167     }
  168 
  169     /* init sub-structures */
  170     tmp->graph = fc_graph_init(graph_size > 0 ? graph_size : 512);
  171     if (tmp->graph == NULL)
  172     {
  173         fc_message("cannot finish context initialization (graph).");
  174         free(tmp);
  175         return (NULL);
  176     }
  177 
  178     tmp->stack = fc_stack_create(stack_size > 0 ? stack_size : 128);
  179     if (tmp->stack == NULL)
  180     {
  181         fc_message("cannot finish context initialization (stack).");
  182         fc_graph_free(tmp->graph);
  183         free(tmp);
  184         return (NULL);
  185     }
  186 
  187     tmp->functions = fc_fhash_create(func_size > 0 ? func_size : 512);
  188     if (tmp->functions == NULL)
  189     {
  190         fc_message("cannot finish context initialization (functions).");
  191         fc_graph_free(tmp->graph);
  192         fc_stack_delete(tmp->stack);
  193         free(tmp);
  194         return (NULL);
  195     }
  196 
  197     /* TODO: real initialization */
  198     tmp->memory = fc_memory_create(memory_size > 0 ? memory_size : 512);
  199     if (tmp->memory == NULL)
  200     {
  201         fc_message("cannot finish context initialization (memory).");
  202         fc_graph_free(tmp->graph);
  203         fc_stack_delete(tmp->stack);
  204         fc_fhash_delete(tmp->functions);
  205         free(tmp);
  206         return (NULL);
  207     }
  208 
  209     tmp->id = id;
  210     tmp->pid = 0;
  211     tmp->first_time = (unsigned long long) first;
  212     tmp->last_time = (unsigned long long) first;
  213     tmp->ulast_time = first;
  214     tmp->time_pad = 0;
  215 
  216     /* 1st call: set the default values */
  217     if (fc_current_context == NULL)
  218     {
  219         fc_current_context = tmp;
  220         fc_current_context_id = id;
  221         fc_ctx_stack_size = stack_size;
  222         fc_ctx_func_size = func_size;
  223         fc_ctx_graph_size = graph_size;
  224         fc_ctx_memory_size = memory_size;
  225         /* set the unique ID */
  226         sprintf(fc_ctx_unique_id, "%d_%d_%d", (int) getpid(), tmp->id,
  227                 (int) time(NULL));
  228     }
  229     else
  230     {/* in case of fork mode, create a set of empty functions 
  231         to allow exits from unknown functions for childs */
  232         if (fc_mcom_mode == FC_MODE_FORK)
  233         {
  234             fc_current_context = tmp;
  235             for (i = 0; i < 16; i++)
  236                 fc_functions_enter(NULL, NULL, first);
  237         }
  238     }
  239 
  240     return (tmp);
  241 }
  242 
  243 /* set the current context regards to the ID (create it if needed) */
  244 void fc_context_set(int id, unsigned int first_time)
  245 {
  246     int i;
  247     FC_Context *ctx;
  248 
  249     /* still the good context */
  250     if (id == fc_current_context_id)
  251         return;
  252 
  253     /* search the context */
  254     for (i = 0; i < fc_nb_context_list; i++)
  255     {
  256         if (fc_context_list[i]->id == id)
  257         {/* set the context */
  258             fc_debug("set context %d", i);
  259             fc_current_context = fc_context_list[i];
  260             fc_current_context_id = id;
  261             return;
  262         }
  263     }
  264 
  265     /* not found. create a new one */
  266     ctx = fc_context_create(id, first_time, fc_ctx_stack_size,
  267                             fc_ctx_func_size, fc_ctx_graph_size,
  268                             fc_ctx_memory_size);
  269     if (ctx != NULL)
  270     {
  271         fc_context_register(ctx);
  272         fc_current_context = ctx;
  273         fc_current_context_id = id;
  274         fc_debug("new ID (%d)", id);
  275     }
  276     else
  277     {/* this is a priori fatal... */
  278         fc_message("new context not created.");
  279     }
  280 }
  281 
  282 /* delete a context */
  283 void fc_context_delete(FC_Context *ctx)
  284 {
  285     /* delete parts of the structure */
  286     fc_fhash_delete(ctx->functions);
  287     fc_stack_delete(ctx->stack);
  288     fc_graph_free(ctx->graph);
  289     fc_memory_delete(ctx->memory);
  290     /* delete the structure */
  291     free(ctx);
  292 }
  293 
  294 /* compute the context file name */
  295 int fc_context_getname(FC_Context *ctx, char *name)
  296 {
  297     char tname[512];
  298 
  299     /* effective name */
  300     if (fc_ctx_usepid)
  301         sprintf(tname, "%s.%d.fc", fc_ctx_name, (int) getpid());
  302     else
  303         sprintf(tname, "%s.fc", fc_ctx_name);
  304 
  305     if (fc_nb_context_list == 1) /* only one process */
  306         sprintf(name, "%s/%s", fc_ctx_path, tname);
  307     else
  308         sprintf(name, "%s/%s.%d", fc_ctx_path, tname, ctx->id);
  309 
  310     return (1);
  311 }
  312 
  313 /* dump an arc to the given FILE */
  314 void fc_arc_dump(unsigned long long key, int val, void *ptr1, void *ptr2, void *user_data)
  315 {
  316     void *from, *to;
  317     unsigned long long mask = 0;
  318     unsigned int i;
  319 
  320     /* mask for the 1st word */
  321     for (i = 0; i<sizeof (int) *8; i++)
  322     {
  323         mask |= ((unsigned long long) 1 << i);
  324     }
  325 
  326     /* extract from/to */
  327     to = (void*) ((unsigned int) (key & mask));
  328     from = (void*) ((unsigned int) ((key >> (sizeof (int) *8)) & mask));
  329 
  330     fprintf((FILE*) user_data, "%p %p %d\n", from, to, val);
  331 }
  332 
  333 /* save a given context */
  334 int fc_context_save(FC_Context *ctx)
  335 {
  336     char fname[512];
  337     FILE *f;
  338     int i, j, nbl, nbf, nbr;
  339 
  340     /* compute the file name */
  341     fc_context_getname(ctx, fname);
  342 
  343     if ((f = fopen(fname, "w")) == NULL)
  344     {
  345         fc_message("cannot create profile file '%s'.", fname);
  346         return (0);
  347     }
  348 
  349     /* save the header */
  350     fprintf(f, "%s\n", FC_CTX_HEADER);
  351     /* the unique ID */
  352     fprintf(f, "%s\n", fc_ctx_unique_id);
  353     /* time mode */
  354     fprintf(f, "%d\n", fc_get_time_type());
  355     /* profile mode */
  356     fprintf(f, "%d\n", fc_ctx_pmode);
  357     /* ID */
  358     fprintf(f, "%d\n", ctx->id);
  359     /* Parent ID */
  360     fprintf(f, "%d\n", ctx->pid);
  361     /* execution time */
  362     fprintf(f, "%lld\n", ctx->last_time - ctx->first_time);
  363     /* save call-graph (arcs) */
  364     fprintf(f, "%d\n", (int) fc_lhash_size(ctx->graph));
  365     /* dump each data */
  366     fc_lhash_foreach(ctx->graph, fc_arc_dump, (void *) f);
  367 
  368     /* save functions stats */
  369     /* check the real number of functions */
  370     j = 0;
  371     for (i = 0; i < ctx->functions->current_size; i++)
  372     {
  373         if (ctx->functions->functions[i].symbol != NULL)
  374         {
  375             j++;
  376         }
  377     }
  378 
  379     fprintf(f, "%d\n", j);
  380     for (i = 0; i < ctx->functions->current_size; i++) /*this may be in fc_hash */
  381     {
  382         if (ctx->functions->functions[i].symbol != NULL)
  383             fprintf(f, "%p %u %lld %lld %lld %lld %lld %lld\n",
  384                     ctx->functions->functions[i].symbol,
  385                     ctx->functions->functions[i].calls,
  386                     ctx->functions->functions[i].local_time,
  387                     ctx->functions->functions[i].total_time,
  388                     ctx->functions->functions[i].min_time,
  389                     ctx->functions->functions[i].max_time,
  390                     ctx->functions->functions[i].min_ltime,
  391                     ctx->functions->functions[i].max_ltime);
  392     }
  393 
  394     /* list of dynamic lib */
  395     fprintf(f, "%d\n", fc_nb_list_ldyn);
  396     for (i = 0; i < fc_nb_list_ldyn; i++)
  397     {
  398         fprintf(f, "%p %s\n", fc_list_ldyn[i].addr, fc_list_ldyn[i].name);
  399     }
  400 
  401     /* list of memory leaks */
  402     if ((ctx->memory == NULL) || (ctx->memory->list == NULL))
  403     {/* no entry */
  404         fprintf(f, "0\n");
  405         fprintf(f, "0\n");
  406         fprintf(f, "0\n");
  407         fclose(f);
  408     }
  409 
  410     /* # of elements */
  411     nbl = 0;
  412     nbr = 0;
  413     nbf = 0;
  414     for (i = 0; i < ctx->memory->nb_elements; i++)
  415     {
  416         if (ctx->memory->list[i].set)
  417         {
  418             if (ctx->memory->list[i].size == UINT_MAX)
  419             {/* invalid free or realloc */
  420                 if (ctx->memory->list[i].realloc_place == NULL)
  421                 {/* free */
  422                     nbf++;
  423                 }
  424                 else
  425                 {/* realloc */
  426                     nbr++;
  427                 }
  428             }
  429             else
  430             {/* memory leak */
  431                 nbl++;
  432             }
  433         }
  434     }
  435 
  436     /* leaks */
  437     fprintf(f, "%d\n", nbl);
  438     for (i = 0; i < ctx->memory->nb_elements; i++)
  439     {
  440         if (ctx->memory->list[i].set)
  441         {
  442             if (ctx->memory->list[i].size != UINT_MAX)
  443             {
  444                 fprintf(f, "%p %u %p %p", ctx->memory->list[i].pointer,
  445                         ctx->memory->list[i].size, ctx->memory->list[i].alloc_place,
  446                         ctx->memory->list[i].realloc_place);
  447                 /* call-stack */
  448                 j = 0;
  449                 while ((j < fc_memory_stack_size) && (ctx->memory->list[i].alloc_stack[j] != NULL))
  450                 {
  451                     fprintf(f, " %p", ctx->memory->list[i].alloc_stack[j]);
  452                     j++;
  453                 }
  454                 /* end of list */
  455                 fprintf(f, " %p\n", NULL);
  456             }
  457         }
  458     }
  459 
  460     /* invalid free */
  461     fprintf(f, "%d\n", nbf);
  462     for (i = 0; i < ctx->memory->nb_elements; i++)
  463     {
  464         if (ctx->memory->list[i].set)
  465         {
  466             if ((ctx->memory->list[i].size == UINT_MAX) &&
  467                     (ctx->memory->list[i].alloc_place != NULL))
  468             {
  469                 fprintf(f, "%p %p", ctx->memory->list[i].alloc_place,
  470                         ctx->memory->list[i].pointer);
  471                 /* call-stack */
  472                 j = 0;
  473                 while ((j < fc_memory_stack_size) && (ctx->memory->list[i].alloc_stack[j] != NULL))
  474                 {
  475                     fprintf(f, " %p", ctx->memory->list[i].alloc_stack[j]);
  476                     j++;
  477                 }
  478                 /* end of list */
  479                 fprintf(f, " %p\n", NULL);
  480             }
  481         }
  482     }
  483 
  484     /* invalid realloc */
  485     fprintf(f, "%d\n", nbr);
  486     for (i = 0; i < ctx->memory->nb_elements; i++)
  487     {
  488         if (ctx->memory->list[i].set)
  489         {
  490             if ((ctx->memory->list[i].size == UINT_MAX) &&
  491                     (ctx->memory->list[i].realloc_place != NULL))
  492             {
  493                 fprintf(f, "%p %p", ctx->memory->list[i].realloc_place,
  494                         ctx->memory->list[i].pointer);
  495                 /* call-stack */
  496                 j = 0;
  497                 while ((j < fc_memory_stack_size) && (ctx->memory->list[i].alloc_stack[j] != NULL))
  498                 {
  499                     fprintf(f, " %p", ctx->memory->list[i].alloc_stack[j]);
  500                     j++;
  501                 }
  502                 /* end of list */
  503                 fprintf(f, " %p\n", NULL);
  504             }
  505         }
  506     }
  507 
  508     fclose(f);
  509     return (0);
  510 }
  511 
  512 /* save all existing contexts */
  513 int fc_context_save_all()
  514 {
  515     int i, ret;
  516     char name[512];
  517     FILE *f;
  518 
  519     ret = 1;
  520     for (i = 0; i < fc_nb_context_list; i++)
  521         ret &= fc_context_save(fc_context_list[i]);
  522 
  523     /* if needed, create the execution-tree of processes */
  524     if (fc_nb_context_list > 1)
  525     {
  526         if (fc_ctx_usepid)
  527             sprintf(name, "%s/%s.%d.fcd", fc_ctx_path, fc_ctx_name, (int) getpid());
  528         else
  529             sprintf(name, "%s/%s.fcd", fc_ctx_path, fc_ctx_name);
  530 
  531         if ((f = fopen(name, "w")) == NULL)
  532         {
  533             fc_message("cannot create FunctionCheck descriptor file '%s'.", name);
  534             return (0);
  535         }
  536 
  537         fc_message("Profiles descriptor file is '%s'", name);
  538         fprintf(f, "FunctionCheck descriptor file.\n");
  539         fprintf(f, "%d processes treated.\n", fc_nb_context_list);
  540         fprintf(f, "Treatments started at: %d/%02d/%02d %02d:%02d:%02d\n",
  541                 fc_ctx_start_time.tm_year + 1900, fc_ctx_start_time.tm_mon + 1,
  542                 fc_ctx_start_time.tm_mday, fc_ctx_start_time.tm_hour,
  543                 fc_ctx_start_time.tm_min, fc_ctx_start_time.tm_sec);
  544         fprintf(f, "Treatments ended at: %d/%02d/%02d %02d:%02d:%02d\n",
  545                 fc_ctx_stop_time.tm_year + 1900, fc_ctx_stop_time.tm_mon + 1,
  546                 fc_ctx_stop_time.tm_mday, fc_ctx_stop_time.tm_hour,
  547                 fc_ctx_stop_time.tm_min, fc_ctx_stop_time.tm_sec);
  548         fprintf(f, "\n");
  549         for (i = 0; i < fc_nb_context_list; i++)
  550         {
  551             fc_context_getname(fc_context_list[i], name);
  552             fprintf(f, "Process id: %d\n", fc_context_list[i]->id);
  553             if (fc_context_list[i]->pid != 0)
  554                 fprintf(f, "    parent: %d\n", fc_context_list[i]->pid);
  555             else
  556                 fprintf(f, "    parent: pthread_create\n");
  557             fprintf(f, "      file: %s\n", name);
  558             fprintf(f, "\n");
  559         }
  560         fclose(f);
  561     }
  562     else
  563     {
  564         fc_context_getname(fc_context_list[i], name);
  565         fc_message("Profile file is '%s'", name);
  566     }
  567 
  568     return (ret);
  569 }
  570 
  571 /* set default values */
  572 inline void fc_context_set_functions(int n)
  573 {
  574     fc_ctx_func_size = n;
  575 }
  576 
  577 inline void fc_context_set_graph(int n)
  578 {
  579     fc_ctx_graph_size = n;
  580 }
  581 
  582 inline void fc_context_set_stack(int n)
  583 {
  584     fc_ctx_stack_size = n;
  585 }
  586 
  587 inline void fc_context_set_memory(int n)
  588 {
  589     fc_ctx_memory_size = n;
  590 }
  591 
  592 inline void fc_context_set_name(char *n)
  593 {
  594     sprintf(fc_ctx_name, "%s", n);
  595 }
  596 
  597 inline void fc_context_set_path(char *n)
  598 {
  599     sprintf(fc_ctx_path, "%s", n);
  600 }
  601 
  602 inline void fc_context_set_usepid(int n)
  603 {
  604     fc_ctx_usepid = n;
  605 }
  606 
  607 inline void fc_context_set_starttime(time_t start)
  608 {
  609     fc_ctx_start_time = *(localtime(&start));
  610 }
  611 
  612 inline void fc_context_set_stoptime(time_t stop)
  613 {
  614     fc_ctx_stop_time = *(localtime(&stop));
  615 }
  616 
  617