Commit eb324716 authored by nanahira's avatar nanahira

add LuaMemTracker & limit Lua memory size

parent c06a0867
#include "LuaMemTracker.h"
#include <lauxlib.h>
LuaMemTracker::LuaMemTracker(size_t mem_limit)
: limit(mem_limit) {
lua_State* tmp_L = luaL_newstate(); // get default alloc
real_alloc = lua_getallocf(tmp_L, &real_ud);
lua_close(tmp_L);
#ifdef YGOPRO_LOG_LUA_MEMORY_SIZE
time_t now = time(nullptr);
char filename[64];
std::snprintf(filename, sizeof(filename), "memtrace-%ld.log", static_cast<long>(now));
log_file = std::fopen(filename, "a");
if (log_file) {
std::fprintf(log_file, "---- Lua memory tracking started ----\n");
}
#endif
}
LuaMemTracker::~LuaMemTracker() {
#ifdef YGOPRO_LOG_LUA_MEMORY_SIZE
if (log_file) {
std::fprintf(log_file, "---- Lua memory tracking ended ----\n");
std::fclose(log_file);
log_file = nullptr;
}
#endif
}
void* LuaMemTracker::AllocThunk(void* ud, void* ptr, size_t osize, size_t nsize) {
return static_cast<LuaMemTracker*>(ud)->Alloc(ptr, osize, nsize);
}
void* LuaMemTracker::Alloc(void* ptr, size_t osize, size_t nsize) {
if (nsize == 0) {
if (ptr && osize <= total_allocated) {
total_allocated -= osize;
}
return real_alloc(real_ud, ptr, osize, nsize);
} else {
size_t projected = total_allocated - osize + nsize;
if (limit && projected > limit) {
return nullptr; // over limit
}
void* newptr = real_alloc(real_ud, ptr, osize, nsize);
if (newptr) {
total_allocated = projected;
#ifdef YGOPRO_LOG_LUA_MEMORY_SIZE
write_log();
#endif
}
return newptr;
}
}
#ifdef YGOPRO_LOG_LUA_MEMORY_SIZE
void LuaMemTracker::write_log() {
if (!log_file) return;
time_t now = time(nullptr);
struct tm* tm_info = localtime(&now);
char time_buf[32];
std::strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tm_info);
if (total_allocated > max_used)
max_used = total_allocated;
if (limit)
std::fprintf(log_file, "%s | used = %zu bytes | max_used = %zu bytes | limit = %zu\n",
time_buf, total_allocated, max_used, limit);
else
std::fprintf(log_file, "%s | used = %zu bytes | max_used = %zu bytes | limit = unlimited\n",
time_buf, total_allocated, max_used);
std::fflush(log_file); // make it write instantly
}
#endif
#ifndef LUA_MEM_TRACKER_H
#define LUA_MEM_TRACKER_H
#include <cstdlib>
#include <cstddef>
#include <lua.h>
#ifdef YGOPRO_LOG_LUA_MEMORY_SIZE
#include <ctime> // time_t
#include <cstdio> // FILE*, fopen, fprintf
#endif
class LuaMemTracker {
public:
LuaMemTracker(size_t mem_limit = 0);
~LuaMemTracker();
static void* AllocThunk(void* ud, void* ptr, size_t osize, size_t nsize);
void* Alloc(void* ptr, size_t osize, size_t nsize);
size_t get_total() const { return total_allocated; }
size_t get_limit() const { return limit; }
private:
#ifdef YGOPRO_LOG_LUA_MEMORY_SIZE
FILE* log_file = nullptr;
void write_log();
#endif
lua_Alloc real_alloc;
void* real_ud;
size_t total_allocated = 0;
size_t limit = 0;
#ifdef YGOPRO_LOG_LUA_MEMORY_SIZE
size_t max_used = 0; // for logging purposes, to track peak memory usage
#endif
};
#endif // LUA_MEM_TRACKER_H
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
#include "interpreter.h" #include "interpreter.h"
interpreter::interpreter(duel* pd): coroutines(256) { interpreter::interpreter(duel* pd): coroutines(256) {
lua_state = luaL_newstate(); mem_tracker = new LuaMemTracker(YGOPRO_LUA_MEMORY_SIZE);
lua_state = lua_newstate(LuaMemTracker::AllocThunk, mem_tracker);
current_state = lua_state; current_state = lua_state;
pduel = pd; pduel = pd;
std::memcpy(lua_getextraspace(lua_state), &pd, LUA_EXTRASPACE); //set_duel_info std::memcpy(lua_getextraspace(lua_state), &pd, LUA_EXTRASPACE); //set_duel_info
...@@ -54,6 +55,7 @@ interpreter::interpreter(duel* pd): coroutines(256) { ...@@ -54,6 +55,7 @@ interpreter::interpreter(duel* pd): coroutines(256) {
} }
interpreter::~interpreter() { interpreter::~interpreter() {
lua_close(lua_state); lua_close(lua_state);
delete mem_tracker;
} }
void interpreter::register_card(card *pcard) { void interpreter::register_card(card *pcard) {
if (!pcard) if (!pcard)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <list> #include <list>
#include <vector> #include <vector>
#include <cstdio> #include <cstdio>
#include "LuaMemTracker.h"
class card; class card;
struct card_data; struct card_data;
...@@ -47,6 +48,7 @@ public: ...@@ -47,6 +48,7 @@ public:
char msgbuf[64]; char msgbuf[64];
lua_State* lua_state; lua_State* lua_state;
lua_State* current_state; lua_State* current_state;
LuaMemTracker* mem_tracker;
param_list params; param_list params;
param_list resumes; param_list resumes;
coroutine_map coroutines; coroutine_map coroutines;
...@@ -97,4 +99,8 @@ public: ...@@ -97,4 +99,8 @@ public:
#define COROUTINE_YIELD 2 #define COROUTINE_YIELD 2
#define COROUTINE_ERROR 3 #define COROUTINE_ERROR 3
#ifndef YGOPRO_LUA_MEMORY_SIZE
#define YGOPRO_LUA_MEMORY_SIZE 67108864 // 64 MB
#endif
#endif /* INTERPRETER_H_ */ #endif /* INTERPRETER_H_ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment