📄 flower_malloc.c
字号:
/* -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- *//* vim:set sts=4 ts=8: *//* * Copyright (c) 2001-2007 International Computer Science Institute * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software") * to deal in the Software without restriction, subject to the conditions * listed in the XORP LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the XORP LICENSE file; the license in that file is * legally binding. */#ident "$XORP: xorp/utils/flower_malloc/flower_malloc.c,v 1.7 2007/02/16 22:47:33 pavlin Exp $"/* * Library interposer to collect malloc/calloc/realloc statistics * * To compile use: * gcc -shared -fpic -o flower_malloc.so flower_malloc.c * * To run use (in BASH): * LD_PRELOAD=$cwd/flower_malloc.so <your application here> * * The results will be in ./flower_report.<prog_name>.<pid> for each * process invoked by current application. * * How to use it... * * Start your application as mentioned above, and send it SIGUSR2 whenever you * want to examine the state of the different allocation points in your * program. * * If you see that one of the tracked allocation points growing suspciously, * create a file called flower_limits.cfg, with the same format a the report * file generated by flower_malloc. When a SIGUSR2 signal is sent to * flower_malloc, it checks for such a file, and if found, it will load the * limits specified therein for 'allocs' and 'total size' (the other fields are * ignored). When any tracker exceeds those limits, the program will abort. * For instance, if your flower_report looks like this: * *********************************************** allocs/watermark total size/watermark avg size tracker_id 0/120 0/252000 2100 3bab4 300/300 90000/90000 300 3d55c + 4/5 280000/350000 70000 3d7ac + 3/3 20480/20480 6826 4d3a9 * and you are worried about the allocation tracked by tracker_id 3d55c, you * can edit the columns 'allocs' and/or 'total size' on the file to be: *********************************************** allocs/watermark total size/watermark avg size tracker_id 200/300 80000/90000 300 3d55c + * * and save it as flower_limits.cfg. You must remove the trackers you are not * interested on. The next time you run your program, it will abort when there * are 200 outstanding allocations or 80 kbytes from that point in your * program. If the limits you provide have already been exceeded by the time * you send the SIGUSR2 signal, flower_malloc will abort the next time an * allocation happens from the execution point identified by the tracker. * * * Sending a SIGUSR2 will also force flower_malloc to read your * limits configuration file, so you will not need to restart your application. * * SIGUSR1 can be used to reset all trackers. */#include "libxorp/xorp.h"#ifdef HOST_OS_FREEBSD #include <dlfcn.h>#include <memory.h>#include <assert.h>#ifdef APPL_IS_MULTITHREADED#include <thread.h>#endif /* APPL_IS_MULTITHREADED */#include <stdio.h>#include <fcntl.h>#include <signal.h>#include <errno.h>#include <stdlib.h>#include <limits.h>#include <unistd.h>/* * XXX: If BACKTRACE_DEPTH is larger than 2, then the program coredumps * on amd64 + FreeBSD-6.1. * If it is larger than 4, the program coredumps on i386 + FreeBSD-4.10. */#define BACKTRACE_DEPTH 2#define HASH_TABLE_SIZE 343051 /* prime, max 31 bits */#define ADMIN_DATA_SIZE 2 * sizeof(uint32_t)typedef struct alloc_tracker { uint32_t count; uint32_t max_count; uint32_t last_read_max; uint32_t total_size; uint32_t watermark;} alloc_tracker_t;typedef struct limit_tracker { uint32_t enabled; uint32_t count; uint32_t total_size;} limit_tracker_t;static FILE *output = NULL;static int pid;static char path[64] = "uninitialized";static alloc_tracker_t tracker_table[HASH_TABLE_SIZE];static limit_tracker_t limits_table[HASH_TABLE_SIZE];static int32_t no_tracking;/* prototypes */static uint32_t within_limits (uint32_t trk_idx);static void init_flower_malloc(void);/*************************************************************************** * print_data - dumps the state of the alloc tracking table * */static void print_data(void){ int i; char growing[2] = " "; no_tracking = 1; /* prevent mallocs in fprintf from spoiling our report */ fprintf(output, "***********************************************\n"); fprintf(output, "allocs/watermark total size/watermark"); fprintf(output, " avg size tracker_id [+]\n"); for (i=0; i < HASH_TABLE_SIZE; i++) if (tracker_table[i].watermark) { fprintf(output, "%8u/%-8u %10u/%-10u ", tracker_table[i].count, tracker_table[i].max_count, tracker_table[i].total_size, tracker_table[i].watermark); if (tracker_table[i].count) fprintf(output, "%8u ", tracker_table[i].total_size / tracker_table[i].count); else /* use watermark to determine avg size */ fprintf(output, "%8u ", tracker_table[i].watermark / tracker_table[i].max_count); if (tracker_table[i].max_count > tracker_table[i].last_read_max) { if (tracker_table[i].last_read_max) growing[0] = '+'; tracker_table[i].last_read_max = tracker_table[i].max_count; } else growing[0] = ' '; fprintf(output, "%8x %s\n", i, growing); } fflush(output); /* untentionally leaving file open */ no_tracking = 0;}/*************************************************************************** * read_config - read flower_malloc config file * */static voidread_config(void){ unsigned long trk_idx, count, max_count, total_size, watermark, avg_size; int assig; FILE *config; #define MAX_CFG_LINE_WIDTH 80 char ignored[MAX_CFG_LINE_WIDTH]; config = fopen("./flower_limits.cfg","r"); if (!config) return; no_tracking = 1; /* prevent mallocs in fprintf from spoiling our report */ do { assig = fscanf(config, "%8lu/%8lu %10lu/%10lu %8lu %8lx %*[+ ]\n", &count, &max_count, &total_size, &watermark, &avg_size, &trk_idx); if (assig == 6) { fprintf(output, "Abort if tracker %8lx exceeds %8lu outst " "allocs or %10lu bytes\n", trk_idx, count, total_size); fflush(stdout); limits_table[trk_idx].enabled = 1; limits_table[trk_idx].count = count; limits_table[trk_idx].total_size = total_size; } else { fgets(ignored, MAX_CFG_LINE_WIDTH, config); } } while (assig != EOF); fclose(config); no_tracking = 0;}/*************************************************************************** * sigusr1_handler - handler for the SIGUSR1 signal * * This signal is used to reset the tracker and limits tables */static void sigusr1_handler(int unused){ uint32_t i; unused = unused; for (i=0; i < HASH_TABLE_SIZE; i++) { tracker_table[i].count = 0; tracker_table[i].max_count = 0; tracker_table[i].last_read_max = 0; tracker_table[i].total_size = 0; tracker_table[i].watermark = 0; limits_table[i].enabled = 0; limits_table[i].count = 0; limits_table[i].total_size = 0; } }/*************************************************************************** * sigusr2_handler - handler for the SIGUSR2 signal * * This signal is used to dump the current state of the alloc tracking table to * the output file. */static void sigusr2_handler(int unused){ unused = unused; read_config(); print_data();}/*************************************************************************** * within_limits - check if a tracker is within its configured limits * * Return zero if not */ static uint32_twithin_limits (uint32_t trk_idx){ if (!limits_table[trk_idx].enabled) return 1; return (tracker_table[trk_idx].count <= limits_table[trk_idx].count && tracker_table[trk_idx].total_size <= limits_table[trk_idx].total_size);}/*************************************************************************** * hash - calculate hash value based on backtrace stack * * This will be used to assign the same tracker to all the allocations that are * made from the same point in a program. */ static uint32_thash (void ** addr_array, size_t depth){ size_t i; size_t hash_value = 0; for (i=0; i<depth; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -