1 /** 2 * Contains implementations of functions called when the 3 * -profile=gc 4 * switch is thrown. 5 * 6 * Tests for this functionality can be found in test/profile/src/profilegc.d 7 * 8 * Copyright: Copyright Digital Mars 2015 - 2015. 9 * License: Distributed under the 10 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 11 * (See accompanying file LICENSE) 12 * Authors: Walter Bright 13 * Source: $(DRUNTIMESRC rt/_tracegc.d) 14 */ 15 16 module rt.tracegc; 17 18 // version = tracegc; 19 20 extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims); 21 extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims); 22 extern (C) void _d_callfinalizer(void* p); 23 extern (C) void _d_callinterfacefinalizer(void *p); 24 extern (C) void _d_delclass(Object* p); 25 extern (C) void _d_delinterface(void** p); 26 extern (C) void _d_delmemory(void* *p); 27 extern (C) void* _d_arrayliteralTX(const TypeInfo ti, size_t length); 28 extern (C) void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, 29 void[] keys, void[] vals); 30 extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, return scope ref byte[] px, size_t n); 31 extern (C) void[] _d_arrayappendcd(ref byte[] x, dchar c); 32 extern (C) void[] _d_arrayappendwd(ref byte[] x, dchar c); 33 extern (C) void[] _d_arraysetlengthT(const TypeInfo ti, size_t newlength, void[]* p); 34 extern (C) void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p); 35 extern (C) void* _d_allocmemory(size_t sz); 36 37 // From GC.BlkInfo_. We cannot import it from core.memory.GC because .stringof 38 // replaces the alias with the private symbol that's not visible from this 39 // module, causing a compile error. 40 private struct BlkInfo 41 { 42 void* base; 43 size_t size; 44 uint attr; 45 } 46 extern (C) void* gc_malloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null); 47 extern (C) BlkInfo gc_qalloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null); 48 extern (C) void* gc_calloc(size_t sz, uint ba = 0, const TypeInfo ti = null); 49 extern (C) void* gc_realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null); 50 extern (C) size_t gc_extend(void* p, size_t mx, size_t sz, const TypeInfo ti = null); 51 52 // Used as wrapper function body to get actual stats. 53 // 54 // Placed here as a separate string constant to simplify maintenance as it is 55 // much more likely to be modified than rest of generation code. 56 enum accumulator = q{ 57 import rt.profilegc : accumulate; 58 import core.memory : GC; 59 import core.stdc.string : strstr; 60 61 static if (is(typeof(ci))) 62 string name = ci.name; 63 else static if (is(typeof(ti))) 64 string name = ti ? ti.toString() : "void[]"; 65 else static if (__FUNCTION__ == "rt.tracegc._d_arrayappendcdTrace") 66 string name = "char[]"; 67 else static if (__FUNCTION__ == "rt.tracegc._d_arrayappendwdTrace") 68 string name = "wchar[]"; 69 else static if (__FUNCTION__ == "rt.tracegc._d_allocmemoryTrace") 70 string name = "closure"; 71 else 72 string name = ""; 73 74 version (tracegc) 75 { 76 import core.stdc.stdio; 77 78 printf("%s file = '%.*s' line = %d function = '%.*s' type = %.*s\n", 79 __FUNCTION__.ptr, 80 file.length, file.ptr, 81 line, 82 funcname.length, funcname.ptr, 83 name.length, name.ptr 84 ); 85 } 86 87 ulong currentlyAllocated = GC.allocatedInCurrentThread; 88 89 scope(exit) 90 { 91 ulong size = GC.allocatedInCurrentThread - currentlyAllocated; 92 // Skip internal functions. 93 if (size > 0 && strstr(funcname.ptr, "core.internal") is null) 94 accumulate(file, line, funcname, name, size); 95 } 96 }; 97 98 mixin(generateTraceWrappers()); 99 //pragma(msg, generateTraceWrappers()); 100 101 //////////////////////////////////////////////////////////////////////////////// 102 // code gen implementation 103 104 private string generateTraceWrappers() 105 { 106 string code; 107 108 foreach (name; __traits(allMembers, mixin(__MODULE__))) 109 { 110 static if (name.length > 3 && name[0..3] == "_d_") 111 { 112 mixin("alias Declaration = " ~ name ~ ";"); 113 code ~= generateWrapper!Declaration(); 114 } 115 static if (name.length > 3 && name[0..3] == "gc_") 116 { 117 mixin("alias Declaration = " ~ name ~ ";"); 118 code ~= generateWrapper!(Declaration, ParamPos.back)(); 119 } 120 } 121 122 return code; 123 } 124 125 static enum ParamPos { front, back } 126 127 private string generateWrapper(alias Declaration, ParamPos pos = ParamPos.front)() 128 { 129 static size_t findParamIndex(string s) 130 { 131 assert (s[$-1] == ')'); 132 size_t brackets = 1; 133 while (brackets != 0) 134 { 135 s = s[0 .. $-1]; 136 if (s[$-1] == ')') 137 ++brackets; 138 if (s[$-1] == '(') 139 --brackets; 140 } 141 142 assert(s.length > 1); 143 return s.length - 1; 144 } 145 146 auto type_string = typeof(Declaration).stringof; 147 auto name = __traits(identifier, Declaration); 148 auto param_idx = findParamIndex(type_string); 149 150 static if (pos == ParamPos.front) 151 auto new_declaration = type_string[0 .. param_idx] ~ " " ~ name 152 ~ "Trace(string file, int line, string funcname, " 153 ~ type_string[param_idx+1 .. $]; 154 else static if (pos == ParamPos.back) 155 auto new_declaration = type_string[0 .. param_idx] ~ " " ~ name 156 ~ "Trace(" ~ type_string[param_idx+1 .. $-1] 157 ~ `, string file = "", int line = 0, string funcname = "")`; 158 else 159 static assert(0); 160 auto call_original = "return " 161 ~ __traits(identifier, Declaration) ~ "(" ~ Arguments!Declaration() ~ ");"; 162 163 return new_declaration ~ "\n{\n" ~ 164 accumulator ~ "\n" ~ 165 call_original ~ "\n" ~ 166 "}\n"; 167 } 168 169 string Arguments(alias Func)() 170 { 171 string result = ""; 172 173 static if (is(typeof(Func) PT == __parameters)) 174 { 175 foreach (idx, _; PT) 176 result ~= __traits(identifier, PT[idx .. idx + 1]) ~ ", "; 177 } 178 179 return result; 180 } 181 182 unittest 183 { 184 void foo(int x, double y) { } 185 static assert (Arguments!foo == "x, y, "); 186 }