]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/util.c
3 * $Id: util.c,v 1.98 2007/12/06 02:37:15 amosjeffries Exp $
6 * AUTHOR: Harvest Derived
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
39 #include "profiling.h"
57 #include <gnumalloc.h>
73 static void default_failure_notify(const char *);
75 void (*failure_notify
) (const char *) = default_failure_notify
;
80 static FILE *tracefp
= NULL
;
83 log_trace_init(char *fn
)
85 tracefp
= fopen(fn
, "a+");
88 perror("log_trace_init");
102 #if XMALLOC_STATISTICS
103 #define DBG_MAXSIZE (1024*1024)
104 #define DBG_SPLIT (256) /* mallocs below this value are tracked with DBG_GRAIN_SM precision instead of DBG_GRAIN */
105 #define DBG_GRAIN (16)
106 #define DBG_GRAIN_SM (4)
107 #define DBG_OFFSET (DBG_SPLIT/DBG_GRAIN_SM - DBG_SPLIT/DBG_GRAIN )
108 #define DBG_MAXINDEX (DBG_MAXSIZE/DBG_GRAIN + DBG_OFFSET)
109 // #define DBG_INDEX(sz) (sz<DBG_MAXSIZE?(sz+DBG_GRAIN-1)/DBG_GRAIN:DBG_MAXINDEX)
110 static int malloc_sizes
[DBG_MAXINDEX
+ 1];
111 static int malloc_histo
[DBG_MAXINDEX
+ 1];
112 static int dbg_stat_init
= 0;
117 if (sz
>= DBG_MAXSIZE
)
121 return (sz
+ DBG_GRAIN_SM
- 1) / DBG_GRAIN_SM
;
123 return (sz
+ DBG_GRAIN
- 1) / DBG_GRAIN
+ DBG_OFFSET
;
131 for (i
= 0; i
<= DBG_MAXINDEX
; i
++)
132 malloc_sizes
[i
] = malloc_histo
[i
] = 0;
143 return malloc_sizes
[DBG_INDEX(sz
)] += 1;
147 malloc_statistics(void (*func
) (int, int, int, void *), void *data
)
151 for (i
= 0; i
<= DBG_SPLIT
; i
+= DBG_GRAIN_SM
)
152 func(i
, malloc_sizes
[DBG_INDEX(i
)], malloc_histo
[DBG_INDEX(i
)], data
);
156 for (i
= i
; i
<= DBG_MAXSIZE
; i
+= DBG_GRAIN
)
157 func(i
, malloc_sizes
[DBG_INDEX(i
)], malloc_histo
[DBG_INDEX(i
)], data
);
159 xmemcpy(&malloc_histo
, &malloc_sizes
, sizeof(malloc_sizes
));
162 #endif /* XMALLOC_STATISTICS */
167 char *xmalloc_file
= "";
168 int xmalloc_line
= 0;
169 char *xmalloc_func
= "";
170 static int xmalloc_count
= 0;
171 int xmalloc_trace
= 0; /* Enable with -m option */
172 size_t xmalloc_total
= 0;
182 #define DBG_ARRY_SZ (1<<11)
183 #define DBG_ARRY_BKTS (1<<8)
184 static void *(*malloc_ptrs
)[DBG_ARRY_SZ
];
185 static int malloc_size
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
187 static char *malloc_file
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
188 static short malloc_line
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
189 static int malloc_count
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
191 static int dbg_initd
= 0;
193 #define DBG_HASH_BUCKET(ptr) (((((int)ptr)>>4)+(((int)ptr)>>12)+(((int)ptr)>>20))&0xFF)
199 /* calloc the ptrs so that we don't see them when hunting lost memory */
200 malloc_ptrs
= calloc(DBG_ARRY_BKTS
, sizeof(*malloc_ptrs
));
202 for (B
= 0; B
< DBG_ARRY_BKTS
; B
++) {
203 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
204 malloc_ptrs
[B
][I
] = NULL
;
205 malloc_size
[B
][I
] = 0;
208 malloc_file
[B
][I
] = NULL
;
209 malloc_line
[B
][I
] = 0;
210 malloc_count
[B
][I
] = 0;
223 B
= DBG_HASH_BUCKET(s
);
225 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
226 if (malloc_ptrs
[B
][I
] != s
)
229 malloc_ptrs
[B
][I
] = NULL
;
231 malloc_size
[B
][I
] = 0;
235 malloc_file
[B
][I
] = NULL
;
237 malloc_line
[B
][I
] = 0;
239 malloc_count
[B
][I
] = 0;
246 if (I
== DBG_ARRY_SZ
) {
247 snprintf(msg
, 128, "xfree: ERROR: s=%p not found!", s
);
248 (*failure_notify
) (msg
);
253 check_malloc(void *p
, size_t sz
)
261 B
= DBG_HASH_BUCKET(p
);
263 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
264 if (!(P
= malloc_ptrs
[B
][I
]))
267 Q
= P
+ malloc_size
[B
][I
];
269 if (P
<= p
&& p
< Q
) {
270 snprintf(msg
, 128, "xmalloc: ERROR: p=%p falls in P=%p+%d",
271 p
, P
, malloc_size
[B
][I
]);
272 (*failure_notify
) (msg
);
276 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
277 if (malloc_ptrs
[B
][I
])
280 malloc_ptrs
[B
][I
] = p
;
282 malloc_size
[B
][I
] = (int) sz
;
286 malloc_file
[B
][I
] = xmalloc_file
;
288 malloc_line
[B
][I
] = xmalloc_line
;
290 malloc_count
[B
][I
] = xmalloc_count
;
297 if (I
== DBG_ARRY_SZ
)
298 (*failure_notify
) ("xmalloc: debug out of array space!");
303 #if XMALLOC_TRACE && !HAVE_MALLOCBLKSIZE
305 xmallocblksize(void *p
)
308 B
= DBG_HASH_BUCKET(p
);
310 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
311 if (malloc_ptrs
[B
][I
] == p
)
312 return malloc_size
[B
][I
];
322 malloc_file_name(void *p
)
325 B
= DBG_HASH_BUCKET(p
);
327 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
328 if (malloc_ptrs
[B
][I
] == p
)
329 return malloc_file
[B
][I
];
336 malloc_line_number(void *p
)
339 B
= DBG_HASH_BUCKET(p
);
341 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
342 if (malloc_ptrs
[B
][I
] == p
)
343 return malloc_line
[B
][I
];
350 malloc_number(void *p
)
353 B
= DBG_HASH_BUCKET(p
);
355 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
356 if (malloc_ptrs
[B
][I
] == p
)
357 return malloc_count
[B
][I
];
364 xmalloc_show_trace(void *p
, int sign
)
366 int statMemoryAccounted();
367 static size_t last_total
= 0, last_accounted
= 0, last_mallinfo
= 0;
368 size_t accounted
= statMemoryAccounted();
373 struct mallinfo mp
= mallinfo();
374 mi
= mp
.uordblks
+ mp
.usmblks
+ mp
.hblkhd
;
377 sz
= xmallocblksize(p
) * sign
;
379 xmalloc_count
+= sign
> 0;
382 fprintf(stderr
, "%c%8p size=%5d/%d acc=%5d/%d mallinfo=%5d/%d %s:%d %s",
383 sign
> 0 ? '+' : '-', p
,
384 (int) xmalloc_total
- last_total
, (int) xmalloc_total
,
385 (int) accounted
- last_accounted
, (int) accounted
,
386 (int) mi
- last_mallinfo
, (int) mi
,
387 xmalloc_file
, xmalloc_line
, xmalloc_func
);
390 fprintf(stderr
, " (%d %s:%d)\n", malloc_number(p
), malloc_file_name(p
), malloc_line_number(p
));
392 fprintf(stderr
, " %d\n", xmalloc_count
);
395 last_total
= xmalloc_total
;
396 last_accounted
= accounted
;
400 short malloc_refs
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
401 #define XMALLOC_LEAK_ALIGN (4)
403 xmalloc_scan_region(void *start
, int size
, int depth
)
407 char *end
= ptr
+ size
- XMALLOC_LEAK_ALIGN
;
411 void *p
= *(void **) ptr
;
413 if (p
&& p
!= start
) {
414 B
= DBG_HASH_BUCKET(p
);
416 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
417 if (malloc_ptrs
[B
][I
] == p
) {
418 if (!malloc_refs
[B
][I
]++) {
419 /* A new reference */
420 fprintf(stderr
, "%*s%p %s:%d size %d allocation %d\n",
422 malloc_ptrs
[B
][I
], malloc_file
[B
][I
],
423 malloc_line
[B
][I
], malloc_size
[B
][I
],
425 sum
+= malloc_size
[B
][I
];
426 xmalloc_scan_region(malloc_ptrs
[B
][I
], malloc_size
[B
][I
], depth
+ 1);
429 if (sum
!= malloc_size
[B
][I
])
430 fprintf(stderr
, "=== %d bytes\n", sum
);
435 #if XMALLOC_SHOW_ALL_REFERENCES
438 /* We have already scanned this pointer... */
439 fprintf(stderr
, "%*s%p %s:%d size %d allocation %d ... (%d)\n",
441 malloc_ptrs
[B
][I
], malloc_file
[B
][I
],
442 malloc_line
[B
][I
], malloc_size
[B
][I
],
443 malloc_count
[B
][I
], malloc_refs
[B
][I
]);
451 ptr
+= XMALLOC_LEAK_ALIGN
;
456 xmalloc_find_leaks(void)
462 fprintf(stderr
, "----- Memory map ----\n");
463 xmalloc_scan_region(&_etext
, (void *) sbrk(0) - (void *) &_etext
, 0);
465 for (B
= 0; B
< DBG_ARRY_BKTS
; B
++) {
466 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
467 if (malloc_ptrs
[B
][I
] && malloc_refs
[B
][I
] == 0) {
468 /* Found a leak... */
469 fprintf(stderr
, "Leak found: %p", malloc_ptrs
[B
][I
]);
470 fprintf(stderr
, " %s", malloc_file
[B
][I
]);
471 fprintf(stderr
, ":%d", malloc_line
[B
][I
]);
472 fprintf(stderr
, " size %d", malloc_size
[B
][I
]);
473 fprintf(stderr
, " allocation %d\n", malloc_count
[B
][I
]);
474 leak_sum
+= malloc_size
[B
][I
];
480 fprintf(stderr
, "Total leaked memory: %d\n", leak_sum
);
482 fprintf(stderr
, "No memory leaks detected\n");
485 fprintf(stderr
, "----------------------\n");
488 #endif /* XMALLOC_TRACE */
491 * xmalloc() - same as malloc(3). Used for portability.
492 * Never returns NULL; fatal on error.
511 if (failure_notify
) {
512 snprintf(msg
, 128, "xmalloc: Unable to allocate %d bytes!\n",
514 (*failure_notify
) (msg
);
526 #if XMALLOC_STATISTICS
533 xmalloc_show_trace(p
, 1);
539 fprintf(tracefp
, "m:%d:%p\n", sz
, p
);
549 * xfree() - same as free(3). Will not call free(3) if s == NULL.
557 xmalloc_show_trace(s
, -1);
573 fprintf(tracefp
, "f:%p\n", s
);
580 /* xxfree() - like xfree(), but we already know s != NULL */
582 xxfree(const void *s_const
)
584 void *s
= (void *) s_const
;
588 xmalloc_show_trace(s
, -1);
599 fprintf(tracefp
, "f:%p\n", s
);
607 * xrealloc() - same as realloc(3). Used for portability.
608 * Never returns NULL; fatal on error.
611 xrealloc(void *s
, size_t sz
)
615 PROF_start(xrealloc
);
618 xmalloc_show_trace(s
, -1);
631 if ((p
= realloc(s
, sz
)) == NULL
) {
632 if (failure_notify
) {
633 snprintf(msg
, 128, "xrealloc: Unable to reallocate %d bytes!\n",
635 (*failure_notify
) (msg
);
647 #if XMALLOC_STATISTICS
654 xmalloc_show_trace(p
, 1);
659 if (tracefp
) /* new ptr, old ptr, new size */
660 fprintf(tracefp
, "r:%p:%p:%d\n", p
, s
, sz
);
670 * xcalloc() - same as calloc(3). Used for portability.
671 * Never returns NULL; fatal on error.
674 xcalloc(size_t n
, size_t sz
)
693 if (failure_notify
) {
694 snprintf(msg
, 128, "xcalloc: Unable to allocate %u blocks of %u bytes!\n",
695 (unsigned int) n
, (unsigned int) sz
);
696 (*failure_notify
) (msg
);
705 check_malloc(p
, sz
* n
);
708 #if XMALLOC_STATISTICS
715 xmalloc_show_trace(p
, 1);
721 fprintf(tracefp
, "c:%u:%u:%p\n", (unsigned int) n
, (unsigned int) sz
, p
);
731 * xstrdup() - same as strdup(3). Used for portability.
732 * Never returns NULL; fatal on error.
735 xstrdup(const char *s
)
742 if (failure_notify
) {
743 (*failure_notify
) ("xstrdup: tried to dup a NULL pointer!\n");
745 fprintf(stderr
, "xstrdup: tried to dup a NULL pointer!\n");
751 /* copy string, including terminating character */
754 p
= memcpy(xmalloc(sz
), s
, sz
);
762 * xstrndup() - string dup with length limit.
765 xstrndup(const char *s
, size_t n
)
769 PROF_start(xstrndup
);
777 p
= xstrncpy(xmalloc(sz
), s
, sz
);
785 * xstrerror() - strerror() wrapper
790 static char xstrerror_buf
[BUFSIZ
];
793 errmsg
= strerror(error
);
795 if (!errmsg
|| !*errmsg
)
796 errmsg
= "Unknown error";
798 snprintf(xstrerror_buf
, BUFSIZ
, "(%d) %s", error
, errmsg
);
800 return xstrerror_buf
;
806 return xstrerr(errno
);
822 tvSubMsec(struct timeval t1
, struct timeval t2
)
824 return (t2
.tv_sec
- t1
.tv_sec
) * 1000 +
825 (t2
.tv_usec
- t1
.tv_usec
) / 1000;
830 tvSubUsec(struct timeval t1
, struct timeval t2
)
832 return (t2
.tv_sec
- t1
.tv_sec
) * 1000000 +
833 (t2
.tv_usec
- t1
.tv_usec
);
838 tvSubDsec(struct timeval t1
, struct timeval t2
)
840 return (double) (t2
.tv_sec
- t1
.tv_sec
) +
841 (double) (t2
.tv_usec
- t1
.tv_usec
) / 1000000.0;
845 * xstrncpy() - similar to strncpy(3) but terminates string
846 * always with '\0' if (n != 0 and dst != NULL),
847 * and doesn't do padding
850 xstrncpy(char *dst
, const char *src
, size_t n
)
853 PROF_start(xstrncpy
);
859 while (--n
!= 0 && *src
!= '\0')
869 /* returns the number of leading white spaces in str; handy in skipping ws */
871 xcountws(const char *str
)
874 PROF_start(xcountws
);
877 while (xisspace(*str
)) {
887 /* somewhat safer calculation of %s */
889 xpercent(double part
, double whole
)
891 return xdiv(100 * part
, whole
);
895 xpercentInt(double part
, double whole
)
898 return (int) rint(xpercent(part
, whole
));
900 /* SCO 3.2v4.2 doesn't have rint() -- mauri@mbp.ee */
901 return (int) floor(xpercent(part
, whole
) + 0.5);
905 /* somewhat safer division */
907 xdiv(double nom
, double denom
)
909 return (denom
!= 0.0) ? nom
/ denom
: -1.0;
912 /* integer to string */
916 static char buf
[24]; /* 2^64 = 18446744073709551616 */
917 snprintf(buf
, sizeof(buf
), "%d", num
);
921 /* int64_t to string */
923 xint64toa(int64_t num
)
925 static char buf
[24]; /* 2^64 = 18446744073709551616 */
926 snprintf(buf
, sizeof(buf
), "%" PRId64
, num
);
930 /* A default failure notifier when the main program hasn't installed any */
932 default_failure_notify(const char *message
)
934 if(write(2, message
, strlen(message
))) {}
935 if(write(2, "\n", 1)) {}
942 g
->gb
+= (g
->bytes
>> 30);
943 g
->bytes
&= (1 << 30) - 1;
947 gb_to_double(const gb_t
* g
)
949 return ((double) g
->gb
) * ((double) (1 << 30)) + ((double) g
->bytes
);
953 double_to_str(char *buf
, int buf_size
, double value
)
958 snprintf(buf
, buf_size
, "%.2f MB", value
/ 1e6
);
959 else if (value
< 1e12
)
960 snprintf(buf
, buf_size
, "%.3f GB", value
/ 1e9
);
962 snprintf(buf
, buf_size
, "%.4f TB", value
/ 1e12
);
968 gb_to_str(const gb_t
* g
)
971 * it is often convenient to call gb_to_str several times for _one_ printf
973 #define max_cc_calls 5
974 typedef char GbBuf
[32];
975 static GbBuf bufs
[max_cc_calls
];
976 static int call_id
= 0;
977 double value
= gb_to_double(g
);
978 char *buf
= bufs
[call_id
++];
980 if (call_id
>= max_cc_calls
)
985 snprintf(buf
, sizeof(GbBuf
), "%.2f MB", value
/ 1e6
);
986 else if (value
< 1e12
)
987 snprintf(buf
, sizeof(GbBuf
), "%.2f GB", value
/ 1e9
);
989 snprintf(buf
, sizeof(GbBuf
), "%.2f TB", value
/ 1e12
);