/* lil-gp Genetic Programming System, version 1.0, 11 July 1995 * Copyright (C) 1995 Michigan State University * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Douglas Zongker (zongker@isl.cps.msu.edu) * Dr. Bill Punch (punch@isl.cps.msu.edu) * * Computer Science Department * A-714 Wells Hall * Michigan State University * East Lansing, Michigan 48824 * USA * * This parallel version based on PVM is an extension of version 1.1 * of Lil-gp. * * Johan Parent (johan@info.vub.ac.be) * * Faculty of Applied Sciences (Engineering Faculty) * Building K, Computer Science Department * Vrije Universiteit Brussel * Pleinlaan 2, 1050 Etterbeek * Belgium * */ #include #ifdef MEMORY_LOG extern FILE *mlog; #endif #ifdef _PARALLEL_H #define _DEBUG_mem_not #define mem_out stdout Mem_info *head_of_report = NULL; unsigned long report_length = 0; unsigned long seq_number = 0; unsigned long alloc_high = 0; /* Upperbound of allocs (bytes) */ unsigned long alloc_total = 0; /* Sum of all allocs (bytes) */ unsigned long alloc_max = 0; /* Biggest chunk (bytes) */ unsigned long alloc_now = 0; /* Currently allocated (bytes) */ unsigned long alloc_calls = 0; /* Number of allocations (/) */ unsigned long free_total = 0; /* Sum of dealloced bytes (bytes) */ unsigned long free_calls = 0; /* Number of deallocations (/) */ unsigned long realloc_total = 0; /* Sum of reallocs (bytes) */ unsigned long realloc_max = 0; /* Biggest chunk (bytes) */ unsigned long realloc_calls = 0; /* Number of reallocations (/) */ #endif static int totalalloc = 0; static int maxalloc = 0; static int freealloc = 0; static int curalloc = 0; static int malloccalls = 0; static int freecalls = 0; static int realloccalls = 0; /* get_memory_stats() * * returns the memory statistics stored in static global * variables. */ void get_memory_stats ( int *total, int *free, int *max, int *mallocc, int *reallocc, int *freec ) { *total = totalalloc; *free = freealloc; *max = maxalloc; *mallocc = malloccalls; *reallocc = realloccalls; *freec = freecalls; } /* track_malloc() * * like malloc(), but tracks memory block size. */ void *track_malloc ( int size ) { unsigned char *p; if ( size == 0 ) return NULL; p = (unsigned char *)malloc ( size+EXTRAMEM ); if ( p == NULL ) return NULL; ++malloccalls; totalalloc += size; curalloc += size; if ( curalloc > maxalloc ) maxalloc = curalloc; *(int *)p = size; #ifdef MEMORY_LOG fprintf ( mlog, "MALLOC %d %08x\n", size, (void *)(p+EXTRAMEM) ); fflush ( mlog ); #endif return (void *)(p+EXTRAMEM); } /* track_free() * * like free(), but tracks memory block size. use with pointers * returned by track_malloc(). */ void track_free ( void *p ) { int size; if ( p == NULL ) return; #ifdef MEMORY_LOG fprintf ( mlog, "FREE %08x\n", p ); fflush ( mlog ); #endif size = *(int *)((unsigned char *)p-EXTRAMEM); ++freecalls; curalloc -= size; freealloc += size; free ( (unsigned char *)p-EXTRAMEM ); } /* *track_realloc() * * like realloc(), but tracks memory block size. use with pointers * returned by track_malloc(). */ void *track_realloc ( void *p, int newsize ) { int size, change; if ( p == NULL ) return MALLOC ( newsize ); size = *(int *)((unsigned char *)p-EXTRAMEM); change = newsize-size; curalloc += change; if ( curalloc > maxalloc ) maxalloc = curalloc; if ( change > 0 ) totalalloc += change; else freealloc -= change; ++realloccalls; #ifdef MEMORY_LOG fprintf ( mlog, "REALLOC %08x", p ); #endif p = realloc ( (unsigned char *)p-EXTRAMEM, newsize+EXTRAMEM ); if ( p == NULL ) return NULL; *(int *)p = newsize; #ifdef MEMORY_LOG fprintf ( mlog, " %d %08x\n", newsize, (void *)((unsigned char *)p+EXTRAMEM) ); fflush ( mlog ); #endif return (void *)((unsigned char *)p+EXTRAMEM); } #ifdef _PARALLEL_H /* malloc_info() * * allocate some memory for stats */ Mem_info *malloc_info (void) { Mem_info *ret; ret = (Mem_info *) malloc ( sizeof(Mem_info)); if (ret == NULL) { fprintf(stderr, "Could not allocate memory in the malloc_info()\n"); exit (-1); } /* Fill in some fields and put the struct in front of the list */ ret->seq_number = seq_number++; ret->alloc_mem = NULL; ret->alloc_line = -1; strcpy(ret->alloc_file, "NO FILE"); ret->realloc_mem = NULL; ret->realloc_line = -1; strcpy(ret->realloc_file, "NO FILE"); ret->free_line = -1; ret->freed_flag = 0; strcpy(ret->free_file, "NO FILE"); /* No previous for the first element in the list. */ ret->previous = NULL; /* Put in front of the double linked list. */ ret->next = (void *) head_of_report; if (head_of_report) head_of_report->previous = (void *) ret; /* Make it the new head of the list */ head_of_report = ret; /* The report got a little longer */ report_length++; return ret; } /* free_info() * * deallocate memory for the given statistics (remove from the linked list) */ Mem_info *free_info (Mem_info *ptr) { void *tmp_ptr; #ifdef PDEBUG_MEM_LOW check_report("begin free_info"); #endif /* Remove from this element from the list and return a different pointer! */ if (ptr == NULL) { printf ("Pointer passed to free_inof() is NULL\n"); return ptr; } /* But first we put trash we can identify in the statistics */ ptr->alloc_mem = NULL; ptr->alloc_line = -1; strcpy(ptr->alloc_file, "FREED"); if (ptr->previous) { /* If we are not the head of the report we should have someone in front of us. */ ((Mem_info *)(ptr->previous))->next = ptr->next; } else { /* Hey, we were the head of the report, someone should replace us... */ head_of_report = ptr->next; } if (ptr->next) { /* If we are not the end of the report we should have someone in after of us. */ ((Mem_info *)(ptr->next))->previous = ptr->previous; } /* At this point the pointers should have been set so that we do not appear in the double linked list anymore */ tmp_ptr = ptr->next; /* Deallocation */ free (ptr); /* Make it really hurt if we would try to use this pointer again */ ptr = tmp_ptr; /* Update report length */ report_length--; if (report_length < 0) printf ("Report length smaller than ZERO\n"); #ifdef PDEBUG_MEM_LOW check_report("begin free_info"); #endif return ptr; } /* debug_malloc() * * allocate some memory and fill in the stats */ void *debug_malloc( int size, char *file, unsigned long line) { void *ret; Mem_info *tmp; #ifdef PDEBUG_MEM printf("malloc %s %ld %d\n", file, line, size); #endif #ifdef PDEBUG_MEM_LOW check_report("Begin debug_malloc"); #endif /* New information container */ tmp = malloc_info(); /* One more call */ alloc_calls++; /* Increase amount of allocated memory */ alloc_now += size; /* Increase the total amount of allocated memory */ alloc_total += size; /* Update upperbound if necessary */ if (alloc_now > alloc_high) alloc_high = alloc_now; /* Update the biggest allocated memory chunk */ if (size > alloc_max) alloc_max = size; /* The allocation */ ret = malloc ( size ); /* Fill in the report */ strcpy(tmp->alloc_file, file); tmp->alloc_line = line; tmp->alloc_size = size; tmp->alloc_mem = ret; //shrink_report(); !!!!!!!!!!!!!!!!!!!!!!1 return ret; } /* debug_realloc() * * reallocate some memory and fill in the stats */ void *debug_realloc( void *ptr, int size, char *file, unsigned long line) { void *ret = NULL; Mem_info *tmp; Mem_info *next_info; #ifdef PDEBUG_MEM printf("realloc %s %ld %d\n", file, line, size); #endif #ifdef PDEBUG_MEM_LOW check_report("BEGIN debug_realloc"); #endif /* This code is based on the manpages of Linux RH6.1. Please inform me of any deviation from the official specifications. See the comments starting with AAA and BBB. */ /* AAA: realloc() invoked with a NULL pointer should be equivalent to malloc(). */ if (ptr == NULL) { return debug_malloc (size, file, line); } /* Increase amount of allocated memory */ realloc_calls++; /* Find the mem_info about this previously allocated memory chunk */ tmp = head_of_report; while (tmp) { if (tmp->alloc_mem == ptr) break; tmp = (Mem_info *) tmp->next; } /* Did we find something?? If not cry a last time :-{ */ if (tmp == NULL) { memory_report(); fprintf (mem_out, " !!! ------------- !!! \n"); fprintf (mem_out, "Trying to reallocate using an invalid address ( %#lx )!\n", (long)ptr); fprintf (mem_out, "Reallocation invoked in %s at line %ld\n", file, line); fprintf (mem_out, " !!! ------------- !!! \n"); exit(-2); } /* BBB: realloc() invoked with a size equal to 0 is equivalent to free(). */ if (size == 0) { debug_free(ptr, file, line); /* Fill in the report */ strcpy(tmp->realloc_file, file); tmp->realloc_line = line; tmp->realloc_size = size; tmp->realloc_mem = ret; return ptr; } /* The reallocation */ ret = realloc ( ptr, size ); if (tmp->realloc_mem == NULL) { /* Fill in the report */ strcpy(tmp->realloc_file, file); tmp->realloc_line = line; tmp->realloc_size = size; tmp->realloc_mem = ret; /* Make some stats for this new chunk. */ next_info = malloc_info(); strcpy(next_info->alloc_file, file); next_info->alloc_line = line; next_info->alloc_size = size; next_info->alloc_mem = ret; } else { printf ("Memory was already reallocated!\n"); } /* First check if the reallocation succeeded */ if (tmp->realloc_mem != NULL) { /* Update the amount of allocated memory */ alloc_now -= tmp->alloc_size; alloc_now += size; alloc_total -= tmp->alloc_size; alloc_total += size; /* Increase the total amount of allocated memory */ realloc_total += size; } if (size > realloc_max) realloc_max = size; /* Update upperbound if necessary. */ if (alloc_now > alloc_high) alloc_high = alloc_now; #ifdef PDEBUG_MEM_LOW check_report("End debug_realloc"); #endif return ret; } /* debug_free() * * free the memory and update the stats */ void debug_free( void *ptr, char *file, unsigned long line) { Mem_info *tmp; /* Update the number of calls */ free_calls++; #ifdef PDEBUG_MEM printf("free %s %ld\n", file, line); #endif #ifdef PDEBUG_MEM_LOW check_report("Begin debug_free"); #endif if (ptr == NULL) { #if 0 tmp = malloc_info(); /* Fill in the report */ strcpy(tmp->alloc_file, "Result FREE(NULL)"); tmp->alloc_line = -2; strcpy(tmp->realloc_file,"Result FREE(NULL)"); tmp->realloc_line = line; strcpy(tmp->free_file, file); tmp->free_line = -2; /* We do not set it on purpose: in order to appear in the report */ tmp->freed_flag = 0; fprintf (mem_out, " !!! ------------- !!! \n"); fprintf (mem_out, "Useless NULL-pointer deallocation.\n"); fprintf (mem_out, "=> this is catched here\n"); fprintf (mem_out, " !!! ------------- !!! \n"); #endif return; } /* Find the mem_info about this previously allocated memory chunk */ tmp = head_of_report; while (tmp) { if ((tmp->realloc_mem == ptr) || (tmp->alloc_mem == ptr)) break; tmp = (Mem_info *) tmp->next; } /* Did we find something?? If not cry a last time :-{*/ if (tmp == NULL) { memory_report(); fprintf (mem_out, " !!! ------------- !!! \n"); fprintf (mem_out, "Trying to deallocate using a invalid address! Was never allocated here\n"); fprintf (mem_out, " file: %s line: %ld addres: %lx\n", file, line, (long) ptr); fprintf (mem_out, " !!! ------------- !!! \n"); exit(-2); } /* Okay, see if this has not already been freed. */ if (tmp->freed_flag == 1) { memory_report(); fprintf (mem_out, " !!! ------------- !!! \n"); fprintf (mem_out, "Trying to deallocate a chunk that was already deallocated! %#lx\n", (long)ptr); fprintf (mem_out, " !!! ------------- !!! \n"); exit(-3); } /* The deallocation */ free ( ptr ); if (tmp->realloc_mem == NULL) { alloc_now -= tmp->alloc_size; free_total += tmp->alloc_size; } else { alloc_now -= tmp->realloc_size; free_total += tmp->realloc_size; } /* Fill in the report */ strcpy(tmp->free_file, file); tmp->free_line = line; tmp->freed_flag = 1; #ifdef PDEBUG_MEM_LOW check_report("End debug_free"); #endif return; } /* memory_report() * * print a report and deallocate the stats */ void memory_report () { static char lock = 0; Mem_info *tmp; Mem_info *swap; int i = 0; int chunk_count = 0; unsigned long sum = 0; if (lock) { printf ("BREAKING LOOP in memory_report()\n"); return; } /* Set the lock */ lock = 1; printf ("Long memory report\n"); printf ("Shrinking report... "); fflush(stdout); /* First reduce the report to useful information. */ //shrink_report(); printf ("done\n"); /* Find the mem_info about this previously allocated memory chunk */ tmp = head_of_report; fprintf(mem_out, " Start of memory allocation report\n"); fprintf(mem_out, "===================================\n\n"); fprintf(mem_out, " This data has been collected at run-time and should hopefully help you in debugging your\n"); fprintf(mem_out, " program(s) for memory leaks. Beware of the order in which the memory information is \n"); fprintf(mem_out, " displayed. The most recently allocated chunck are reported first.\n\n"); fprintf(mem_out, " # | event | size (bytes) | address | line | Source file\n"); while (tmp) { chunk_count++; i++; if (i > 5) { fprintf(mem_out, "-------------------------------------------------------------------------------------\n"); fprintf(mem_out, " # | event | size (bytes) | address | line | Source file\n"); i = 0; } fprintf(mem_out, "-------------------------------------------------------------------------------------\n"); fprintf(mem_out, " %10ld | %10s | %12ld | %#lx | %8ld | %s\n", tmp->seq_number, " allocation ", tmp->alloc_size, (long) tmp->alloc_mem, tmp->alloc_line, tmp->alloc_file); sum += tmp->alloc_size; /* if (tmp->alloc_mem == NULL) { printf ("**** This allocation failed!!!! ****\n"); } */ if (tmp->realloc_mem !=NULL) { fprintf(mem_out, " | %10s | %12ld | %#lx | %8ld | %s\n", "reallocation", tmp->realloc_size, (long) tmp->alloc_mem, tmp->realloc_line, tmp->realloc_file); } else { fprintf(mem_out, " | reallocation | ----- | ----- | ----- | -----\n"); } if (tmp->freed_flag != 0) { fprintf(mem_out, " | %10s | | | %8ld | %s\n", "deallocation", tmp->free_line, tmp->free_file); } else { fprintf(mem_out, " | deallocation | ----- | ----- | ----- | -----\n"); fprintf(mem_out, " *** Warning the memory chunk was never deallocated!!! *** "); fprintf(mem_out, "This leaves %ld bytes allocated\n", tmp->alloc_size); } swap = tmp; tmp = (Mem_info *) tmp->next; free(swap); } fprintf(mem_out, "========================================================================\n"); fprintf(mem_out, "\n"); fprintf(mem_out, "Total number of bytes allocated : %8ld (bytes), %8ld (Kbytes)\n", alloc_total, alloc_total/1024); fprintf(mem_out, "Total number of bytes freed: - %8ld (bytes), %8ld (Kbytes)\n", free_total, free_total/1024); fprintf(mem_out, "--------------------------------------------------------------------------\n"); fprintf(mem_out, "Total number of bytes still allocated: %8ld (bytes), %8ld (Kbytes)\n", alloc_now, alloc_now/1024); fprintf(mem_out, "\n"); fprintf(mem_out, "Highest number of bytes allocated (at 1 moment): %8ld (bytes), %8ld (kbytes)\n", alloc_high, alloc_high/1024); fprintf(mem_out, "Those were allocated in %ld step(s).\n", alloc_calls); fprintf(mem_out, "ps: biggest chunk size was %ld bytes (%ld kbytes).\n", alloc_max, alloc_max/1024); fprintf(mem_out, "\n"); fprintf(mem_out, "Those bytes are distributed over %d chunk(s).\n", chunk_count); fprintf(mem_out, "\n"); fprintf(mem_out, "Those were freed in %ld step(s).\n", free_calls); fprintf(mem_out, "\n"); fprintf(mem_out, "Total number of reallocated bytes: %ld (bytes), %ld (kbytes)\n", realloc_total, realloc_total/1024); fprintf(mem_out, "Those were reallocated in %ld step(s).\n", realloc_calls); fprintf(mem_out, "ps: biggest reallocated chunk size was %ld bytes.\n", realloc_max); fprintf(mem_out, "\n"); fprintf(mem_out, "End of memory usage report.\n"); lock = 0; return; } /* memory_short_report() * * print a report and deallocate the stats */ void memory_short_report () { static char lock = 0; Mem_info *tmp; int chunk_count = 0; if (lock) { printf ("BREAKING LOOP in memory_short_report()\n"); return; } /* Set the lock */ lock = 1; printf ("Short report\n"); printf ("Shrinking report... "); fflush(stdout); /* First reduce the report to useful information. */ //shrink_report(); printf ("done\n"); /* Find the mem_info about this previously allocated memory chunk */ tmp = head_of_report; fprintf(mem_out, " Start of memory allocation report\n"); fprintf(mem_out, "===================================\n\n"); fprintf(mem_out, " This data has been collected at run-time and should hopefully help you in debugging your\n"); fprintf(mem_out, " program(s) for memory leaks.\n"); fprintf(mem_out, "\n"); fprintf(mem_out, "Total number of bytes allocated : %8ld (bytes), %8ld (Kbytes)\n", alloc_total, alloc_total/1024); fprintf(mem_out, "Total number of bytes freed: - %8ld (bytes), %8ld (Kbytes)\n", free_total, free_total/1024); fprintf(mem_out, "--------------------------------------------------------------------------\n"); fprintf(mem_out, "Total number of bytes still allocated: %8ld (bytes), %8ld (Kbytes)\n", alloc_now, alloc_now/1024); fprintf(mem_out, "\n"); fprintf(mem_out, "Highest number of bytes allocated (at 1 moment): %8ld (bytes), %8ld (kbytes)\n", alloc_high, alloc_high/1024); fprintf(mem_out, "Those were allocated in %ld step(s).\n", alloc_calls); fprintf(mem_out, "ps: biggest chunk size was %ld bytes (%ld kbytes).\n", alloc_max, alloc_max/1024); fprintf(mem_out, "\n"); fprintf(mem_out, "Those bytes are distributed over %d chunk(s).\n", chunk_count); fprintf(mem_out, "\n"); fprintf(mem_out, "Those were freed in %ld step(s).\n", free_calls); fprintf(mem_out, "\n"); fprintf(mem_out, "Total number of reallocated bytes: %ld (bytes), %ld (kbytes)\n", realloc_total, realloc_total/1024); fprintf(mem_out, "Those were reallocated in %ld step(s).\n", realloc_calls); fprintf(mem_out, "ps: biggest reallocated chunk size was %ld bytes.\n", realloc_max); fprintf(mem_out, "\n"); fprintf(mem_out, "End of memory usage report.\n"); lock = 0; return; } /* shrink_report() * * perfom some garbage collection in the double linked list (this thing can get large...) */ void shrink_report() { static char lock = 0; static unsigned long shrink_removals = 0; static unsigned long shrink_calls = 1; static unsigned long previous_length = 0; Mem_info *tmp; /* Mem_info *remove; */ if (lock) { printf ("BREAKING LOOP in shrink_report()\n"); return; } /* Set the lock */ lock = 1; /* We want to limit the number of calls give the simple datastructure used here. So we only clean the report if the report has grown more than the number of element we remove on the average. */ if ((report_length - previous_length) < (shrink_removals / shrink_calls)) return; /* We only update here otherwise the average will not represent the average removal per call of this function. */ shrink_calls++; #ifdef PDEBUG_MEM_LOW check_report("Before shrinking"); #endif tmp = head_of_report; while (tmp) { if ((tmp->realloc_mem != NULL) || (tmp->freed_flag == 1)) { /* This memory chunk is either: - reallocated in which case there is another statistic for it. - freed so there is no problem either. */ shrink_removals++; tmp = free_info(tmp); } else { tmp = tmp->next; } } previous_length = report_length; #ifdef PDEBUG_MEM_LOW check_report("After shrinking"); #endif /* Remove lock */ lock = 0; return; } /* check_report * * check the double linked list */ int check_report (char *s) { Mem_info *tmp; Mem_info *last; long count = 0; int ret = 0; last = NULL; tmp = head_of_report; while (tmp) { if (tmp->next == NULL) last = tmp; tmp = tmp->next; count++; } ret = abs(count - report_length); if ( (count == 0) || (report_length == 0)) { printf ("Forward fase\n"); printf ("length of report (%ld) reported length (%ld)\n", count, report_length); } if (ret) { printf ("Forward fase\n"); printf ("Error detected in %s\n", s); printf ("Error length of report (%ld) differs from reported length (%ld)\n", count, report_length); } count = 0; tmp = last; while (tmp) { tmp = tmp->previous; count++; } ret = abs(count - report_length); if ( (count == 0) || (report_length == 0)) { printf ("Backward fase\n"); printf ("length of report (%ld) reported length (%ld)\n", count, report_length); } if (ret) { printf ("Backward fase\n"); printf ("Error detected in %s\n", s); printf ("Error length of report (%ld) differs from reported length (%ld)\n", count, report_length); } //printf ("C"); return ret; } #endif