mirror of
https://github.com/opentx/opentx.git
synced 2025-07-15 20:35:17 +03:00
Lua memory (de)allocation tracer: (#5191)
* Lua memory (de)allocation tracer: Usage: * turn on: `cmake -DLUA=YES -DLUA_ALLOCATOR_TRACER=YES -DDEBUG=YES -DNANO=NO` * get debug output and make plot data: `./simu 2>&1 | grep "^LT" | ../radio/util/lua_trace2plot.py > data.plot` * plot: `gnuplot -e 'set xtics rotate; plot "data.plot" using 2:xtic(1) ; pause mouse close'` * Changes based on Bertrand comments
This commit is contained in:
parent
c30ff28f85
commit
f0f3e35bf6
6 changed files with 161 additions and 8 deletions
|
@ -195,6 +195,9 @@ if(NOT LUA STREQUAL NO)
|
||||||
if(LUA_COMPILER)
|
if(LUA_COMPILER)
|
||||||
add_definitions(-DLUA_COMPILER)
|
add_definitions(-DLUA_COMPILER)
|
||||||
endif()
|
endif()
|
||||||
|
if(LUA_ALLOCATOR_TRACER AND DEBUG)
|
||||||
|
add_definitions(-DLUA_ALLOCATOR_TRACER)
|
||||||
|
endif()
|
||||||
if(NOT "${LUA_SCRIPT_LOAD_MODE}" STREQUAL "")
|
if(NOT "${LUA_SCRIPT_LOAD_MODE}" STREQUAL "")
|
||||||
add_definitions(-DLUA_SCRIPT_LOAD_MODE="${LUA_SCRIPT_LOAD_MODE}")
|
add_definitions(-DLUA_SCRIPT_LOAD_MODE="${LUA_SCRIPT_LOAD_MODE}")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -51,6 +51,39 @@ struct our_longjmp * global_lj = 0;
|
||||||
uint32_t luaExtraMemoryUsage = 0;
|
uint32_t luaExtraMemoryUsage = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
|
||||||
|
LuaMemTracer lsScriptsTrace;
|
||||||
|
|
||||||
|
#if defined(PCBHORUS)
|
||||||
|
extern LuaMemTracer lsWidgetsTrace;
|
||||||
|
#define GET_TRACER(L) (L == lsScripts) ? &lsScriptsTrace : &lsWidgetsTrace
|
||||||
|
#else
|
||||||
|
#define GET_TRACER(L) &lsScriptsTrace
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *tracer_alloc(void * ud, void * ptr, size_t osize, size_t nsize)
|
||||||
|
{
|
||||||
|
LuaMemTracer * tracer = (LuaMemTracer *)ud;
|
||||||
|
if (ptr) {
|
||||||
|
if (osize < nsize) {
|
||||||
|
// TRACE("Lua alloc %u", nsize - osize);
|
||||||
|
tracer->alloc += nsize - osize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TRACE("Lua free %u", osize - nsize);
|
||||||
|
tracer->free += osize - nsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TRACE("Lua alloc %u (type %s)", nsize, osize < LUA_TOTALTAGS ? lua_typename(0, osize) : "unk");
|
||||||
|
tracer->alloc += nsize;
|
||||||
|
}
|
||||||
|
return l_alloc(ud, ptr, osize, nsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #if defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
|
||||||
/* custom panic handler */
|
/* custom panic handler */
|
||||||
int custom_lua_atpanic(lua_State * L)
|
int custom_lua_atpanic(lua_State * L)
|
||||||
{
|
{
|
||||||
|
@ -64,6 +97,7 @@ int custom_lua_atpanic(lua_State * L)
|
||||||
|
|
||||||
void luaHook(lua_State * L, lua_Debug *ar)
|
void luaHook(lua_State * L, lua_Debug *ar)
|
||||||
{
|
{
|
||||||
|
if (ar->event == LUA_HOOKCOUNT) {
|
||||||
instructionsPercent++;
|
instructionsPercent++;
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
// Disable Lua script instructions limit in DEBUG mode,
|
// Disable Lua script instructions limit in DEBUG mode,
|
||||||
|
@ -86,12 +120,30 @@ void luaHook(lua_State * L, lua_Debug *ar)
|
||||||
luaL_error(L, "CPU limit");
|
luaL_error(L, "CPU limit");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
#if defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
else if (ar->event == LUA_HOOKLINE) {
|
||||||
|
lua_getinfo(L, "nSl", ar);
|
||||||
|
LuaMemTracer * tracer = GET_TRACER(L);
|
||||||
|
if (tracer->alloc || tracer->free) {
|
||||||
|
TRACE("LT: [+%u,-%u] %s:%d", tracer->alloc, tracer->free, tracer->script, tracer->lineno);
|
||||||
|
}
|
||||||
|
tracer->script = ar->source;
|
||||||
|
tracer->lineno = ar->currentline;
|
||||||
|
tracer->alloc = 0;
|
||||||
|
tracer->free = 0;
|
||||||
|
}
|
||||||
|
#endif // #if defined(LUA_ALLOCATOR_TRACER)
|
||||||
}
|
}
|
||||||
|
|
||||||
void luaSetInstructionsLimit(lua_State * L, int count)
|
void luaSetInstructionsLimit(lua_State * L, int count)
|
||||||
{
|
{
|
||||||
instructionsPercent = 0;
|
instructionsPercent = 0;
|
||||||
|
#if defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
lua_sethook(L, luaHook, LUA_MASKCOUNT|LUA_MASKLINE, count);
|
||||||
|
#else
|
||||||
lua_sethook(L, luaHook, LUA_MASKCOUNT, count);
|
lua_sethook(L, luaHook, LUA_MASKCOUNT, count);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int luaGetInputs(lua_State * L, ScriptInputsOutputs & sid)
|
int luaGetInputs(lua_State * L, ScriptInputsOutputs & sid)
|
||||||
|
@ -189,6 +241,14 @@ void luaClose(lua_State ** L)
|
||||||
PROTECT_LUA() {
|
PROTECT_LUA() {
|
||||||
TRACE("luaClose %p", *L);
|
TRACE("luaClose %p", *L);
|
||||||
lua_close(*L); // this should not panic, but we make sure anyway
|
lua_close(*L); // this should not panic, but we make sure anyway
|
||||||
|
#if defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
LuaMemTracer * tracer = GET_TRACER(*L);
|
||||||
|
if (tracer->alloc || tracer->free) {
|
||||||
|
TRACE("LT: [+%u,-%u] luaClose(%s)", tracer->alloc, tracer->free, (*L == lsScripts) ? "scipts" : "widgets");
|
||||||
|
}
|
||||||
|
tracer->alloc = 0;
|
||||||
|
tracer->free = 0;
|
||||||
|
#endif // #if defined(LUA_ALLOCATOR_TRACER)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// we can only disable Lua for the rest of the session
|
// we can only disable Lua for the rest of the session
|
||||||
|
@ -1017,6 +1077,10 @@ void luaInit()
|
||||||
if (luaState != INTERPRETER_PANIC) {
|
if (luaState != INTERPRETER_PANIC) {
|
||||||
#if defined(USE_BIN_ALLOCATOR)
|
#if defined(USE_BIN_ALLOCATOR)
|
||||||
lsScripts = lua_newstate(bin_l_alloc, NULL); //we use our own allocator!
|
lsScripts = lua_newstate(bin_l_alloc, NULL); //we use our own allocator!
|
||||||
|
#elif defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
memset(&lsScriptsTrace, 0 , sizeof(lsScriptsTrace));
|
||||||
|
lsScriptsTrace.script = "lua_newstate(scripts)";
|
||||||
|
lsScripts = lua_newstate(tracer_alloc, &lsScriptsTrace); //we use tracer allocator
|
||||||
#else
|
#else
|
||||||
lsScripts = lua_newstate(l_alloc, NULL); //we use Lua default allocator
|
lsScripts = lua_newstate(l_alloc, NULL); //we use Lua default allocator
|
||||||
#endif
|
#endif
|
||||||
|
@ -1024,6 +1088,10 @@ void luaInit()
|
||||||
// install our panic handler
|
// install our panic handler
|
||||||
lua_atpanic(lsScripts, &custom_lua_atpanic);
|
lua_atpanic(lsScripts, &custom_lua_atpanic);
|
||||||
|
|
||||||
|
#if defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
lua_sethook(lsScripts, luaHook, LUA_MASKLINE, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
// protect libs and constants registration
|
// protect libs and constants registration
|
||||||
PROTECT_LUA() {
|
PROTECT_LUA() {
|
||||||
luaRegisterLibraries(lsScripts);
|
luaRegisterLibraries(lsScripts);
|
||||||
|
|
|
@ -168,10 +168,24 @@ void luaRegisterLibraries(lua_State * L);
|
||||||
void registerBitmapClass(lua_State * L);
|
void registerBitmapClass(lua_State * L);
|
||||||
void luaSetInstructionsLimit(lua_State* L, int count);
|
void luaSetInstructionsLimit(lua_State* L, int count);
|
||||||
int luaLoadScriptFileToState(lua_State * L, const char * filename, const char * mode);
|
int luaLoadScriptFileToState(lua_State * L, const char * filename, const char * mode);
|
||||||
|
|
||||||
|
struct LuaMemTracer {
|
||||||
|
const char * script;
|
||||||
|
int lineno;
|
||||||
|
uint32_t alloc;
|
||||||
|
uint32_t free;
|
||||||
|
};
|
||||||
|
|
||||||
|
void * tracer_alloc(void * ud, void * ptr, size_t osize, size_t nsize);
|
||||||
|
void luaHook(lua_State * L, lua_Debug *ar);
|
||||||
|
|
||||||
|
|
||||||
#else // defined(LUA)
|
#else // defined(LUA)
|
||||||
|
|
||||||
#define luaInit()
|
#define luaInit()
|
||||||
#define LUA_INIT_THEMES_AND_WIDGETS()
|
#define LUA_INIT_THEMES_AND_WIDGETS()
|
||||||
#define LUA_LOAD_MODEL_SCRIPTS()
|
#define LUA_LOAD_MODEL_SCRIPTS()
|
||||||
|
|
||||||
#endif // defined(LUA)
|
#endif // defined(LUA)
|
||||||
|
|
||||||
#endif // _LUA_API_H_
|
#endif // _LUA_API_H_
|
||||||
|
|
|
@ -514,12 +514,20 @@ void luaLoadFiles(const char * directory, void (*callback)())
|
||||||
f_closedir(&dir);
|
f_closedir(&dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
LuaMemTracer lsWidgetsTrace;
|
||||||
|
#endif
|
||||||
|
|
||||||
void luaInitThemesAndWidgets()
|
void luaInitThemesAndWidgets()
|
||||||
{
|
{
|
||||||
TRACE("luaInitThemesAndWidgets");
|
TRACE("luaInitThemesAndWidgets");
|
||||||
|
|
||||||
#if defined(USE_BIN_ALLOCATOR)
|
#if defined(USE_BIN_ALLOCATOR)
|
||||||
lsWidgets = lua_newstate(bin_l_alloc, NULL); //we use our own allocator!
|
lsWidgets = lua_newstate(bin_l_alloc, NULL); //we use our own allocator!
|
||||||
|
#elif defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
memset(&lsWidgetsTrace, 0 , sizeof(lsWidgetsTrace));
|
||||||
|
lsWidgetsTrace.script = "lua_newstate(widgets)";
|
||||||
|
lsWidgets = lua_newstate(tracer_alloc, &lsWidgetsTrace); //we use tracer allocator
|
||||||
#else
|
#else
|
||||||
lsWidgets = lua_newstate(l_alloc, NULL); //we use Lua default allocator
|
lsWidgets = lua_newstate(l_alloc, NULL); //we use Lua default allocator
|
||||||
#endif
|
#endif
|
||||||
|
@ -527,6 +535,10 @@ void luaInitThemesAndWidgets()
|
||||||
// install our panic handler
|
// install our panic handler
|
||||||
lua_atpanic(lsWidgets, &custom_lua_atpanic);
|
lua_atpanic(lsWidgets, &custom_lua_atpanic);
|
||||||
|
|
||||||
|
#if defined(LUA_ALLOCATOR_TRACER)
|
||||||
|
lua_sethook(lsWidgets, luaHook, LUA_MASKLINE, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
// protect libs and constants registration
|
// protect libs and constants registration
|
||||||
PROTECT_LUA() {
|
PROTECT_LUA() {
|
||||||
luaRegisterLibraries(lsWidgets);
|
luaRegisterLibraries(lsWidgets);
|
||||||
|
|
|
@ -2,6 +2,7 @@ set(LUA "NO" CACHE STRING "Lua scripts (YES/NO/NO_MODEL_SCRIPTS)")
|
||||||
set_property(CACHE LUA PROPERTY STRINGS YES NO NO_MODEL_SCRIPTS)
|
set_property(CACHE LUA PROPERTY STRINGS YES NO NO_MODEL_SCRIPTS)
|
||||||
set(LUA_SCRIPT_LOAD_MODE "" CACHE STRING "Script loading mode and compilation flags [btTxcd] (see loadScript() API docs). Blank for default ('bt' on radio, 'T' on SIMU/DEBUG builds)")
|
set(LUA_SCRIPT_LOAD_MODE "" CACHE STRING "Script loading mode and compilation flags [btTxcd] (see loadScript() API docs). Blank for default ('bt' on radio, 'T' on SIMU/DEBUG builds)")
|
||||||
option(LUA_COMPILER "Pre-compile and save Lua scripts" OFF)
|
option(LUA_COMPILER "Pre-compile and save Lua scripts" OFF)
|
||||||
|
option(LUA_ALLOCATOR_TRACER "Trace Lua memory (de)allocations to debug port (also needs DEBUG=YES NANO=NO)" OFF)
|
||||||
|
|
||||||
set(ARCH ARM)
|
set(ARCH ARM)
|
||||||
set(STM32USB_DIR ${THIRDPARTY_DIR}/STM32_USB-Host-Device_Lib_V2.2.0/Libraries)
|
set(STM32USB_DIR ${THIRDPARTY_DIR}/STM32_USB-Host-Device_Lib_V2.2.0/Libraries)
|
||||||
|
|
55
radio/util/lua_trace2plot.py
Executable file
55
radio/util/lua_trace2plot.py
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
This script parses debug log events related to Lua memory (de)allocations ( lines
|
||||||
|
starting wiht "LT: ") and produces a data for gnuplot program
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
./simu 2>&1 | grep "^LT" | ../radio/util/lua_trace2plot.py > data.plot
|
||||||
|
gnuplot -e 'set xtics rotate; plot "data.plot" using 2:xtic(1) ; pause mouse close'
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
inputFile = sys.argv[1]
|
||||||
|
inp = open(inputFile, "r")
|
||||||
|
else:
|
||||||
|
inp = sys.stdin
|
||||||
|
|
||||||
|
|
||||||
|
x = 0
|
||||||
|
memUsed = 0
|
||||||
|
while True:
|
||||||
|
skip = True
|
||||||
|
line = inp.readline()
|
||||||
|
if len(line) == 0:
|
||||||
|
break
|
||||||
|
line = line.strip('\r\n')
|
||||||
|
if len(line) == 0:
|
||||||
|
skip = True
|
||||||
|
if line.startswith("LT:"):
|
||||||
|
skip = False
|
||||||
|
|
||||||
|
if not skip:
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) >= 3:
|
||||||
|
data = parts[1].strip("[").strip("]").split(",")
|
||||||
|
alloc = int(data[0])
|
||||||
|
free = int(data[1])
|
||||||
|
line = parts[2]
|
||||||
|
if alloc > 0:
|
||||||
|
memUsed += alloc
|
||||||
|
print("'%s'\t%d" % (line, memUsed))
|
||||||
|
x += 1
|
||||||
|
if free < 0:
|
||||||
|
memUsed += free
|
||||||
|
print("'%s'\t%d" % (line, memUsed))
|
||||||
|
x += 1
|
||||||
|
|
||||||
|
inp.close()
|
Loading…
Add table
Add a link
Reference in a new issue