osMemory.c 7.6 KB
Newer Older
wafwerar's avatar
wafwerar 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#define ALLOW_FORBID_FUNC
wafwerar's avatar
wafwerar 已提交
17
#include <malloc.h>
wafwerar's avatar
wafwerar 已提交
18 19
#include "os.h"

wafwerar's avatar
wafwerar 已提交
20
#if defined(USE_TD_MEMORY) || defined(USE_ADDR2LINE)
wafwerar's avatar
wafwerar 已提交
21

L
Liu Jicong 已提交
22
#define TD_MEMORY_SYMBOL ('T' << 24 | 'A' << 16 | 'O' << 8 | 'S')
wafwerar's avatar
wafwerar 已提交
23

24
#define TD_MEMORY_STACK_TRACE_DEPTH 10
wafwerar's avatar
wafwerar 已提交
25

26 27
typedef struct TdMemoryInfo *TdMemoryInfoPtr;

H
Haojun Liao 已提交
28
typedef struct TdMemoryInfo {
wafwerar's avatar
wafwerar 已提交
29
  int32_t symbol;
H
Haojun Liao 已提交
30
  int32_t memorySize;
L
Liu Jicong 已提交
31
  void   *stackTrace[TD_MEMORY_STACK_TRACE_DEPTH];  // gdb: disassemble /m 0xXXX
32 33 34
  // TdMemoryInfoPtr pNext;
  // TdMemoryInfoPtr pPrev;
} TdMemoryInfo;
wafwerar's avatar
wafwerar 已提交
35

36
// static TdMemoryInfoPtr GlobalMemoryPtr = NULL;
wafwerar's avatar
wafwerar 已提交
37

wafwerar's avatar
wafwerar 已提交
38
#ifdef WINDOWS
L
Liu Jicong 已提交
39
#define tstrdup(str) _strdup(str)
wafwerar's avatar
wafwerar 已提交
40
#else
L
Liu Jicong 已提交
41
#define tstrdup(str) strdup(str)
wafwerar's avatar
wafwerar 已提交
42

L
Liu Jicong 已提交
43
#include <execinfo.h>
wafwerar's avatar
wafwerar 已提交
44

wafwerar's avatar
wafwerar 已提交
45
#define STACKCALL __attribute__((regparm(1), noinline))
46
void **STACKCALL taosGetEbp(void) {
wafwerar's avatar
wafwerar 已提交
47 48 49 50 51 52 53
  void **ebp = NULL;
  __asm__ __volatile__("mov %%rbp, %0;\n\t"
                       : "=m"(ebp)  /* output */
                       :            /* input */
                       : "memory"); /* not affect register */
  return (void **)(*ebp);
}
wafwerar's avatar
wafwerar 已提交
54

wafwerar's avatar
wafwerar 已提交
55 56
int32_t taosBackTrace(void **buffer, int32_t size) {
  int32_t frame = 0;
L
Liu Jicong 已提交
57 58 59
  void  **ebp;
  void  **ret = NULL;
  size_t  func_frame_distance = 0;
wafwerar's avatar
wafwerar 已提交
60
  if (buffer != NULL && size > 0) {
61
    ebp = taosGetEbp();
wafwerar's avatar
wafwerar 已提交
62
    func_frame_distance = (size_t)*ebp - (size_t)ebp;
wafwerar's avatar
wafwerar 已提交
63 64 65 66 67
    while (ebp && frame < size && (func_frame_distance < (1ULL << 24))  // assume function ebp more than 16M
           && (func_frame_distance > 0)) {
      ret = ebp + 1;
      buffer[frame++] = *ret;
      ebp = (void **)(*ebp);
wafwerar's avatar
wafwerar 已提交
68
      func_frame_distance = (size_t)*ebp - (size_t)ebp;
wafwerar's avatar
wafwerar 已提交
69 70 71 72
    }
  }
  return frame;
}
wafwerar's avatar
wafwerar 已提交
73

74 75 76 77 78
// char **taosBackTraceSymbols(int32_t *size) {
//   void  *buffer[20] = {NULL};
//   *size = taosBackTrace(buffer, 20);
//   return backtrace_symbols(buffer, *size);
// }
wafwerar's avatar
wafwerar 已提交
79

wafwerar's avatar
wafwerar 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
#ifdef USE_ADDR2LINE

#include "osThread.h"
#include "libdwarf.h"
#include "dwarf.h"

#define DW_PR_DUu "llu"

typedef struct lookup_table
{
    Dwarf_Line *table;
    Dwarf_Line_Context *ctxts;
    int cnt;
    Dwarf_Addr low;
    Dwarf_Addr high;
} lookup_tableT;

