osMemory.c 7.7 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 107
  TdThreadOnce tmp = PTHREAD_ONCE_INIT;
  if (memcmp(&traceThreadInit, &tmp, sizeof(TdThreadOnce)) != 0) {
wafwerar's avatar
wafwerar 已提交
108 109
    delete_lookup_table(&lookup_table);
    dwarf_finish(tDbg);
wafwerar's avatar
wafwerar 已提交
110
  }
wafwerar's avatar
wafwerar 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
}
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 已提交
134 135
  char *linesrc = "??";
  Dwarf_Unsigned lineno = 0;
wafwerar's avatar
wafwerar 已提交
136

wafwerar's avatar
wafwerar 已提交
137 138 139 140
  if (line) {
    dwarf_linesrc(line, &linesrc, NULL);
    dwarf_lineno(line, &lineno, NULL);
  }
141
  printf("BackTrace %08" PRId64 " %s:%" DW_PR_DUu "\n", taosGetSelfPthreadId(), linesrc, lineno);
wafwerar's avatar
wafwerar 已提交
142
  if (line) dwarf_dealloc(dbg, linesrc, DW_DLA_STRING);
wafwerar's avatar
wafwerar 已提交
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 180
}
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 已提交
181 182
#endif

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

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

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

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

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

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

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

  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
wafwerar's avatar
wafwerar 已提交
221 222 223 224 225 226 227
  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 已提交
228

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

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

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

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

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

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

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

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

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

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

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