"Fossies" - the Fresh Open Source Software Archive

Member "heaplayers-351/allocators/vam/tools/malloctrace2.h" (2 Jan 2006, 14319 Bytes) of package /linux/misc/old/heaplayers_3_5_1.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. For more information about "malloctrace2.h" see the Fossies "Dox" file reference documentation.

    1 // -*- C++ -*-
    2 
    3 #ifndef _MALLOCTRACE_H_
    4 #define _MALLOCTRACE_H_
    5 
    6 #include <dlfcn.h>
    7 #include <stdlib.h>
    8 
    9 #include <map>
   10 #include <new>
   11 
   12 #include "heaplayers.h"
   13 #include "vamcommon.h"
   14 
   15 #define PRINT_TRACE         1
   16 #define PRINT_TIMESTAMP     0
   17 
   18 
   19 // PosixRecursiveLockType: recursive lock
   20 class PosixRecursiveLockType {
   21 
   22 public:
   23 
   24     PosixRecursiveLockType() {
   25         pthread_mutexattr_t attr;
   26         pthread_mutexattr_init(&attr);
   27         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
   28         pthread_mutex_init(&mutex, &attr);
   29     }
   30   
   31     ~PosixRecursiveLockType() {
   32         pthread_mutex_destroy(&mutex);
   33     }
   34   
   35     void lock() {
   36         pthread_mutex_lock(&mutex);
   37     }
   38   
   39     void unlock() {
   40         pthread_mutex_unlock(&mutex);
   41     }
   42   
   43 private:
   44 
   45     pthread_mutex_t mutex;
   46 
   47 };  // end of class PosixRecursiveLockType
   48 
   49 
   50 struct PageCmp {
   51     bool operator()(const void * a, const void * b) const {
   52         return (size_t) a < (size_t) b;
   53     }
   54 };
   55 class MyMapHeap : public HL::OneHeap<HL::FreelistHeap<HL::StaticHeap<4 * 1024 * 1024> > > {};
   56 typedef pair<const void *, unsigned int> PageStatusPair;
   57 typedef map<const void *, unsigned int, PageCmp, HL::STLAllocator<PageStatusPair, MyMapHeap> > PageStatusMap;
   58 
   59 
   60 class MallocTracer {
   61 
   62 public:
   63 
   64     void * calloc(size_t nmemb, size_t size) {
   65         MallocTracerLock l(_lock);
   66 
   67         // deny memory allocation from dlsym, it'll use static buffer
   68         if (_in_dlsym)
   69             return NULL;
   70 
   71         if (_real_calloc == NULL)
   72             init_all();
   73 
   74         void * rv = (*_real_calloc)(nmemb, size);
   75         trace_printf("c %p %u %u\n", rv, nmemb, size);
   76 
   77         return rv;
   78     }
   79 
   80     void * malloc(size_t size) {
   81         MallocTracerLock l(_lock);
   82 
   83         if (_real_malloc == NULL)
   84             init_all();
   85 
   86         void * rv = (*_real_malloc)(size);
   87         trace_printf("m %p %u\n", rv, size);
   88 
   89         return rv;
   90     }
   91 
   92     void free(void * ptr) {
   93         MallocTracerLock l(_lock);
   94 
   95         if (_real_free == NULL)
   96             init_all();
   97 
   98         (*_real_free)(ptr);
   99         trace_printf("f %p\n", ptr);
  100     }
  101 
  102     void * realloc(void * ptr, size_t size) {
  103         MallocTracerLock l(_lock);
  104 
  105         if (_real_realloc == NULL)
  106             init_all();
  107 
  108         void * rv = (*_real_realloc)(ptr, size);
  109         trace_printf("r %p %p %u\n", rv, ptr, size);
  110 
  111         return rv;
  112     }
  113 
  114     int brk(void * end_data_segment) {
  115         MallocTracerLock l(_lock);
  116 
  117         if (_real_brk == NULL)
  118             init_all();
  119 
  120         int rv = (*_real_brk)(end_data_segment);
  121         dbprintf("brk(%p) returned %d\n", end_data_segment, rv);
  122         assert(rv == 0);
  123 
  124         if (rv == 0) {
  125             handleNewBreak((char *) end_data_segment);
  126         }
  127 
  128         return rv;
  129     }
  130 
  131     void * sbrk(intptr_t increment) {
  132         MallocTracerLock l(_lock);
  133 
  134         if (_real_sbrk == NULL)
  135             init_all();
  136 
  137         void * rv = (*_real_sbrk)(increment);
  138         dbprintf("sbrk(%d) returned %p\n", increment, rv);
  139         assert(rv == currentBreak);
  140 
  141         if (rv == currentBreak) {
  142             handleNewBreak(currentBreak + increment);
  143         }
  144 
  145         return rv;
  146     }
  147 
  148     void * mmap(void * start, size_t length, int prot, int flags, int fd, off_t offset) {
  149         MallocTracerLock l(_lock);
  150 
  151         if (_real_mmap == NULL)
  152             init_all();
  153 
  154         void * rv = (*_real_mmap)(start, length, prot, flags, fd, offset);
  155         dbprintf("mmap(%p, %x, %x, %x, %d, %x) returned %p\n", start, length, prot, flags, fd, offset, rv);
  156         assert(((size_t) rv & ~PAGE_MASK) == 0);
  157 
  158         if (rv != NULL) {
  159             unsigned int page_status;
  160 
  161             if (flags & MAP_ANONYMOUS) {
  162                 page_status = PAGE_MMAP_ANON;
  163             }
  164             else {
  165                 if (flags & MAP_PRIVATE) {
  166                     page_status = PAGE_MMAP_PRIVATE;
  167                 }
  168                 else {
  169                     assert(flags & MAP_SHARED);
  170                     page_status = PAGE_MMAP_SHARED;
  171                 }
  172             }
  173 
  174             page_status |= PAGE_ON_DEMAND;
  175 
  176             length = (length + PAGE_SIZE - 1) & PAGE_MASK;
  177 
  178             // mprotect the pages to trap future access
  179             int rc = mprotect(rv, length, PROT_NONE);
  180             assert(rc == 0);
  181 
  182             size_t mapped = 0;
  183             while (mapped < length) {
  184                 void * page= (char *) rv + mapped;
  185 
  186                 assert(_page_status_map.find(page) == _page_status_map.end());
  187                 _page_status_map[page] = page_status;
  188 
  189                 mapped += PAGE_SIZE;
  190             }
  191 
  192             currentAllocatedMmap += length;
  193             currentMmapUntouched += length;
  194             if (currentAllocatedMmap + currentAllocatedSbrk > maxAllocated) {
  195                 maxAllocated = currentAllocatedMmap + currentAllocatedSbrk;
  196             }
  197         }
  198 
  199         return rv;
  200     }
  201 
  202     int munmap(void * start, size_t length) {
  203         MallocTracerLock l(_lock);
  204 
  205         if (_real_munmap == NULL)
  206             init_all();
  207 
  208         int rv = (*_real_munmap)(start, length);
  209         dbprintf("munmap(%p, %x) returned %d\n", start, length, rv);
  210 
  211         if (rv == 0) {
  212             length = (length + PAGE_SIZE - 1) & PAGE_MASK;
  213 
  214             size_t unmapped = 0;
  215             while (unmapped < length) {
  216                 void * page = (char *) start + unmapped;
  217 
  218                 // find and remove the page in the map
  219                 PageStatusMap::iterator i = _page_status_map.find(page);
  220                 assert(i != _page_status_map.end());
  221 
  222                 if (i != _page_status_map.end()) {
  223                     unsigned int page_status = (*i).second;
  224 
  225                     switch (page_status & PAGE_MAPPING_MASK) {
  226                     case PAGE_MMAP_ANON:
  227                     case PAGE_MMAP_PRIVATE:
  228                     case PAGE_MMAP_SHARED:
  229                         break;
  230                     default:
  231                         assert(false);
  232                     }
  233 
  234                     switch (page_status & PAGE_STATUS_MASK) {
  235                     case PAGE_ON_DEMAND:
  236                         currentMmapUntouched -= PAGE_SIZE;
  237                         assert(currentMmapUntouched >= 0);
  238                         break;
  239                     case PAGE_DISCARDED:
  240                         currentMmapDiscarded -= PAGE_SIZE;
  241                         break;
  242                     case PAGE_IN_MEMORY:
  243                         break;
  244                     default:
  245                         assert(false);
  246                     }
  247 
  248                     _page_status_map.erase(i);
  249                 }
  250 
  251                 unmapped += PAGE_SIZE;
  252             }
  253 
  254             currentAllocatedMmap -= length;
  255         }
  256 
  257         return rv;
  258     }
  259 
  260     int madvise(void * start, size_t length, int advice) {
  261         MallocTracerLock l(_lock);
  262 
  263         if (_real_madvise == NULL)
  264             init_all();
  265 
  266         int rv = (*_real_madvise)(start, length, advice);
  267         dbprintf("madvise(%p, %x, %d) returned %d\n", start, length, advice, rv);
  268 
  269         if (rv == 0 && advice == MADV_DONTNEED) {
  270             length = (length + PAGE_SIZE - 1) & PAGE_MASK;
  271 
  272             // mprotect the pages to trap future access
  273             int rc = mprotect(start, length, PROT_NONE);
  274             assert(rc == 0);
  275 
  276             size_t advised = 0;
  277             while (advised < length) {
  278                 void * page = (char *) start + advised;
  279 
  280                 // find the page in the map and change its status
  281                 PageStatusMap::iterator i = _page_status_map.find(page);
  282                 assert(i != _page_status_map.end());
  283 
  284                 if (i != _page_status_map.end()) {
  285                     unsigned int page_status = (*i).second;
  286 
  287                     switch (page_status & PAGE_STATUS_MASK) {
  288                     case PAGE_ON_DEMAND:
  289                     case PAGE_DISCARDED:
  290                         break;
  291                     case PAGE_IN_MEMORY:
  292                         switch (page_status & PAGE_MAPPING_MASK) {
  293                         case PAGE_SBRK_ANON:
  294                             currentSbrkDiscarded += PAGE_SIZE;
  295                             break;
  296                         case PAGE_MMAP_ANON:
  297                         case PAGE_MMAP_PRIVATE:
  298                         case PAGE_MMAP_SHARED:
  299                             currentMmapDiscarded += PAGE_SIZE;
  300                             break;
  301                         default:
  302                             assert(false);
  303                         }
  304                         page_status ^= PAGE_IN_MEMORY | PAGE_DISCARDED;
  305                         break;
  306                     default:
  307                         assert(false);
  308                     }
  309 
  310                     (*i).second = page_status;
  311                 }
  312 
  313                 advised += PAGE_SIZE;
  314             }
  315         }
  316 
  317         return rv;
  318     }
  319 
  320     inline static MallocTracer * getMallocTracer() {
  321         static char buf[sizeof(MallocTracer)];
  322         static MallocTracer * mt = new (buf) MallocTracer;
  323         return mt;
  324     }
  325 
  326 private:
  327 
  328     enum {
  329         PAGE_SBRK_ANON      = 0x0001,
  330         PAGE_MMAP_ANON      = 0x0002,
  331         PAGE_MMAP_PRIVATE   = 0x0004,
  332         PAGE_MMAP_SHARED    = 0x0008,
  333         PAGE_MAPPING_MASK   = 0x000F,
  334 
  335         PAGE_ON_DEMAND      = 0x0010,
  336         PAGE_DISCARDED      = 0x0020,
  337         PAGE_IN_MEMORY      = 0x0040,
  338         PAGE_STATUS_MASK    = 0x00F0,
  339     };
  340 
  341     typedef void * callocType (size_t, size_t);
  342     typedef void * mallocType (size_t);
  343     typedef void freeType (void * ptr);
  344     typedef void * reallocType (void *, size_t);
  345 
  346     typedef int brkType (void *);
  347     typedef void * sbrkType (intptr_t);
  348     typedef void * mmapType (void *, size_t, int, int, int, off_t);
  349     typedef int munmapType (void *, size_t);
  350     typedef int madviseType (void *, size_t, int);
  351 
  352     typedef HL::Guard<PosixRecursiveLockType> MallocTracerLock;
  353 
  354     PosixRecursiveLockType _lock;
  355 
  356     bool _in_dlsym;
  357 
  358     callocType * _real_calloc;
  359     mallocType * _real_malloc;
  360     freeType * _real_free;
  361     reallocType * _real_realloc;
  362 
  363     brkType * _real_brk;
  364     sbrkType * _real_sbrk;
  365     mmapType * _real_mmap;
  366     munmapType * _real_munmap;
  367     madviseType * _real_madvise;
  368 
  369     ssize_t currentAllocatedMmap;
  370     ssize_t currentAllocatedSbrk;
  371     ssize_t currentMmapDiscarded;
  372     ssize_t currentSbrkDiscarded;
  373     ssize_t currentMmapUntouched;
  374     ssize_t currentSbrkUntouched;
  375     ssize_t maxAllocated;
  376     char * initialBreak;
  377     char * currentBreak;
  378 
  379     static __thread int trace_fd;
  380 
  381 #ifdef DEBUG
  382     static __thread int debug_fd;
  383 #endif
  384 
  385     PageStatusMap _page_status_map;
  386 
  387     MallocTracer()
  388         : _lock(),
  389           _in_dlsym(false),
  390           _real_calloc(NULL),
  391           _real_malloc(NULL),
  392           _real_free(NULL),
  393           _real_realloc(NULL) {
  394     }
  395 
  396     ~MallocTracer() {
  397         dbprintf("MallocTracer terminating...\n");
  398     }
  399 
  400     void init_all() {
  401         _in_dlsym = true;
  402 
  403         _real_calloc = (callocType *) dlsym(RTLD_NEXT, "calloc");
  404         _real_malloc = (mallocType *) dlsym(RTLD_NEXT, "malloc");
  405         _real_free = (freeType *) dlsym(RTLD_NEXT, "free");
  406         _real_realloc = (reallocType *) dlsym(RTLD_NEXT, "realloc");
  407 
  408         _in_dlsym = false;
  409 
  410         assert(_real_calloc != NULL);
  411         assert(_real_malloc != NULL);
  412         assert(_real_free != NULL);
  413         assert(_real_realloc != NULL);
  414 
  415         dbprintf("MallocTracer init ending...\n");
  416     }
  417 
  418     void addPagesSbrked(size_t start, size_t length) {
  419         assert((length & ~PAGE_MASK) == 0);
  420 
  421         unsigned int page_status = PAGE_SBRK_ANON | PAGE_ON_DEMAND | PAGE_ORIG_READABLE | PAGE_ORIG_WRITABLE;
  422 
  423         // mprotect the pages to trap future access
  424         int rc = mprotect((void *) start, length, PROT_NONE);
  425         assert(rc == 0);
  426 
  427         size_t offset = 0;
  428         while (offset < length) {
  429             void * page = (void *) (start + offset);
  430 
  431             assert(_page_status_map.find(page) == _page_status_map.end());
  432             _page_status_map[page] = page_status;
  433 
  434             offset += PAGE_SIZE;
  435         }
  436 
  437         currentAllocatedSbrk += length;
  438         currentSbrkUntouched += length;
  439         if (currentAllocatedMmap + currentAllocatedSbrk > maxAllocated) {
  440             maxAllocated = currentAllocatedMmap + currentAllocatedSbrk;
  441         }
  442     }
  443 
  444     void removePagesSbrked(size_t start, size_t length) {
  445         assert((length & ~PAGE_MASK) == 0);
  446 
  447         size_t offset = 0;
  448         while (offset < length) {
  449             void * page = (void *) (start + offset);
  450 
  451             // find and remove the page in the map
  452             PageStatusMap::iterator i = _page_status_map.find(page);
  453             assert(i != _page_status_map.end());
  454 
  455             if (i != _page_status_map.end()) {
  456                 unsigned int page_status = (*i).second;
  457 
  458                 switch (page_status & PAGE_MAPPING_MASK) {
  459                 case PAGE_SBRK_ANON:
  460                     break;
  461                 default:
  462                     assert(false);
  463                 }
  464 
  465                 switch (page_status & PAGE_STATUS_MASK) {
  466                 case PAGE_ON_DEMAND:
  467                     currentSbrkUntouched -= PAGE_SIZE;
  468                     assert(currentSbrkUntouched >= 0);
  469                     break;
  470                 case PAGE_DISCARDED:
  471                     currentSbrkDiscarded -= PAGE_SIZE;
  472                     break;
  473                 case PAGE_IN_MEMORY:
  474                     break;
  475                 default:
  476                     assert(false);
  477                 }
  478 
  479                 _page_status_map.erase(i);
  480             }
  481 
  482             offset += PAGE_SIZE;
  483         }
  484 
  485         currentAllocatedSbrk -= length;
  486 
  487         // remove these in the unprotected window
  488         removePageRangeUnprotectedWindow(start, length);
  489     }
  490 
  491     void handleNewBreak(char * newBreak) {
  492         assert(newBreak >= initialBreak);
  493 
  494         size_t old_page_end = ((size_t) currentBreak + PAGE_SIZE - 1) & PAGE_MASK;
  495         size_t new_page_end = ((size_t) newBreak + PAGE_SIZE - 1) & PAGE_MASK;
  496         dbprintf("old_page_end=%p new_page_end=%p\n", old_page_end, new_page_end);
  497 
  498         currentBreak = newBreak;
  499         assert(currentBreak == (*_real_sbrk)(0));
  500 
  501         if (new_page_end > old_page_end) {
  502             addPagesSbrked(old_page_end, new_page_end - old_page_end);
  503         }
  504         else if (new_page_end < old_page_end) {
  505             removePagesSbrked(new_page_end, old_page_end - new_page_end);
  506         }
  507 
  508         currentAllocatedSbrk = currentBreak - initialBreak;
  509         if (currentAllocatedMmap + currentAllocatedSbrk > maxAllocated) {
  510             maxAllocated = currentAllocatedMmap + currentAllocatedSbrk;
  511         }
  512     }
  513 
  514     void trace_printf(const char * fmt, ...) {
  515 #if PRINT_TRACE
  516         if (trace_fd == 0) {
  517             char trace_name[50];
  518             sprintf(trace_name, "malloctrace.%u.%lx", (unsigned int) getpid(), (unsigned long) pthread_self());
  519 
  520             trace_fd = open(trace_name, O_CREAT | O_TRUNC | O_WRONLY | O_LARGEFILE, S_IRUSR | S_IWUSR);
  521             if (trace_fd <= 0) {
  522                 assert(false);
  523                 abort();
  524             }
  525         }
  526 
  527         char buf[100];
  528         size_t offset = 0;
  529 
  530 #if PRINT_TIMESTAMP
  531         unsigned long long timestamp;
  532         unsigned long * ts_low = (unsigned long *) &timestamp;
  533         unsigned long * ts_hi = ts_low + 1;
  534 
  535         asm volatile ("rdtsc" : "=a"(*ts_low), "=d"(*ts_hi));
  536         sprintf(buf, "%llx ", timestamp);
  537         offset = strlen(buf);
  538 #endif
  539 
  540         va_list ap;
  541         va_start(ap, fmt);
  542 
  543         int n = vsnprintf(buf + offset, 100, fmt, ap);
  544         if (n < 0 || n >= 100) {
  545             abort();
  546         }
  547 
  548         write(trace_fd, buf, offset + n);
  549 #endif  // PRINT_TRACE
  550     }
  551 
  552     void dbprintf(const char * fmt, ...) {
  553 #ifdef DEBUG
  554 
  555 #if DB_PRINT_TO_FILE
  556         if (debug_fd == 0) {
  557             char debug_name[50];
  558             sprintf(debug_name, "debuglog.%d.%lx", (unsigned int) getpid(), (unsigned long) pthread_self());
  559 
  560             debug_fd = open(debug_name, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
  561             if (debug_fd <= 0)
  562                 abort();
  563         }
  564 #endif
  565 
  566         char buf[BUF_SZ];
  567         va_list ap;
  568         va_start(ap, fmt);
  569 
  570         int n = vsnprintf(buf, BUF_SZ, fmt, ap);
  571         if (n < 0 || n >= BUF_SZ)
  572             abort();
  573 
  574 #if DB_PRINT_TO_FILE
  575         write(debug_fd, buf, n);
  576 #else
  577         fprintf(stderr, "<dbprintf> %s", buf);
  578         fflush(stderr);
  579 #endif
  580 
  581 #endif  // DEBUG
  582     }
  583 
  584 };  // end of class MallocTracer
  585 
  586 __thread int MallocTracer::trace_fd;
  587 
  588 #ifdef DEBUG
  589 __thread int MallocTracer::debug_fd;
  590 #endif
  591 
  592 
  593 extern "C" {
  594 
  595     void * calloc(size_t nmemb, size_t size) {
  596         return MallocTracer::getMallocTracer()->calloc(nmemb, size);
  597     }
  598 
  599     void * malloc(size_t size) {
  600         return MallocTracer::getMallocTracer()->malloc(size);
  601     }
  602 
  603     void free(void * ptr) {
  604         MallocTracer::getMallocTracer()->free(ptr);
  605     }
  606 
  607     void * realloc(void * ptr, size_t size) {
  608         return MallocTracer::getMallocTracer()->realloc(ptr, size);
  609     }
  610 
  611     int brk(void * end_data_segment) {
  612         return MallocTracer::getMallocTracer()->brk(end_data_segment);
  613     }
  614 
  615     void * sbrk(intptr_t increment) {
  616         return MallocTracer::getMallocTracer()->sbrk(increment);
  617     }
  618 
  619     void * mmap(void * start, size_t length, int prot, int flags, int fd, off_t offset) {
  620         return MallocTracer::getMallocTracer()->mmap(start, length, prot, flags, fd, offset);
  621     }
  622 
  623     int munmap(void * start, size_t length) {
  624         return MallocTracer::getMallocTracer()->munmap(start, length);
  625     }
  626 
  627     int madvise(void * start, size_t length, int advice) {
  628         return MallocTracer::getMallocTracer()->madvise(start, length, advice);
  629     }
  630     
  631 }
  632 
  633 #endif