extern int create_lookup_table(Dwarf_Debug dbg, lookup_tableT *lookup_table);
extern void delete_lookup_table(lookup_tableT *lookup_table);

size_t addr = 0;
lookup_tableT lookup_table;
Dwarf_Debug tDbg;
static TdThreadOnce traceThreadInit = PTHREAD_ONCE_INIT;

void endTrace() {
wafwerar's avatar
wafwerar 已提交
106
  if (traceThreadInit != PTHREAD_ONCE_INIT) {
wafwerar's avatar
wafwerar 已提交
107 108
    delete_lookup_table(&lookup_table);
    dwarf_finish(tDbg);
wafwerar's avatar
wafwerar 已提交
109
  }
wafwerar's avatar
wafwerar 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
}
void startTrace() {
  int ret;
  Dwarf_Ptr errarg = 0;

  FILE *fp = fopen("/proc/self/maps", "r");
  fscanf(fp, "%lx-", &addr);
  fclose(fp);

  ret = dwarf_init_path("/proc/self/exe", NULL, 0, DW_GROUPNUMBER_ANY, NULL, errarg, &tDbg, NULL);
  if (ret == DW_DLV_NO_ENTRY) {
    printf("Unable to open file");
    return;
  }

  ret = create_lookup_table(tDbg, &lookup_table);
  if (ret != DW_DLV_OK) {
    printf("Unable to create lookup table");
    return;
  }
  atexit(endTrace);
}
static void print_line(Dwarf_Debug dbg, Dwarf_Line line, Dwarf_Addr pc) {
wafwerar's avatar
wafwerar 已提交
133 134
  char *linesrc = "??";
  Dwarf_Unsigned lineno = 0;
wafwerar's avatar
wafwerar 已提交
135

wafwerar's avatar
wafwerar 已提交
136 137 138 139 140 141
  if (line) {
    dwarf_linesrc(line, &linesrc, NULL);
    dwarf_lineno(line, &lineno, NULL);
  }
  printf("%s:%" DW_PR_DUu "\n", linesrc, lineno);
  if (line) dwarf_dealloc(dbg, linesrc, DW_DLA_STRING);
wafwerar's avatar
wafwerar 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
}
void taosPrintBackTrace() {
  int size = 20;
  void **buffer[20];
  Dwarf_Addr pc;
  int32_t frame = 0;
  void **ebp;
  void **ret = NULL;
  size_t func_frame_distance = 0;

  taosThreadOnce(&traceThreadInit, startTrace);

  if (buffer != NULL && size > 0) {
      ebp = taosGetEbp();
    func_frame_distance = (size_t)*ebp - (size_t)ebp;
    while (ebp && frame < size && (func_frame_distance < (1ULL << 24)) && (func_frame_distance > 0)) {
      ret = ebp + 1;
      buffer[frame++] = *ret;
      ebp = (void **)(*ebp);
      func_frame_distance = (size_t)*ebp - (size_t)ebp;
    }
    for (size_t i = 0; i < frame; i++) {
      pc = (size_t)buffer[i] - addr;
      if (pc > 0) {
        if (pc >= lookup_table.low && pc < lookup_table.high) {
          Dwarf_Line line = lookup_table.table[pc - lookup_table.low];
          if (line) print_line(tDbg, line, pc);
        }
      }
    }
  }
}
#endif
#endif
#endif

#ifndef USE_ADDR2LINE
void taosPrintBackTrace() { return; }
wafwerar's avatar
wafwerar 已提交
180 181
#endif

