doc: Add serial to list of ci file reserved words
[charm.git] / src / ck-perf / trace-memory.C
1 #include "trace-memory.h"
2
3 #define DefaultBufferSize  10000
4
5 #define DEBUGF(x) // CmiPrintf x
6
7 CkpvStaticDeclare(TraceMemory*, _trace);
8 extern "C" void memory_trace_all_existing_mallocs();
9 extern "C" int get_memory_allocated_user_total();
10
11 /**
12   For each TraceFoo module, _createTraceFoo() must be defined.
13   This function is called in _createTraces() generated in moduleInit.C
14 */
15 void _createTracememory(char **argv)
16 {
17   DEBUGF(("%d createTraceMemory\n", CkMyPe()));
18   CkpvInitialize(TraceMemory*, _trace);
19   CkpvAccess(_trace) = new TraceMemory(argv);
20   CkpvAccess(_traces)->addTrace(CkpvAccess(_trace));
21   /* Since we started after the beginning of the program, we missed a bunch of
22    * allocations. We cannot record what was allocated and then deleted, but we
23    * can still record all the memory that is still allocated.
24    */
25 }
26
27 MemEntry::MemEntry() : type(0), where(0), size(0), stackSize(0) { }
28
29 void MemEntry::write(FILE *fp) {
30   if (type == BEGIN_TRACE) {
31     fprintf(fp, "%d %d\n", type, size);
32     return;
33   }
34   fprintf(fp, "%d %p %d", type, where, size);
35   if (type == MEMORY_MALLOC) {
36     fprintf(fp, " %d", stackSize);
37     void **stack = (void**)(this+1);
38     for (int i=stackSize-1; i>=0; --i) {
39       fprintf(fp, " %p", stack[i]);
40     }
41   }
42   fprintf(fp, "\n");
43 }
44
45 TraceMemory::TraceMemory(char **argv) {
46   usedBuffer = 0;
47   firstTime = 1;
48   traceDisabled = false;
49   logBufSize = DefaultBufferSize;
50   if (CmiGetArgIntDesc(argv,"+memlogsize",&logBufSize, 
51                        "Log buffer size (in kB)")) {
52     if (CkMyPe() == 0) {
53       CmiPrintf("Trace: logsize: %d kB\n", logBufSize);
54     }
55   }
56   recordStack = false;
57   if (CmiGetArgFlagDesc(argv,"+recordStack",
58                "Record stack trace for malloc")) {
59     recordStack = true;
60   }
61   logBufSize *= 1024;
62   logBuffer = (char *) ::malloc(logBufSize);
63 }
64
65 inline void TraceMemory::checkFlush(int increment) {
66   if (usedBuffer+increment >= logBufSize) {
67     flush();
68   }
69 }
70
71 inline void TraceMemory::flush() {
72   traceDisabled = true;
73   //CmiPrintf("[%d] TraceMemory::flush %d\n",CmiMyPe(),usedBuffer);
74   const char *mode;
75   if (firstTime) mode = "w";
76   else mode = "a";
77   firstTime = 0;
78   // flushing the logs
79   char fname[1024];
80   sprintf(fname, "memoryLog_%d", CkMyPe());
81   FILE *fp;
82   do {
83     fp = fopen(fname, mode);
84   } while (!fp && (errno == EINTR || errno == EMFILE));
85   if (!fp) {
86     CmiAbort("Cannot open file for Memory log writing\n");
87   }
88   //fprintf(fp, "begin flush\n");
89   for (int i=0; i<usedBuffer; i += sizeof(MemEntry) + ((MemEntry*)&logBuffer[i])->stackSize*sizeof(void*)) {
90     ((MemEntry*)&logBuffer[i])->write(fp);
91   }
92   //fprintf(fp, "end flush\n");
93   fclose(fp);
94   usedBuffer = 0;
95   traceDisabled = false;
96 }
97
98 void TraceMemory::traceClose() {
99   flush();
100 }
101
102 void TraceMemory::traceBegin() {
103   int increment = sizeof(MemEntry);
104   checkFlush(increment);
105   ((MemEntry*)&logBuffer[usedBuffer])->set(BEGIN_TRACE, 0, get_memory_allocated_user_total());
106   usedBuffer += increment;
107 }
108
109 void TraceMemory::malloc(void *where, int size, void **stack, int stackSize) {
110   if (!traceDisabled) {
111     int increment = sizeof(MemEntry) + (recordStack ? stackSize*sizeof(void*) : 0);
112     checkFlush(increment);
113     ((MemEntry*)&logBuffer[usedBuffer])->set(MEMORY_MALLOC, where, size);
114     if (recordStack) ((MemEntry*)&logBuffer[usedBuffer])->setStack(stackSize, stack);
115     usedBuffer += increment;
116     //CmiPrintf("[%d] TraceMemory::malloc  %d  (%p)\n",CmiMyPe(),usedBuffer,where);
117   }
118 }
119
120 void TraceMemory::free(void *where, int size) {
121   if (!traceDisabled) {
122     int increment = sizeof(MemEntry);
123     checkFlush(increment);
124     ((MemEntry*)&logBuffer[usedBuffer])->set(MEMORY_FREE, where, size);
125     usedBuffer += increment;
126     //CmiPrintf("[%d] TraceMemory::free    %d  (%p)\n",CmiMyPe(),usedBuffer,where);
127   }
128 }