source: memlog.c @ 0a0ef57

Revision 0a0ef57, 5.2 KB checked in by Hal Finkel <hfinkel@…>, 9 years ago (diff)

unw_get_proc_info does not work on ppc/ppc64; add getrusage info

  • Property mode set to 100644
Line 
1#ifndef _GNU_SOURCE
2#define _GNU_SOURCE
3#endif
4
5#include <stdlib.h>
6#include <stdio.h>
7#include <limits.h>
8#include <string.h>
9
10#include <sys/time.h>
11#include <sys/resource.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <sys/utsname.h>
15#include <fcntl.h>
16#include <unistd.h>
17
18#include <pthread.h>
19
20#define UNW_LOCAL_ONLY
21#include <libunwind.h>
22
23#include <dlfcn.h>
24
25FILE *log_file = NULL;
26static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
27
28__attribute__((__constructor__))
29static void record_init() {
30  struct utsname u;
31  uname(&u);
32
33  char log_name[PATH_MAX];
34  snprintf(log_name, PATH_MAX, "%s.%d.memory.log_file", u.nodename, getpid());
35  log_file = fopen(log_name, "w");
36  if (!log_file)
37    fprintf(stderr, "fopen failed for '%s': %m\n", log_name);
38}
39
40__attribute__((__destructor__))
41static void record_cleanup() {
42  if (!log_file)
43    return;
44
45  (void) fflush(log_file);
46  (void) fclose(log_file);
47}
48
49static void print_context(unw_context_t *context) {
50  struct rusage usage;
51  if (getrusage(RUSAGE_SELF, &usage)) {
52    fprintf(stderr, "getrusage failed: %m\n");
53    return;
54  }
55
56  fprintf(log_file, "\t%ld.%06ld %ld", usage.ru_utime.tv_sec,
57          usage.ru_utime.tv_usec, usage.ru_maxrss);
58
59  int r;
60  unw_cursor_t cursor;
61  if ((r = unw_init_local(&cursor, context))) {
62    fprintf(stderr, "unw_init_local failed: %s [%d]\n",
63            unw_strerror(r), r);
64    return;
65  }
66
67  while ((r = unw_step(&cursor)) > 0) {
68    unw_word_t off;
69    char proc_name[PATH_MAX];
70    if (unw_get_proc_name(&cursor, proc_name, PATH_MAX, &off)) {
71      off = 0;
72      strcpy(proc_name, "?");
73    }
74
75    unw_proc_info_t pip;
76    if ((r = unw_get_proc_info(&cursor, &pip))) {
77      // unw_get_proc_info is not supported on some platforms (ppc and ppc64,
78      // for example), so we need to try harder...
79      if (r == -UNW_EINVAL) {
80        unw_word_t pc;
81        if ((r = unw_get_reg(&cursor, UNW_REG_IP, &pc))) {
82          fprintf(stderr, "unw_get_reg UNW_REG_IP failed: %s [%d]\n",
83                  unw_strerror(r), r);
84          return;
85        }
86
87        if ((r = unw_get_proc_info_by_ip(unw_local_addr_space, pc, &pip, NULL))) {
88          fprintf(stderr, "unw_get_proc_info_by_ip failed: %s [%d]\n",
89                  unw_strerror(r), r);
90          return;
91        }
92      } else {
93        fprintf(stderr, "unw_get_proc_info failed: %s [%d]\n",
94                unw_strerror(r), r);
95        return;
96      }
97    }
98
99    const char *file_name;
100    Dl_info dlinfo;
101    if (dladdr((void *)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
102        *dlinfo.dli_fname)
103      file_name = dlinfo.dli_fname;
104    else
105      file_name = "?";
106
107    fprintf(log_file, "\t%s (%s+0x%x) [%p]", file_name, proc_name, (int) off,
108            (void *) (pip.start_ip + off));
109  }
110
111  if (r < 0)
112    fprintf(stderr, "unw_step failed: %s [%d]\n",
113            unw_strerror(r), r);
114}
115
116static void record_malloc(size_t size, void *ptr, unw_context_t *uc) {
117  if (!log_file)
118    return;
119
120  if (pthread_mutex_lock(&log_mutex))
121    return;
122
123  fprintf(log_file, "M: %zd %p", size, ptr);
124  print_context(uc);
125  fprintf(log_file, "\n");
126
127done:
128  pthread_mutex_unlock(&log_mutex);
129}
130
131static void record_free(void *ptr, unw_context_t *uc) {
132  if (!log_file)
133    return;
134
135  if (pthread_mutex_lock(&log_mutex))
136    return;
137
138  fprintf(log_file, "F: %p", ptr);
139  print_context(uc);
140  fprintf(log_file, "\n");
141
142done:
143  pthread_mutex_unlock(&log_mutex);
144}
145
146// glibc exports its underlying malloc implementation under the name
147// __libc_malloc so that hooks like this can use it.
148extern void *__libc_malloc(size_t size);
149extern void *__libc_realloc(void *ptr, size_t size);
150extern void *__libc_calloc(size_t nmemb, size_t size);
151extern void *__libc_memalign(size_t boundary, size_t size);
152extern void __libc_free(void *ptr);
153
154// The malloc hook might use functions that call malloc, and we need to make
155// sure this does not cause an infinite loop.
156static __thread int in_malloc = 0;
157
158void *malloc(size_t size) {
159  if (in_malloc)
160    return __libc_malloc(size);
161
162  in_malloc = 1;
163
164  void *ptr = __libc_malloc(size);
165
166  unw_context_t uc;
167  if (!unw_getcontext(&uc))
168    record_malloc(size, ptr, &uc);
169
170  in_malloc = 0;
171  return ptr;
172}
173
174void *realloc(void *ptr, size_t size) {
175  if (in_malloc)
176    return __libc_realloc(ptr, size);
177
178  in_malloc = 1;
179
180  void *nptr = __libc_realloc(ptr, size);
181
182  unw_context_t uc;
183  if (!unw_getcontext(&uc)) {
184    record_free(ptr, &uc);
185    record_malloc(size, nptr, &uc);
186  }
187
188  in_malloc = 0;
189
190  return nptr;
191}
192
193void *calloc(size_t nmemb, size_t size) {
194  if (in_malloc)
195    return __libc_calloc(nmemb, size);
196
197  in_malloc = 1;
198
199  void *ptr = __libc_calloc(nmemb, size);
200
201  unw_context_t uc;
202  if (!unw_getcontext(&uc))
203    record_malloc(nmemb*size, ptr, &uc);
204
205  in_malloc = 0;
206
207  return ptr;
208}
209
210void *memalign(size_t boundary, size_t size) {
211  if (in_malloc)
212    return __libc_memalign(boundary, size);
213
214  in_malloc = 1;
215
216  void *ptr = __libc_memalign(boundary, size);
217
218  unw_context_t uc;
219  if (!unw_getcontext(&uc))
220    record_malloc(size, ptr, &uc);
221
222  in_malloc = 0;
223
224  return ptr;
225}
226
227void free(void *ptr) {
228  if (in_malloc)
229    return __libc_free(ptr);
230
231  in_malloc = 1;
232
233  unw_context_t uc;
234  if (!unw_getcontext(&uc))
235    record_free(ptr, &uc);
236
237  __libc_free(ptr);
238
239  in_malloc = 0;
240}
241
Note: See TracBrowser for help on using the repository browser.