wafwerar's avatar
wafwerar 已提交
182
void *taosMemoryMalloc(int32_t size) {
wafwerar's avatar
wafwerar 已提交
183
#ifdef USE_TD_MEMORY
wafwerar's avatar
wafwerar 已提交
184
  void *tmp = malloc(size + sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
185 186 187 188 189
  if (tmp == NULL) return NULL;

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)tmp;
  pTdMemoryInfo->memorySize = size;
  pTdMemoryInfo->symbol = TD_MEMORY_SYMBOL;
L
Liu Jicong 已提交
190
  taosBackTrace(pTdMemoryInfo->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
wafwerar's avatar
wafwerar 已提交
191

L
Liu Jicong 已提交
192
  return (char *)tmp + sizeof(TdMemoryInfo);
wafwerar's avatar
wafwerar 已提交
193 194 195
#else
  return malloc(size);
#endif
wafwerar's avatar
wafwerar 已提交
196 197 198
}

void *taosMemoryCalloc(int32_t num, int32_t size) {
wafwerar's avatar
wafwerar 已提交
199
#ifdef USE_TD_MEMORY
wafwerar's avatar
wafwerar 已提交
200
  int32_t memorySize = num * size;
L
Liu Jicong 已提交
201
  char   *tmp = calloc(memorySize + sizeof(TdMemoryInfo), 1);
wafwerar's avatar
wafwerar 已提交
202 203 204 205 206
  if (tmp == NULL) return NULL;

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)tmp;
  pTdMemoryInfo->memorySize = memorySize;
  pTdMemoryInfo->symbol = TD_MEMORY_SYMBOL;
L
Liu Jicong 已提交
207
  taosBackTrace(pTdMemoryInfo->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
wafwerar's avatar
wafwerar 已提交
208

L
Liu Jicong 已提交
209
  return (char *)tmp + sizeof(TdMemoryInfo);
wafwerar's avatar
wafwerar 已提交
210 211 212
#else
  return calloc(num, size);
#endif
wafwerar's avatar
wafwerar 已提交
213 214 215
}

void *taosMemoryRealloc(void *ptr, int32_t size) {
wafwerar's avatar
wafwerar 已提交
216
#ifdef USE_TD_MEMORY
wafwerar's avatar
wafwerar 已提交
217
  if (ptr == NULL) return taosMemoryMalloc(size);
L
Liu Jicong 已提交
218 219

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
220 221 222 223 224 225 226
  assert(pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL);

  TdMemoryInfo tdMemoryInfo;
  memcpy(&tdMemoryInfo, pTdMemoryInfo, sizeof(TdMemoryInfo));

  void *tmp = realloc(pTdMemoryInfo, size + sizeof(TdMemoryInfo));
  if (tmp == NULL) return NULL;
L
Liu Jicong 已提交
227

wafwerar's avatar
wafwerar 已提交
228 229 230
  memcpy(tmp, &tdMemoryInfo, sizeof(TdMemoryInfo));
  ((TdMemoryInfoPtr)tmp)->memorySize = size;

L
Liu Jicong 已提交
231
  return (char *)tmp + sizeof(TdMemoryInfo);
wafwerar's avatar
wafwerar 已提交
232 233 234
#else
  return realloc(ptr, size);
#endif
wafwerar's avatar
wafwerar 已提交
235 236
}

237 238 239
void *taosMemoryStrDup(void *ptr) {
#ifdef USE_TD_MEMORY
  if (ptr == NULL) return NULL;
L
Liu Jicong 已提交
240 241

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
242 243 244 245
  assert(pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL);

  void *tmp = tstrdup((const char *)pTdMemoryInfo);
  if (tmp == NULL) return NULL;
L
Liu Jicong 已提交
246

247
  memcpy(tmp, pTdMemoryInfo, sizeof(TdMemoryInfo));
L
Liu Jicong 已提交
248
  taosBackTrace(((TdMemoryInfoPtr)tmp)->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
249

L
Liu Jicong 已提交
250
  return (char *)tmp + sizeof(TdMemoryInfo);
251 252 253 254 255
#else
  return tstrdup((const char *)ptr);
#endif
}

wafwerar's avatar
wafwerar 已提交
256
void taosMemoryFree(void *ptr) {
wafwerar's avatar
wafwerar 已提交
257
#ifdef USE_TD_MEMORY
L
Liu Jicong 已提交
258 259
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
  if (pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL) {
wafwerar's avatar
wafwerar 已提交
260 261
    pTdMemoryInfo->memorySize = 0;
    // memset(pTdMemoryInfo, 0, sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
262 263
    free(pTdMemoryInfo);
  } else {
wafwerar's avatar
wafwerar 已提交
264
    free(ptr);
wafwerar's avatar
wafwerar 已提交
265
  }
wafwerar's avatar
wafwerar 已提交
266
#else
wafwerar's avatar
wafwerar 已提交
267
  return free(ptr);
wafwerar's avatar
wafwerar 已提交
268
#endif
wafwerar's avatar
wafwerar 已提交
269 270 271 272
}

int32_t taosMemorySize(void *ptr) {
  if (ptr == NULL) return 0;
wafwerar's avatar
wafwerar 已提交
273 274

#ifdef USE_TD_MEMORY
L
Liu Jicong 已提交
275
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
276 277 278
  assert(pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL);

  return pTdMemoryInfo->memorySize;
wafwerar's avatar
wafwerar 已提交
279 280 281
#else
#ifdef WINDOWS
  return _msize(ptr);
wafwerar's avatar
wafwerar 已提交
282 283 284
#else
  return malloc_usable_size(ptr);
#endif
wafwerar's avatar
wafwerar 已提交
285
#endif
L
Liu Jicong 已提交
286
}