You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. *Tencent is pleased to support the open source community by making xLua available.
  3. *Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
  4. *Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
  5. *http://opensource.org/licenses/MIT
  6. *Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
  7. */
  8. #define LUA_LIB
  9. #include "lua.h"
  10. #include "lauxlib.h"
  11. #include "lualib.h"
  12. #include <stdio.h>
  13. #include <string.h>
  14. #define ROOT_TABLE 1
  15. #define MARKED_TABLE 2
  16. #define RT_GLOBAL 1
  17. #define RT_REGISTRY 2
  18. #define RT_UPVALUE 3
  19. #define RT_LOCAL 4
  20. #if defined(_MSC_VER) && _MSC_VER < 1900
  21. #define snprintf c99_snprintf
  22. #define vsnprintf c99_vsnprintf
  23. __inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
  24. {
  25. int count = -1;
  26. if (size != 0)
  27. count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
  28. if (count == -1)
  29. count = _vscprintf(format, ap);
  30. return count;
  31. }
  32. __inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
  33. {
  34. int count;
  35. va_list ap;
  36. va_start(ap, format);
  37. count = c99_vsnprintf(outBuf, size, format, ap);
  38. va_end(ap);
  39. return count;
  40. }
  41. #endif
  42. #if LUA_VERSION_NUM == 501
  43. static void lua_rawsetp(lua_State *L, int idx, const void *p) {
  44. if (idx < 0) {
  45. idx += lua_gettop(L) + 1;
  46. }
  47. lua_pushlightuserdata(L, (void *)p);
  48. lua_insert(L, -2);
  49. lua_rawset(L, idx);
  50. }
  51. static void lua_rawgetp(lua_State *L, int idx, const void *p) {
  52. if (idx < 0) {
  53. idx += lua_gettop(L) + 1;
  54. }
  55. lua_pushlightuserdata(L, (void *)p);
  56. lua_rawget(L, idx);
  57. }
  58. #endif
  59. #if LUA_VERSION_NUM == 503
  60. #define lua_objlen(L,i) lua_rawlen(L, (i))
  61. #endif
  62. static void make_root(lua_State *L, const void *p, const char *name, int type, const char *used_in, int need_stat) {
  63. lua_rawgetp(L, ROOT_TABLE, p);
  64. if (lua_isnil(L, -1)) {
  65. lua_pop(L, 1);
  66. lua_newtable(L); // -- root
  67. lua_newtable(L); // root.used_in
  68. if (used_in != NULL) {
  69. lua_pushboolean(L, 1);
  70. lua_setfield(L, -2, used_in);
  71. }
  72. lua_setfield(L, -2, "used_in");
  73. if (need_stat) {
  74. lua_pushstring(L, name);
  75. lua_setfield(L, -2, "name");
  76. lua_pushnumber(L, type);
  77. lua_setfield(L, -2, "type");
  78. }
  79. lua_pushvalue(L, -1);
  80. lua_rawsetp(L, ROOT_TABLE, p); //ROOT_TABLE[p] = root
  81. } else {
  82. if (used_in != NULL) {
  83. lua_getfield(L, -1, "used_in");
  84. lua_pushboolean(L, 1);
  85. lua_setfield(L, -2, used_in);
  86. lua_pop(L, 1);
  87. }
  88. }
  89. }
  90. //static void print_top(lua_State *L) {
  91. // lua_getglobal(L, "print");
  92. // lua_pushvalue(L, -2);
  93. // lua_call(L, 1, 0);
  94. //}
  95. //
  96. //static void print_str(lua_State *L, const char *str) {
  97. // lua_getglobal(L, "print");
  98. // lua_pushstring(L, str);
  99. // lua_call(L, 1, 0);
  100. //}
  101. static int is_marked(lua_State *L, const void *p) {
  102. lua_rawgetp(L, MARKED_TABLE, p);
  103. if (lua_isnil(L, -1)) {
  104. lua_pop(L, 1);
  105. return 0;
  106. } else {
  107. lua_pop(L, 1);
  108. return 1;
  109. }
  110. }
  111. static void marked(lua_State *L, const void *p, int len) {
  112. lua_pushnumber(L, len);
  113. lua_rawsetp(L, MARKED_TABLE, p);
  114. }
  115. static void mark_object(lua_State *L, lua_State *dL);
  116. static void mark_table(lua_State *L, lua_State *dL) {
  117. const void *p = lua_topointer(L, -1);
  118. int len = 0;
  119. if (!is_marked(dL, p)) {
  120. marked(dL, p, 0);
  121. lua_pushnil(L);
  122. while (lua_next(L, -2) != 0) {
  123. ++len;
  124. mark_object(L, dL);
  125. lua_pop(L, 1);
  126. mark_object(L, dL);
  127. }
  128. marked(dL, p, len);
  129. }
  130. }
  131. static void mark_function(lua_State *L, lua_State *dL) {
  132. const void *p = lua_topointer(L, -1);
  133. int i;
  134. lua_Debug ar;
  135. char used_in[128];
  136. const char *name;
  137. if (!is_marked(dL, p)) {
  138. marked(dL, p, 0); //已经在table里头算了
  139. lua_pushvalue(L, -1);
  140. lua_getinfo(L, ">S", &ar);
  141. snprintf(used_in, sizeof(used_in) - 1, "%s:%d~%d", ar.short_src, ar.linedefined, ar.lastlinedefined);
  142. used_in[sizeof(used_in) - 1] = 0;
  143. for (i=1;;i++) {
  144. name = lua_getupvalue(L,-1,i);
  145. if (name == NULL)
  146. break;
  147. p = lua_topointer(L, -1);
  148. if (*name != '\0' && LUA_TTABLE == lua_type(L, -1)) {
  149. make_root(dL, p, name, RT_UPVALUE, used_in, 1);
  150. lua_insert(dL, MARKED_TABLE);
  151. mark_object(L, dL);
  152. lua_remove(dL, MARKED_TABLE);
  153. } else if (LUA_TFUNCTION == lua_type(L, -1)) {
  154. mark_function(L, dL);
  155. }
  156. lua_pop(L, 1);
  157. }
  158. }
  159. }
  160. static void mark_object(lua_State *L, lua_State *dL) {
  161. switch (lua_type(L, -1)) {
  162. case LUA_TTABLE:
  163. mark_table(L, dL);
  164. break;
  165. case LUA_TFUNCTION:
  166. mark_function(L, dL);
  167. break;
  168. default:
  169. break;
  170. }
  171. }
  172. static void make_report(lua_State* L, lua_State* dL) {
  173. int size = 0;
  174. int i = 0;
  175. luaL_Buffer b;
  176. lua_newtable(L);
  177. lua_pushnil(dL);
  178. while (lua_next(dL, ROOT_TABLE) != 0) {
  179. lua_getfield(dL, -1, "name");
  180. if (lua_isnil(dL, -1)) {
  181. lua_pop(dL, 2);
  182. continue;
  183. } else {
  184. lua_pop(dL, 1);
  185. }
  186. lua_newtable(L);
  187. size = 0;
  188. lua_pushnil(dL);
  189. while (lua_next(dL, -2) != 0) {
  190. if (LUA_TLIGHTUSERDATA == lua_type(dL, -2)) {
  191. size += (int)lua_tointeger(dL, -1);
  192. }
  193. lua_pop(dL, 1);
  194. }
  195. lua_pushnumber(L, size);
  196. lua_setfield(L, -2, "size");
  197. lua_pushfstring(L, "%p", lua_touserdata(dL, -2));
  198. lua_setfield(L, -2, "pointer");
  199. lua_getfield(dL, -1, "name");
  200. lua_pushstring(L, lua_tostring(dL, -1));
  201. lua_pop(dL, 1);
  202. lua_setfield(L, -2, "name");
  203. lua_getfield(dL, -1, "type");
  204. lua_pushnumber(L, lua_tonumber(dL, -1));
  205. lua_pop(dL, 1);
  206. lua_setfield(L, -2, "type");
  207. lua_getfield(dL, -1, "used_in");
  208. luaL_buffinit(L, &b);
  209. lua_pushnil(dL);
  210. while (lua_next(dL, -2) != 0) {
  211. lua_pop(dL, 1);
  212. luaL_addstring(&b, lua_tostring(dL, -1));
  213. luaL_addchar(&b, ';');
  214. }
  215. luaL_pushresult(&b);
  216. lua_pop(dL, 1);
  217. lua_setfield(L, -2, "used_in");
  218. ++i;
  219. lua_rawseti(L, -2, i);
  220. lua_pop(dL, 1);
  221. }
  222. }
  223. static int mark_root_table(lua_State* L, lua_State* dL, int type) {
  224. int len = 0;
  225. lua_pushnil(L);
  226. while (lua_next(L, -2) != 0) {
  227. ++len;
  228. if (LUA_TTABLE == lua_type(L, -1)) {
  229. lua_pushvalue(L, -2);
  230. make_root(dL, lua_topointer(L, -2), lua_tostring(L, -1), type, NULL, 1);
  231. lua_pop(L, 1);
  232. mark_table(L, dL);
  233. lua_pop(dL, 1);
  234. } else {
  235. make_root(dL, lua_topointer(L, -1), "FUNCTION", type, NULL, 0);
  236. mark_object(L, dL);
  237. lua_pop(dL, 1);
  238. }
  239. lua_pop(L, 1);
  240. make_root(dL, lua_topointer(L, -1), "[KEY]", type, NULL, LUA_TTABLE == lua_type(L, -1));
  241. mark_object(L, dL);
  242. lua_pop(dL, 1);
  243. }
  244. return len;
  245. }
  246. static int snapshot(lua_State* L) {
  247. lua_State *dL = luaL_newstate();
  248. int len;
  249. const void * p;
  250. lua_newtable(dL);
  251. #if LUA_VERSION_NUM == 503
  252. lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
  253. #else
  254. lua_pushvalue(L, LUA_GLOBALSINDEX);
  255. #endif
  256. mark_root_table(L, dL, RT_GLOBAL);
  257. lua_pop(L, 1);
  258. lua_pushvalue(L, LUA_REGISTRYINDEX);
  259. p = lua_topointer(L, -1);
  260. len = mark_root_table(L, dL, RT_REGISTRY);
  261. lua_pop(L, 1);
  262. make_report(L, dL);
  263. lua_newtable(L);
  264. lua_pushstring(L, "[REGISTRY Level 1]");
  265. lua_setfield(L, -2, "name");
  266. lua_pushnumber(L, RT_REGISTRY);
  267. lua_setfield(L, -2, "type");
  268. lua_pushnumber(L, len);
  269. lua_setfield(L, -2, "size");
  270. lua_pushfstring(L, "%p", p);
  271. lua_setfield(L, -2, "pointer");
  272. lua_pushstring(L, "");
  273. lua_setfield(L, -2, "used_in");
  274. lua_rawseti(L, -2, lua_objlen(L, -2) + 1);
  275. lua_close(dL);
  276. return 1;
  277. }
  278. static const luaL_Reg preflib[] = {
  279. {"snapshot", snapshot},
  280. {NULL, NULL}
  281. };
  282. LUALIB_API int luaopen_perflib(lua_State* L)
  283. {
  284. #if LUA_VERSION_NUM == 503
  285. luaL_newlib(L, preflib);
  286. lua_setglobal(L, "perf");
  287. #else
  288. luaL_register(L, "perf", preflib);
  289. lua_pop(L, 1);
  290. #endif
  291. return 0;
  292. }