]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/util.c
5 * AUTHOR: Harvest Derived
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 #include "profiling.h"
53 #include <gnumalloc.h>
69 static void default_failure_notify(const char *);
71 void (*failure_notify
) (const char *) = default_failure_notify
;
76 static FILE *tracefp
= NULL
;
79 log_trace_init(char *fn
)
81 tracefp
= fopen(fn
, "a+");
84 perror("log_trace_init");
98 #if XMALLOC_STATISTICS
99 #define DBG_MAXSIZE (1024*1024)
100 #define DBG_SPLIT (256) /* mallocs below this value are tracked with DBG_GRAIN_SM precision instead of DBG_GRAIN */
101 #define DBG_GRAIN (16)
102 #define DBG_GRAIN_SM (4)
103 #define DBG_OFFSET (DBG_SPLIT/DBG_GRAIN_SM - DBG_SPLIT/DBG_GRAIN )
104 #define DBG_MAXINDEX (DBG_MAXSIZE/DBG_GRAIN + DBG_OFFSET)
105 #if 0 /* function version defined below */
106 #define DBG_INDEX(sz) (sz<DBG_MAXSIZE?(sz+DBG_GRAIN-1)/DBG_GRAIN:DBG_MAXINDEX)
108 static int malloc_sizes
[DBG_MAXINDEX
+ 1];
109 static int malloc_histo
[DBG_MAXINDEX
+ 1];
110 static int dbg_stat_init
= 0;
115 if (sz
>= DBG_MAXSIZE
)
119 return (sz
+ DBG_GRAIN_SM
- 1) / DBG_GRAIN_SM
;
121 return (sz
+ DBG_GRAIN
- 1) / DBG_GRAIN
+ DBG_OFFSET
;
129 for (i
= 0; i
<= DBG_MAXINDEX
; i
++)
130 malloc_sizes
[i
] = malloc_histo
[i
] = 0;
141 return malloc_sizes
[DBG_INDEX(sz
)] += 1;
145 malloc_statistics(void (*func
) (int, int, int, void *), void *data
)
149 for (i
= 0; i
<= DBG_SPLIT
; i
+= DBG_GRAIN_SM
)
150 func(i
, malloc_sizes
[DBG_INDEX(i
)], malloc_histo
[DBG_INDEX(i
)], data
);
154 for (i
= i
; i
<= DBG_MAXSIZE
; i
+= DBG_GRAIN
)
155 func(i
, malloc_sizes
[DBG_INDEX(i
)], malloc_histo
[DBG_INDEX(i
)], data
);
157 xmemcpy(&malloc_histo
, &malloc_sizes
, sizeof(malloc_sizes
));
160 #endif /* XMALLOC_STATISTICS */
165 char *xmalloc_file
= "";
166 int xmalloc_line
= 0;
167 char *xmalloc_func
= "";
168 static int xmalloc_count
= 0;
169 int xmalloc_trace
= 0; /* Enable with -m option */
170 size_t xmalloc_total
= 0;
180 #define DBG_ARRY_SZ (1<<11)
181 #define DBG_ARRY_BKTS (1<<8)
182 static void *(*malloc_ptrs
)[DBG_ARRY_SZ
];
183 static int malloc_size
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
185 static char *malloc_file
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
186 static short malloc_line
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
187 static int malloc_count
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
189 static int dbg_initd
= 0;
191 #define DBG_HASH_BUCKET(ptr) (((((int)ptr)>>4)+(((int)ptr)>>12)+(((int)ptr)>>20))&0xFF)
197 /* calloc the ptrs so that we don't see them when hunting lost memory */
198 malloc_ptrs
= calloc(DBG_ARRY_BKTS
, sizeof(*malloc_ptrs
));
200 for (B
= 0; B
< DBG_ARRY_BKTS
; B
++) {
201 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
202 malloc_ptrs
[B
][I
] = NULL
;
203 malloc_size
[B
][I
] = 0;
206 malloc_file
[B
][I
] = NULL
;
207 malloc_line
[B
][I
] = 0;
208 malloc_count
[B
][I
] = 0;
221 B
= DBG_HASH_BUCKET(s
);
223 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
224 if (malloc_ptrs
[B
][I
] != s
)
227 malloc_ptrs
[B
][I
] = NULL
;
229 malloc_size
[B
][I
] = 0;
233 malloc_file
[B
][I
] = NULL
;
235 malloc_line
[B
][I
] = 0;
237 malloc_count
[B
][I
] = 0;
244 if (I
== DBG_ARRY_SZ
) {
245 snprintf(msg
, 128, "xfree: ERROR: s=%p not found!", s
);
246 (*failure_notify
) (msg
);
251 check_malloc(void *p
, size_t sz
)
259 B
= DBG_HASH_BUCKET(p
);
261 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
262 if (!(P
= malloc_ptrs
[B
][I
]))
265 Q
= P
+ malloc_size
[B
][I
];
267 if (P
<= p
&& p
< Q
) {
268 snprintf(msg
, 128, "xmalloc: ERROR: p=%p falls in P=%p+%d",
269 p
, P
, malloc_size
[B
][I
]);
270 (*failure_notify
) (msg
);
274 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
275 if (malloc_ptrs
[B
][I
])
278 malloc_ptrs
[B
][I
] = p
;
280 malloc_size
[B
][I
] = (int) sz
;
284 malloc_file
[B
][I
] = xmalloc_file
;
286 malloc_line
[B
][I
] = xmalloc_line
;
288 malloc_count
[B
][I
] = xmalloc_count
;
295 if (I
== DBG_ARRY_SZ
)
296 (*failure_notify
) ("xmalloc: debug out of array space!");
301 #if XMALLOC_TRACE && !HAVE_MALLOCBLKSIZE
303 xmallocblksize(void *p
)
306 B
= DBG_HASH_BUCKET(p
);
308 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
309 if (malloc_ptrs
[B
][I
] == p
)
310 return malloc_size
[B
][I
];
320 malloc_file_name(void *p
)
323 B
= DBG_HASH_BUCKET(p
);
325 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
326 if (malloc_ptrs
[B
][I
] == p
)
327 return malloc_file
[B
][I
];
334 malloc_line_number(void *p
)
337 B
= DBG_HASH_BUCKET(p
);
339 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
340 if (malloc_ptrs
[B
][I
] == p
)
341 return malloc_line
[B
][I
];
348 malloc_number(void *p
)
351 B
= DBG_HASH_BUCKET(p
);
353 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
354 if (malloc_ptrs
[B
][I
] == p
)
355 return malloc_count
[B
][I
];
362 xmalloc_show_trace(void *p
, int sign
)
364 int statMemoryAccounted();
365 static size_t last_total
= 0, last_accounted
= 0, last_mallinfo
= 0;
366 size_t accounted
= statMemoryAccounted();
371 struct mallinfo mp
= mallinfo();
372 mi
= mp
.uordblks
+ mp
.usmblks
+ mp
.hblkhd
;
375 sz
= xmallocblksize(p
) * sign
;
377 xmalloc_count
+= sign
> 0;
380 fprintf(stderr
, "%c%8p size=%5d/%d acc=%5d/%d mallinfo=%5d/%d %s:%d %s",
381 sign
> 0 ? '+' : '-', p
,
382 (int) xmalloc_total
- last_total
, (int) xmalloc_total
,
383 (int) accounted
- last_accounted
, (int) accounted
,
384 (int) mi
- last_mallinfo
, (int) mi
,
385 xmalloc_file
, xmalloc_line
, xmalloc_func
);
388 fprintf(stderr
, " (%d %s:%d)\n", malloc_number(p
), malloc_file_name(p
), malloc_line_number(p
));
390 fprintf(stderr
, " %d\n", xmalloc_count
);
393 last_total
= xmalloc_total
;
394 last_accounted
= accounted
;
398 short malloc_refs
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
399 #define XMALLOC_LEAK_ALIGN (4)
401 xmalloc_scan_region(void *start
, int size
, int depth
)
405 char *end
= ptr
+ size
- XMALLOC_LEAK_ALIGN
;
409 void *p
= *(void **) ptr
;
411 if (p
&& p
!= start
) {
412 B
= DBG_HASH_BUCKET(p
);
414 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
415 if (malloc_ptrs
[B
][I
] == p
) {
416 if (!malloc_refs
[B
][I
]++) {
417 /* A new reference */
418 fprintf(stderr
, "%*s%p %s:%d size %d allocation %d\n",
420 malloc_ptrs
[B
][I
], malloc_file
[B
][I
],
421 malloc_line
[B
][I
], malloc_size
[B
][I
],
423 sum
+= malloc_size
[B
][I
];
424 xmalloc_scan_region(malloc_ptrs
[B
][I
], malloc_size
[B
][I
], depth
+ 1);
427 if (sum
!= malloc_size
[B
][I
])
428 fprintf(stderr
, "=== %d bytes\n", sum
);
433 #if XMALLOC_SHOW_ALL_REFERENCES
436 /* We have already scanned this pointer... */
437 fprintf(stderr
, "%*s%p %s:%d size %d allocation %d ... (%d)\n",
439 malloc_ptrs
[B
][I
], malloc_file
[B
][I
],
440 malloc_line
[B
][I
], malloc_size
[B
][I
],
441 malloc_count
[B
][I
], malloc_refs
[B
][I
]);
449 ptr
+= XMALLOC_LEAK_ALIGN
;
454 xmalloc_find_leaks(void)
460 fprintf(stderr
, "----- Memory map ----\n");
461 xmalloc_scan_region(&_etext
, (void *) sbrk(0) - (void *) &_etext
, 0);
463 for (B
= 0; B
< DBG_ARRY_BKTS
; B
++) {
464 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
465 if (malloc_ptrs
[B
][I
] && malloc_refs
[B
][I
] == 0) {
466 /* Found a leak... */
467 fprintf(stderr
, "Leak found: %p", malloc_ptrs
[B
][I
]);
468 fprintf(stderr
, " %s", malloc_file
[B
][I
]);
469 fprintf(stderr
, ":%d", malloc_line
[B
][I
]);
470 fprintf(stderr
, " size %d", malloc_size
[B
][I
]);
471 fprintf(stderr
, " allocation %d\n", malloc_count
[B
][I
]);
472 leak_sum
+= malloc_size
[B
][I
];
478 fprintf(stderr
, "Total leaked memory: %d\n", leak_sum
);
480 fprintf(stderr
, "No memory leaks detected\n");
483 fprintf(stderr
, "----------------------\n");
486 #endif /* XMALLOC_TRACE */
489 * xmalloc() - same as malloc(3). Used for portability.
490 * Never returns NULL; fatal on error.
509 if (failure_notify
) {
510 snprintf(msg
, 128, "xmalloc: Unable to allocate %d bytes!\n",
512 (*failure_notify
) (msg
);
524 #if XMALLOC_STATISTICS
531 xmalloc_show_trace(p
, 1);
537 fprintf(tracefp
, "m:%d:%p\n", sz
, p
);
547 * xfree() - same as free(3). Will not call free(3) if s == NULL.
555 xmalloc_show_trace(s
, -1);
571 fprintf(tracefp
, "f:%p\n", s
);
578 /* xxfree() - like xfree(), but we already know s != NULL */
580 xxfree(const void *s_const
)
582 void *s
= (void *) s_const
;
586 xmalloc_show_trace(s
, -1);
597 fprintf(tracefp
, "f:%p\n", s
);
605 * xrealloc() - same as realloc(3). Used for portability.
606 * Never returns NULL; fatal on error.
609 xrealloc(void *s
, size_t sz
)
613 PROF_start(xrealloc
);
616 xmalloc_show_trace(s
, -1);
629 if ((p
= realloc(s
, sz
)) == NULL
) {
630 if (failure_notify
) {
631 snprintf(msg
, 128, "xrealloc: Unable to reallocate %d bytes!\n",
633 (*failure_notify
) (msg
);
645 #if XMALLOC_STATISTICS
652 xmalloc_show_trace(p
, 1);
657 if (tracefp
) /* new ptr, old ptr, new size */
658 fprintf(tracefp
, "r:%p:%p:%d\n", p
, s
, sz
);
668 * xcalloc() - same as calloc(3). Used for portability.
669 * Never returns NULL; fatal on error.
672 xcalloc(size_t n
, size_t sz
)
691 if (failure_notify
) {
692 snprintf(msg
, 128, "xcalloc: Unable to allocate %u blocks of %u bytes!\n",
693 (unsigned int) n
, (unsigned int) sz
);
694 (*failure_notify
) (msg
);
703 check_malloc(p
, sz
* n
);
706 #if XMALLOC_STATISTICS
713 xmalloc_show_trace(p
, 1);
719 fprintf(tracefp
, "c:%u:%u:%p\n", (unsigned int) n
, (unsigned int) sz
, p
);
729 * xstrdup() - same as strdup(3). Used for portability.
730 * Never returns NULL; fatal on error.
733 xstrdup(const char *s
)
740 if (failure_notify
) {
741 (*failure_notify
) ("xstrdup: tried to dup a NULL pointer!\n");
743 fprintf(stderr
, "xstrdup: tried to dup a NULL pointer!\n");
749 /* copy string, including terminating character */
752 p
= (char *)xmalloc(sz
);
761 * xstrndup() - string dup with length limit.
764 xstrndup(const char *s
, size_t n
)
768 PROF_start(xstrndup
);
776 p
= xstrncpy((char *)xmalloc(sz
), s
, sz
);
784 * xstrerror() - strerror() wrapper
789 static char xstrerror_buf
[BUFSIZ
];
792 errmsg
= strerror(error
);
794 if (!errmsg
|| !*errmsg
)
795 errmsg
= "Unknown error";
797 snprintf(xstrerror_buf
, BUFSIZ
, "(%d) %s", error
, errmsg
);
799 return xstrerror_buf
;
805 return xstrerr(errno
);
821 tvSubMsec(struct timeval t1
, struct timeval t2
)
823 return (t2
.tv_sec
- t1
.tv_sec
) * 1000 +
824 (t2
.tv_usec
- t1
.tv_usec
) / 1000;
829 tvSubUsec(struct timeval t1
, struct timeval t2
)
831 return (t2
.tv_sec
- t1
.tv_sec
) * 1000000 +
832 (t2
.tv_usec
- t1
.tv_usec
);
837 tvSubDsec(struct timeval t1
, struct timeval t2
)
839 return (double) (t2
.tv_sec
- t1
.tv_sec
) +
840 (double) (t2
.tv_usec
- t1
.tv_usec
) / 1000000.0;
844 * xstrncpy() - similar to strncpy(3) but terminates string
845 * always with '\0' if (n != 0 and dst != NULL),
846 * and doesn't do padding
849 xstrncpy(char *dst
, const char *src
, size_t n
)
852 PROF_start(xstrncpy
);
858 while (--n
!= 0 && *src
!= '\0')
868 /* returns the number of leading white spaces in str; handy in skipping ws */
870 xcountws(const char *str
)
873 PROF_start(xcountws
);
876 while (xisspace(*str
)) {
886 /* somewhat safer calculation of %s */
888 xpercent(double part
, double whole
)
890 return xdiv(100 * part
, whole
);
894 xpercentInt(double part
, double whole
)
897 return (int) rint(xpercent(part
, whole
));
899 /* SCO 3.2v4.2 doesn't have rint() -- mauri@mbp.ee */
900 return (int) floor(xpercent(part
, whole
) + 0.5);
904 /* somewhat safer division */
906 xdiv(double nom
, double denom
)
908 return (denom
!= 0.0) ? nom
/ denom
: -1.0;
911 /* integer to string */
915 static char buf
[24]; /* 2^64 = 18446744073709551616 */
916 snprintf(buf
, sizeof(buf
), "%d", num
);
920 /* int64_t to string */
922 xint64toa(int64_t num
)
924 static char buf
[24]; /* 2^64 = 18446744073709551616 */
925 snprintf(buf
, sizeof(buf
), "%" PRId64
, num
);
929 /* A default failure notifier when the main program hasn't installed any */
931 default_failure_notify(const char *message
)
933 if (write(2, message
, strlen(message
))) {}
934 if (write(2, "\n", 1)) {}
941 g
->gb
+= (g
->bytes
>> 30);
942 g
->bytes
&= (1 << 30) - 1;
946 gb_to_double(const gb_t
* g
)
948 return ((double) g
->gb
) * ((double) (1 << 30)) + ((double) g
->bytes
);
952 double_to_str(char *buf
, int buf_size
, double value
)
957 snprintf(buf
, buf_size
, "%.2f MB", value
/ 1e6
);
958 else if (value
< 1e12
)
959 snprintf(buf
, buf_size
, "%.3f GB", value
/ 1e9
);
961 snprintf(buf
, buf_size
, "%.4f TB", value
/ 1e12
);
967 gb_to_str(const gb_t
* g
)
970 * it is often convenient to call gb_to_str several times for _one_ printf
972 #define max_cc_calls 5
973 typedef char GbBuf
[32];
974 static GbBuf bufs
[max_cc_calls
];
975 static int call_id
= 0;
976 double value
= gb_to_double(g
);
977 char *buf
= bufs
[call_id
++];
979 if (call_id
>= max_cc_calls
)
984 snprintf(buf
, sizeof(GbBuf
), "%.2f MB", value
/ 1e6
);
985 else if (value
< 1e12
)
986 snprintf(buf
, sizeof(GbBuf
), "%.2f GB", value
/ 1e9
);
988 snprintf(buf
, sizeof(GbBuf
), "%.2f TB", value
/ 1e12
);
994 * rounds num to the next upper integer multiple of what
996 unsigned int RoundTo(const unsigned int num
, const unsigned int what
)
998 return what
* ((num
+ what
-1)/what
);