new directory hierarchy
parent
22a001fb5e
commit
4604eee835
24
Makefile
24
Makefile
|
@ -21,25 +21,25 @@ LUA_LIBS = -llua5.2
|
|||
all: luamemprofiler.so
|
||||
|
||||
luamemprofiler.so: graphic.o lmp_struct.o vmemory.o lmp.o luamemprofiler.o
|
||||
$(CC) graphic.o lmp_struct.o vmemory.o lmp.o luamemprofiler.o -o luamemprofiler.so $(CFLAGS) $(SDL_LIBS) $(LUA_LIBS)
|
||||
cd src && $(CC) graphic.o lmp_struct.o vmemory.o lmp.o luamemprofiler.o -o luamemprofiler.so $(CFLAGS) $(SDL_LIBS) $(LUA_LIBS) && mv luamemprofiler.so ../
|
||||
|
||||
luamemprofiler.o: luamemprofiler.c lmp.h
|
||||
$(CC) -c luamemprofiler.c $(CFLAGS) $(LUA_CFLAGS)
|
||||
luamemprofiler.o:
|
||||
cd src && $(CC) -c luamemprofiler.c $(CFLAGS) $(LUA_CFLAGS)
|
||||
|
||||
lmp.o: lmp.c lmp.h lmp_struct.h vmemory.h
|
||||
$(CC) -c lmp.c $(CFLAGS) $(LUA_CFLAGS)
|
||||
lmp.o:
|
||||
cd src && $(CC) -c lmp.c $(CFLAGS) $(LUA_CFLAGS)
|
||||
|
||||
lmp_struct.o: lmp_struct.c lmp_struct.h
|
||||
$(CC) -c lmp_struct.c $(CFLAGS) $(LUA_CFLAGS)
|
||||
lmp_struct.o:
|
||||
cd src && $(CC) -c lmp_struct.c $(CFLAGS) $(LUA_CFLAGS)
|
||||
|
||||
vmemory.o: vmemory.c lmp.h vmemory.h graphic.h
|
||||
$(CC) -c vmemory.c $(CFLAGS) $(LUA_CFLAGS)
|
||||
vmemory.o:
|
||||
cd src && $(CC) -c vmemory.c $(CFLAGS) $(LUA_CFLAGS)
|
||||
|
||||
graphic.o: gsdl.c graphic.h
|
||||
$(CC) -c gsdl.c -o graphic.o $(CFLAGS) $(SDL_CFLAGS)
|
||||
graphic.o:
|
||||
cd src && $(CC) -c gsdl.c -o graphic.o $(CFLAGS) $(SDL_CFLAGS)
|
||||
|
||||
clean:
|
||||
rm *.o
|
||||
rm src/*.o
|
||||
|
||||
test:
|
||||
./run.sh
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
local bytes_per_pixel = {4, 8, 12, 16, 32}
|
||||
|
||||
function num_of_pixels(w, h)
|
||||
return w * (h/2)
|
||||
end
|
||||
|
||||
function num_of_bytes(nop, bpp)
|
||||
return bpp * nop
|
||||
end
|
||||
|
||||
function resolution(bpp, memused)
|
||||
local side = math.sqrt(memused * 1000000 * 2 / bpp / (4*3))+ 1;
|
||||
local w = side * 4;
|
||||
local h = side * 3;
|
||||
return w, h
|
||||
end
|
||||
|
||||
local op = 1
|
||||
while op do
|
||||
print("Digite 1 para numero de bytes, 2 para resolução, 3 para bytes per pixel")
|
||||
op = tonumber(io.read())
|
||||
|
||||
if op == 1 then
|
||||
print("Entre com a largura:")
|
||||
local w = tonumber(io.read())
|
||||
|
||||
print("Entre com a altura:")
|
||||
local h = tonumber(io.read())
|
||||
|
||||
for v=4,32,4 do
|
||||
local nop = num_of_pixels(w,h)
|
||||
local nob = num_of_bytes(nop, v)
|
||||
print(string.format("%d bytes %d x %d | %d | %d", v, w, h, nop, nob))
|
||||
end
|
||||
elseif op == 2 then
|
||||
print("Entre com a memoria maxima usada:")
|
||||
local mmu = tonumber(io.read())
|
||||
|
||||
for v=4,32,4 do
|
||||
local w, h = resolution(v, mmu)
|
||||
print(string.format("%d bytes %d x %d", v, w, h))
|
||||
end
|
||||
elseif op == 3 then
|
||||
print("Entre com a memoria maxima usada:")
|
||||
local mmu = tonumber(io.read())
|
||||
|
||||
local nop = num_of_pixels(800, 600)
|
||||
print(string.format("%d bytes %d x %d", mmu*1000000/nop, 800, 600))
|
||||
else
|
||||
op = nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
LD_PRELOAD=/lib/libpthread.so.0 gdb --args lua5.2 $@
|
|
@ -0,0 +1,25 @@
|
|||
# generates test output based on your machine.
|
||||
# You should run this file, before starting to work on the luamemprofiler code.
|
||||
#
|
||||
|
||||
TEST=cicle
|
||||
lua tests/$TEST.lua > tests/out/$TEST.txt
|
||||
|
||||
TEST=dupfinalizer
|
||||
lua tests/$TEST.lua > tests/out/$TEST.txt
|
||||
|
||||
TEST=eval
|
||||
lua tests/$TEST.lua > tests/out/$TEST.txt
|
||||
|
||||
TEST=function
|
||||
lua tests/$TEST.lua > tests/out/$TEST.txt
|
||||
|
||||
TEST=string
|
||||
lua tests/$TEST.lua > tests/out/$TEST.txt
|
||||
|
||||
TEST=table
|
||||
lua tests/$TEST.lua > tests/out/$TEST.txt
|
||||
|
||||
TEST=wfc
|
||||
lua tests/$TEST.lua > tests/out/$TEST.txt
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#############################################################################
|
||||
# Author: Pablo Musa #
|
||||
# Creation Date: mar 27 2011 #
|
||||
# Last Modification: aug 09 2011 #
|
||||
# #
|
||||
# Script for automated test #
|
||||
#############################################################################
|
||||
|
||||
TESTS=tests
|
||||
OUT=$TESTS/out
|
||||
|
||||
for i in $TESTS/*.lua
|
||||
do
|
||||
i=`basename $i .lua`
|
||||
# echo "lua5.2 $TESTS/$i.lua > tmp.txt"
|
||||
lua5.2 $TESTS/$i.lua > tmp.txt
|
||||
echo "diff tmp.txt $OUT/$i.txt"
|
||||
diff $OUT/$i.txt tmp.txt
|
||||
done
|
||||
|
||||
rm tmp.txt
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
**
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: mar 27 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** This is the header file of the drawing module. There is no graphic tool
|
||||
** attached to our implementation. One can choose any graphic library to
|
||||
** implement the graphic module. But one must implement all functions of
|
||||
** this file and respect their contracts.
|
||||
** If you are going to implement the graphic module using another graphic
|
||||
** tool, please pay attention to the functions definitions.
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LMP_GRAPHIC_H
|
||||
#define LMP_GRAPHIC_H
|
||||
|
||||
|
||||
#define LMP_EVENT_EMPTY 0
|
||||
#define LMP_EVENT_KEY 1
|
||||
#define LMP_EVENT_MOUSE 2
|
||||
#define LEFT_BUTTON 1
|
||||
#define RIGHT_BUTTON 3
|
||||
|
||||
#define FONT_SIZE 16
|
||||
|
||||
#define mkColor(r,g,b) ((r) | ((g) << 8) | ((b) << 16))
|
||||
|
||||
#define getRed(c) ((c) & 0xFF)
|
||||
#define getGreen(c) (((c) & 0xFF00) >> 8)
|
||||
#define getBlue(c) (((c) & 0xFF0000) >> 16)
|
||||
|
||||
#define DARKBLUE mkColor(0, 0, 139)
|
||||
#define DARKRED mkColor(139, 0, 0)
|
||||
#define DARKGREEN mkColor(0, 100, 0)
|
||||
#define DARKORANGE mkColor(255, 140, 0)
|
||||
#define DARKMAGENTA mkColor(139, 0, 139)
|
||||
#define DIMGRAY mkColor(105, 105, 105)
|
||||
#define LTWHITE mkColor(240, 240, 240)
|
||||
#define LTGRAY mkColor(211, 211, 211)
|
||||
#define WHITE mkColor(255, 255, 255)
|
||||
#define BLACK mkColor(0, 0, 0)
|
||||
#define RED mkColor(255, 0, 0)
|
||||
|
||||
|
||||
struct kevent {
|
||||
int key;
|
||||
};
|
||||
|
||||
struct mevent {
|
||||
int x, y, b;
|
||||
};
|
||||
|
||||
union LMP_event {
|
||||
struct kevent kevent;
|
||||
struct mevent mevent;
|
||||
};
|
||||
typedef union LMP_event LMP_Event;
|
||||
|
||||
/*
|
||||
** There are some available colors predefined in the beginning of this file.
|
||||
** Use the macros: get(Red, Green, Blue) to map from Color to R, G or B.
|
||||
*/
|
||||
typedef long Color;
|
||||
|
||||
typedef void Screen;
|
||||
typedef void Font;
|
||||
|
||||
/*
|
||||
** Create a new window with the specified width, height, icon and title.
|
||||
** This function must load a base font if the graphic tool does not have
|
||||
** one by default. This font will be used by other functions.
|
||||
** Returns the screen pointer.
|
||||
*/
|
||||
Screen *gr_newscreen (int width,int height,const char *icon,const char *title);
|
||||
|
||||
/*
|
||||
** Destroy the window referenced by the screen pointer.
|
||||
** This function must unload the font if any font was loaded in gr_newscreen.
|
||||
*/
|
||||
void gr_destroyscreen (Screen *screen);
|
||||
|
||||
/*
|
||||
** Draw a line in the window from (x0,y0) to (x1, y1).
|
||||
*/
|
||||
void gr_drawline (Screen *screen, int x0 , int y0 , int x1, int y1 );
|
||||
|
||||
/*
|
||||
** Draw an horizontal block from (x0,y) to x1 with blockheight.
|
||||
*/
|
||||
void gr_drawblock (Screen *screen, int x0 , int x1 , int y, int blockheight);
|
||||
|
||||
/*
|
||||
** Write the specified text beginning at (x,y).
|
||||
*/
|
||||
void gr_drawtext (Screen *screen, const char *text, int x, int y);
|
||||
|
||||
/*
|
||||
** Paint all window with the specified color.
|
||||
** See Color typedef (beginning of this file) for more details about Color.
|
||||
*/
|
||||
void gr_drawbackground (Screen *screen, Color color);
|
||||
|
||||
/*
|
||||
** Set the specified color for any following draw.
|
||||
** See Color typedef (beginning of this file) for more details about Color.
|
||||
*/
|
||||
void gr_setdrawcolor(Screen *screen, Color color);
|
||||
|
||||
/*
|
||||
** Set the specified color for any following text.
|
||||
** See Color typedef (beginning of this file) for more details about Color.
|
||||
*/
|
||||
void gr_settextcolor (Screen *screen, Color color);
|
||||
|
||||
/*
|
||||
** Return the width of one text character in pixels.
|
||||
*/
|
||||
int gr_gettextwidth(Screen *screen);
|
||||
|
||||
/*
|
||||
** Return the height of one text character in pixels.
|
||||
*/
|
||||
int gr_gettextheight(Screen *screen);
|
||||
|
||||
/*
|
||||
** Search for a keyboard or mouse event until queue is empty.
|
||||
** Return an int containing the event type (mouse, keyboard or empty).
|
||||
** This function removes all events from the top of the queue that are not
|
||||
** keydown or mousebuttondown events.
|
||||
*/
|
||||
int gr_getevent(Screen *screen, LMP_Event *event);
|
||||
|
||||
/*
|
||||
** Wait until a keyboard or mouse event occur.
|
||||
** Returns an int containing the event type (mouse, keyboard or empty).
|
||||
** This function discards all events from the top of the queue that are not
|
||||
** keydown or mousebuttondown events.
|
||||
*/
|
||||
int gr_waitevent(Screen *screen, LMP_Event *event);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
**
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: mar 27 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** This file contains the implementation of the graphic module (graphic.h)
|
||||
** using the SDL graphic toolkit and the SDL_ttf library.
|
||||
** See graphic.h for more details about the functions
|
||||
*/
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_ttf.h>
|
||||
#include <string.h>
|
||||
#include "graphic.h"
|
||||
|
||||
/* GLOBAL VARIABLES */
|
||||
static TTF_Font *font;
|
||||
static SDL_Colour fontcolor = {0,0,0};
|
||||
static int gr_textwidth;
|
||||
static int gr_textheight;
|
||||
|
||||
/* STATIC FUNCTIONS */
|
||||
static TTF_Font* loadfont(char* file, int ptsize);
|
||||
|
||||
/* GLOBAL FUNCTIONS */
|
||||
Screen *gr_newscreen(int width,int height,const char *icon,const char *title) {
|
||||
SDL_Window *screen;
|
||||
SDL_Renderer *renderer;
|
||||
|
||||
Uint32 vmode = SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_RESIZABLE;
|
||||
/*SDL_WINDOW_OPENGL;*/
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) == -1)
|
||||
return NULL;
|
||||
|
||||
screen = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, vmode);
|
||||
if(!screen) {
|
||||
printf("Unable to set video mode: %s\n", SDL_GetError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
SDL_SetWindowIcon(screen, SDL_LoadBMP(icon));
|
||||
|
||||
renderer = SDL_CreateRenderer(screen, -1, 0);
|
||||
if(!renderer) {
|
||||
printf("Unable to set renderer: %s\n", SDL_GetError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (TTF_Init() == -1) {
|
||||
printf("Unable to initialize SDL_ttf(fonts): %s \n", TTF_GetError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
font = loadfont("FreeMono.ttf", FONT_SIZE);
|
||||
|
||||
return (Screen*) renderer;
|
||||
}
|
||||
|
||||
void gr_destroyscreen (Screen *screen) {
|
||||
TTF_Quit();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
/* DRAW FUNCTIONS */
|
||||
void gr_drawline (Screen *screen, int x0, int y0, int x1, int y1) {
|
||||
SDL_Renderer *sdl_screen = (SDL_Renderer*) screen;
|
||||
SDL_RenderDrawLine(sdl_screen, x0, y0, x1, y1);
|
||||
SDL_RenderPresent(sdl_screen);
|
||||
}
|
||||
|
||||
void gr_drawblock (Screen *screen, int x0 , int x1 , int y, int blockheight) {
|
||||
SDL_Renderer *sdl_screen = (SDL_Renderer*) screen;
|
||||
SDL_Rect rect;
|
||||
rect.x = x0;
|
||||
rect.y = y;
|
||||
rect.w = x1 - x0 + 1; /* +1 -> draw x0 AND x1 */
|
||||
rect.h = blockheight;
|
||||
SDL_RenderFillRect(sdl_screen, &rect);
|
||||
SDL_RenderPresent(sdl_screen);
|
||||
}
|
||||
|
||||
void gr_drawtext(Screen *screen, const char *text, int x, int y) {
|
||||
SDL_Renderer *sdl_screen = (SDL_Renderer*) screen;
|
||||
SDL_Surface *tsurface;
|
||||
SDL_Texture *ttexture;
|
||||
SDL_Rect rect;
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.w = strlen(text) * gr_textwidth;
|
||||
rect.h = gr_textheight;
|
||||
|
||||
tsurface = TTF_RenderText_Solid(font, text, fontcolor);
|
||||
if(!tsurface) {
|
||||
printf("Unable to create text surface: %s \n", TTF_GetError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ttexture = SDL_CreateTextureFromSurface(sdl_screen, tsurface);
|
||||
SDL_FreeSurface(tsurface);
|
||||
if(!ttexture) {
|
||||
printf("Unable to create text texture: %s \n", SDL_GetError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
SDL_RenderCopy(sdl_screen, ttexture, NULL, &rect);
|
||||
SDL_RenderPresent(sdl_screen);
|
||||
}
|
||||
|
||||
void gr_drawbackground(Screen *screen, Color clr) {
|
||||
SDL_Renderer *sdl_screen = (SDL_Renderer*) screen;
|
||||
SDL_SetRenderDrawColor(sdl_screen, getRed(clr), getGreen(clr), getBlue(clr), SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(sdl_screen);
|
||||
SDL_RenderPresent(sdl_screen);
|
||||
}
|
||||
|
||||
/* SET FUNCTIONS */
|
||||
void gr_setdrawcolor(Screen *screen, Color clr) {
|
||||
SDL_Renderer *sdl_screen = (SDL_Renderer*) screen;
|
||||
SDL_SetRenderDrawColor(sdl_screen, getRed(clr), getGreen(clr), getBlue(clr), SDL_ALPHA_OPAQUE);
|
||||
}
|
||||
|
||||
void gr_settextcolor (Screen *screen, Color clr) {
|
||||
fontcolor.r = getRed(clr);
|
||||
fontcolor.g = getGreen(clr);
|
||||
fontcolor.b = getBlue(clr);
|
||||
}
|
||||
|
||||
/* GET FUNCTIONS */
|
||||
int gr_gettextwidth(Screen *screen) {
|
||||
return gr_textwidth;
|
||||
}
|
||||
|
||||
int gr_gettextheight(Screen *screen) {
|
||||
return gr_textheight;
|
||||
}
|
||||
|
||||
/* EVENT FUNCTIONS */
|
||||
int gr_getevent(Screen *screen, LMP_Event *event) {
|
||||
int res;
|
||||
SDL_Event sdlevent;
|
||||
|
||||
/* search for a keyboard or mouse event until list is empty */
|
||||
res = SDL_PollEvent(&sdlevent);
|
||||
while (res == 1) {
|
||||
if (sdlevent.type == SDL_KEYDOWN) {
|
||||
event->kevent.key = sdlevent.key.keysym.sym;
|
||||
return LMP_EVENT_KEY;
|
||||
} else if (sdlevent.type == SDL_MOUSEBUTTONDOWN) {
|
||||
event->mevent.x = sdlevent.button.x;
|
||||
event->mevent.y = sdlevent.button.y;
|
||||
return LMP_EVENT_MOUSE;
|
||||
}
|
||||
res = SDL_PollEvent(&sdlevent);
|
||||
}
|
||||
|
||||
/* no more events in the list */
|
||||
return LMP_EVENT_EMPTY;
|
||||
}
|
||||
|
||||
int gr_waitevent(Screen *screen, LMP_Event *event) {
|
||||
int res;
|
||||
SDL_Event sdlevent;
|
||||
|
||||
/* wait until a keyboard or mouse event occur. discard other events */
|
||||
res = SDL_WaitEvent(&sdlevent);
|
||||
while (res == 1) {
|
||||
if (sdlevent.type == SDL_KEYDOWN) {
|
||||
event->kevent.key = sdlevent.key.keysym.sym;
|
||||
return LMP_EVENT_KEY;
|
||||
} else if (sdlevent.type == SDL_MOUSEBUTTONDOWN) {
|
||||
event->mevent.b = sdlevent.button.button; /* 1 - Left | 3 - Right */
|
||||
event->mevent.x = sdlevent.button.x;
|
||||
event->mevent.y = sdlevent.button.y;
|
||||
return LMP_EVENT_MOUSE;
|
||||
}
|
||||
res = SDL_WaitEvent(&sdlevent);
|
||||
}
|
||||
|
||||
printf("Unable to wait for an event!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* STATIC FUNCTIONS */
|
||||
static TTF_Font* loadfont(char* file, int ptsize) {
|
||||
TTF_Font *tmpfont = TTF_OpenFont(file, ptsize);
|
||||
if (tmpfont == NULL){
|
||||
printf("Unable to load font: %s %s \n", file, TTF_GetError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
TTF_SizeText(tmpfont, "0", &gr_textwidth, &gr_textheight);
|
||||
return tmpfont;
|
||||
}
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
**
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: may 27 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** See lmp.h for module overview
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lmp.h"
|
||||
#include "vmemory.h"
|
||||
#include "lmp_struct.h"
|
||||
|
||||
#define LMP_FREE 0
|
||||
#define LMP_MALLOC 1
|
||||
#define LMP_REALLOC 2
|
||||
|
||||
|
||||
/* STATIC VARIABLES */
|
||||
/* ac = allocation counter */
|
||||
static int ac_string, ac_function, ac_userdata, ac_thread, ac_table, ac_other;
|
||||
|
||||
static long nallocs, alloc_size;
|
||||
static long nreallocs, realloc_size;
|
||||
static long nfrees, free_size;
|
||||
static long memoryuse, maxmemoryuse;
|
||||
static int Laddress;
|
||||
static int Maddress = 0;
|
||||
static int usegraphics;
|
||||
|
||||
/* STATIC FUNCTIONS */
|
||||
static void *lmp_malloc(size_t nsize, size_t osize);
|
||||
static void *lmp_free(void *ptr);
|
||||
static void *lmp_realloc(void *ptr, size_t nsize);
|
||||
static void initcounters();
|
||||
static void updatecounters(int alloctype, size_t size, size_t luatype);
|
||||
static void generatereport();
|
||||
|
||||
/* PUBLIC FUNCTIONS */
|
||||
void lmp_start(int lowestaddress, float memused, int usegraphic) {
|
||||
initcounters();
|
||||
st_newhash(usegraphic);
|
||||
usegraphics = usegraphic;
|
||||
Laddress = lowestaddress; /* save lowest address to calc mem needed */
|
||||
if (usegraphics)
|
||||
vm_start(lowestaddress, memused);
|
||||
}
|
||||
|
||||
void lmp_stop() {
|
||||
generatereport();
|
||||
|
||||
/* erase counters and blocks */
|
||||
initcounters();
|
||||
st_destroyhash();
|
||||
if (usegraphics)
|
||||
vm_stop();
|
||||
}
|
||||
|
||||
/* allocation function used by Lua when luamemprofiler is used */
|
||||
void *lmp_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||
(void) ud;
|
||||
(void) osize;
|
||||
|
||||
if (nsize == 0) { /* calls our malloc, free or realloc functions */
|
||||
return lmp_free(ptr);
|
||||
} else if (ptr == NULL) {
|
||||
return lmp_malloc(nsize, osize); /* osize is the lua_type */
|
||||
} else {
|
||||
return lmp_realloc(ptr, nsize);
|
||||
}
|
||||
}
|
||||
|
||||
/* STATIC FUNCTIONS */
|
||||
|
||||
/* does normal malloc and then alloc and update other structures */
|
||||
static void *lmp_malloc(size_t nsize, size_t luatype) {
|
||||
void *ptr = malloc(nsize); /* normal malloc */
|
||||
lmp_Block *new = (lmp_Block *) malloc (sizeof(lmp_Block));
|
||||
|
||||
st_initblock(new, ptr, nsize, luatype);
|
||||
st_insertblock(new);
|
||||
|
||||
updatecounters(LMP_MALLOC, nsize, luatype);
|
||||
if ((uintptr_t) ptr > Maddress) /* save max address to calc mem needed */
|
||||
Maddress = (uintptr_t) ptr;
|
||||
|
||||
if (usegraphics) /* if graphics enabled call function to handle */
|
||||
vm_newmemop(LMP_VM_MALLOC, ptr, luatype, nsize);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* free and update other structures and then does normal free */
|
||||
static void *lmp_free(void *ptr) {
|
||||
lmp_Block *block = st_removeblock(ptr);
|
||||
if (block != NULL) {
|
||||
int size = st_getsize(block);
|
||||
updatecounters(LMP_FREE, size, 0);
|
||||
if (usegraphics) { /* if graphics enabled call function to handle */
|
||||
vm_newmemop(LMP_VM_FREE, ptr, LUA_TFREE, size);
|
||||
}
|
||||
free(block);
|
||||
}
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** does normal realloc, assumes realloc always change object address (wich is
|
||||
** not true, but is simplier to program and costless) and updates block
|
||||
** information. then, if usegraphics, verify if realloc is enlarging or
|
||||
** shrinking and call vm_newop with the correct values. Optimise drawing if
|
||||
** realloc uses same object address. Finally, update counters.
|
||||
*/
|
||||
|
||||
static void *lmp_realloc(void *ptr, size_t nsize) {
|
||||
lmp_Block *block;
|
||||
size_t osize;
|
||||
void *p = realloc(ptr, nsize);
|
||||
if (p == NULL) return NULL;
|
||||
|
||||
block = st_removeblock(ptr); /* realloc usually changes memory address */
|
||||
if (block != NULL) {
|
||||
osize = st_getsize(block);
|
||||
st_setsize(block, nsize);
|
||||
st_setptr(block, p);
|
||||
st_insertblock(block);
|
||||
if (usegraphics) {
|
||||
int luatype = st_getluatype(block);
|
||||
if (ptr != p) { /* memory location changed */
|
||||
vm_newmemop(LMP_VM_REALLOC, ptr, LUA_TFREE, osize); /*erase old block*/
|
||||
vm_newmemop(LMP_VM_REALLOC, p, luatype, nsize);
|
||||
} else {
|
||||
if (nsize > osize) { /* enlarging block */
|
||||
vm_newmemop(LMP_VM_REALLOC, (char *) ptr + osize, luatype, nsize - osize);
|
||||
} else if (osize > nsize) { /* shrinking block - erase extra part */
|
||||
vm_newmemop(LMP_VM_REALLOC, (char*) ptr + nsize, LUA_TFREE, osize - nsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
updatecounters(LMP_REALLOC, nsize - osize, 0);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* STATIC FUNCTIONS */
|
||||
static void initcounters() {
|
||||
ac_string=0;ac_function=0;ac_userdata=0;ac_thread=0;ac_table=0;ac_other=0;
|
||||
nallocs=0;alloc_size=0;
|
||||
nreallocs=0;realloc_size=0;
|
||||
nfrees=0;free_size=0;
|
||||
memoryuse=0;maxmemoryuse=0;
|
||||
}
|
||||
|
||||
/* check alloctype and update counters accordingly */
|
||||
static void updatecounters (int alloctype, size_t size, size_t luatype) {
|
||||
if (alloctype == LMP_FREE) {
|
||||
nfrees = nfrees + 1;
|
||||
free_size = free_size + size;
|
||||
memoryuse = memoryuse - size;
|
||||
} else if (alloctype == LMP_REALLOC) {
|
||||
nreallocs = nreallocs + 1;
|
||||
realloc_size = realloc_size + size;
|
||||
memoryuse = memoryuse + size;
|
||||
if (memoryuse > maxmemoryuse) {
|
||||
maxmemoryuse = memoryuse;
|
||||
}
|
||||
} else if (alloctype == LMP_MALLOC) {
|
||||
nallocs = nallocs + 1;
|
||||
alloc_size = alloc_size + size;
|
||||
memoryuse = memoryuse + size;
|
||||
if (memoryuse > maxmemoryuse) {
|
||||
maxmemoryuse = memoryuse;
|
||||
}
|
||||
switch(luatype) {
|
||||
case LUA_TSTRING:
|
||||
ac_string++;
|
||||
break;
|
||||
case LUA_TFUNCTION:
|
||||
ac_function++;
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
ac_userdata++;
|
||||
break;
|
||||
case LUA_TTHREAD:
|
||||
ac_thread++;
|
||||
break;
|
||||
case LUA_TTABLE:
|
||||
ac_table++;
|
||||
break;
|
||||
default:
|
||||
ac_other++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** writes the report in the standard output. If not usegraphics, calculates
|
||||
** program memory usage and sugest memory consumption parameter for future
|
||||
** execution.
|
||||
*/
|
||||
static void generatereport() {
|
||||
float mem = ((float) (Maddress - Laddress) / 1000000) + 0.1;
|
||||
|
||||
if (!usegraphics)
|
||||
mem = mem + 0.4; /* empiric size of graphic mem usage */
|
||||
|
||||
printf("===================================================================\n");
|
||||
printf("Number of Mallocs=%ld\tTotal Malloc Size=%ld\n", nallocs, alloc_size);
|
||||
printf("Number of Reallocs=%ld\tTotal Realloc Size=%ld\n", nreallocs, realloc_size);
|
||||
printf("Number of Frees=%ld\tTotal Free Size=%ld\n", nfrees, free_size);
|
||||
printf("\nNumber of Allocs of Each Type:\n");
|
||||
printf(" String=%d | Function=%d | Userdata=%d | Thread=%d | Table=%d | Other=%d\n", ac_string, ac_function, ac_userdata, ac_thread, ac_table, ac_other);
|
||||
printf("\nMaximum Memory Used=%ld bytes\n", maxmemoryuse);
|
||||
|
||||
if (!usegraphics && nallocs > 0) {
|
||||
printf("\nWe suggest you run the application again using %.1f as parameter\n", mem);
|
||||
}
|
||||
printf("===================================================================\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
**
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: may 27 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** This module is responsible by defining the new allocation function and
|
||||
** by collecting all information about memory management.
|
||||
** At the end of the program execution or when luamemprofiler.stop() is
|
||||
** called, it generates a log containing several memory information.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef LMP_LMP_H
|
||||
#define LMP_LMP_H
|
||||
|
||||
/*
|
||||
** Initializes the counters, sets the lowest address of the heap and
|
||||
** enables/disables the use of the graphic module (vm_start).
|
||||
*/
|
||||
void lmp_start (int lowestaddress, float memused, int usegraphics);
|
||||
|
||||
/*
|
||||
** Finalizes the counters, free all blocks structures, stop the graphic
|
||||
** module (vm_stop) [if started] and generates the report (number of: mallocs,
|
||||
** frees, tables, ...).
|
||||
*/
|
||||
void lmp_stop ();
|
||||
|
||||
/*
|
||||
** Checks the alloc type (malloc, free, realloc) and update data in
|
||||
** accordance. Create, remove or update block structures, update report
|
||||
** counters (mallocs, tables, etc.) and call vm_newmemop if graphic
|
||||
** module is enabled.
|
||||
*/
|
||||
void *lmp_alloc (void *ud, void *ptr, size_t osize, size_t nsize);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
**
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: aug 16 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** See lmp_struct.h for module overview
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "lmp_struct.h"
|
||||
#include "lua.h"
|
||||
|
||||
#define HASH_SIZE 23 /* empiric hash size - need more tests to confirm */
|
||||
|
||||
|
||||
/* simple hash function */
|
||||
static int hashfunc(void *ptr) {
|
||||
return ((uintptr_t) ptr) % HASH_SIZE;
|
||||
}
|
||||
|
||||
|
||||
/* STATIC GLOBAL VARIABLE */
|
||||
static lmp_Block **lmp_head = NULL; /* hashtable for all blocks */
|
||||
static int usegraphics;
|
||||
|
||||
|
||||
/* GLOBAL VARIABLES - filter lists */
|
||||
/* multiply linked lists used for type filtering. used only in graphic mode */
|
||||
lmp_Block *lmp_string = NULL;
|
||||
lmp_Block *lmp_function = NULL;
|
||||
lmp_Block *lmp_userdata = NULL;
|
||||
lmp_Block *lmp_thread = NULL;
|
||||
lmp_Block *lmp_table = NULL;
|
||||
lmp_Block *lmp_other = NULL;
|
||||
lmp_Block *lmp_all = NULL; /* used to redraw all blocks */
|
||||
|
||||
|
||||
void st_newhash(int usegraphic) {
|
||||
int i;
|
||||
usegraphics = usegraphic;
|
||||
lmp_head = (lmp_Block **) malloc (HASH_SIZE * sizeof(lmp_Block*));
|
||||
for (i = 0; i < HASH_SIZE; i++) {
|
||||
lmp_head[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void st_destroyhash() {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < HASH_SIZE; i++) {
|
||||
lmp_Block *p;
|
||||
lmp_Block *head = lmp_head[i];
|
||||
while (head != NULL) {
|
||||
p = head;
|
||||
head = head->next;
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
free(lmp_head);
|
||||
|
||||
if (usegraphics) {
|
||||
lmp_string = NULL;
|
||||
lmp_function = NULL;
|
||||
lmp_userdata = NULL;
|
||||
lmp_thread = NULL;
|
||||
lmp_table = NULL;
|
||||
lmp_other = NULL;
|
||||
lmp_all = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lmp_Block *st_removeblock (void *ptr) {
|
||||
lmp_Block *p, *ant = NULL;
|
||||
int i = hashfunc(ptr);
|
||||
for (p = lmp_head[i]; p != NULL; ant = p, p = p->next) {
|
||||
if (p->ptr == ptr) {
|
||||
if (ant == NULL) {
|
||||
lmp_head[i] = p->next;
|
||||
} else {
|
||||
ant->next = p->next;
|
||||
}
|
||||
p->next = NULL;
|
||||
|
||||
if (usegraphics) {
|
||||
if (p->prevtype != NULL) {
|
||||
p->prevtype->nexttype = p->nexttype;
|
||||
}
|
||||
if (p->nexttype != NULL) {
|
||||
p->nexttype->prevtype = p->prevtype;
|
||||
}
|
||||
|
||||
if (p->prevall != NULL) {
|
||||
p->prevall->nextall = p->nextall;
|
||||
}
|
||||
if (p->nextall != NULL) {
|
||||
p->nextall->prevall = p->prevall;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void st_insertblock (lmp_Block *block) {
|
||||
lmp_Block **type;
|
||||
|
||||
int i = hashfunc(block->ptr);
|
||||
block->next = lmp_head[i];
|
||||
lmp_head[i] = block;
|
||||
|
||||
if (usegraphics) {
|
||||
switch (block->luatype) {
|
||||
case LUA_TSTRING:
|
||||
type = &lmp_string;
|
||||
break;
|
||||
case LUA_TFUNCTION:
|
||||
type = &lmp_function;
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
type = &lmp_userdata;
|
||||
break;
|
||||
case LUA_TTHREAD:
|
||||
type = &lmp_thread;
|
||||
break;
|
||||
case LUA_TTABLE:
|
||||
type = &lmp_table;
|
||||
break;
|
||||
default: /* OTHER */
|
||||
type = &lmp_other;
|
||||
break;
|
||||
}
|
||||
if (*type != NULL) {
|
||||
(*type)->prevtype = block;
|
||||
}
|
||||
block->nexttype = *type;
|
||||
block->prevtype = NULL;
|
||||
*type = block;
|
||||
|
||||
if (lmp_all != NULL) {
|
||||
lmp_all->prevall = block;
|
||||
}
|
||||
block->nextall = lmp_all;
|
||||
block->prevall = NULL;
|
||||
lmp_all = block;
|
||||
}
|
||||
}
|
||||
|
||||
void st_initblock (lmp_Block *block, void *ptr, size_t size, size_t luatype) {
|
||||
block->ptr = ptr;
|
||||
block->size = size;
|
||||
block->luatype = luatype;
|
||||
block->next = NULL;
|
||||
if (usegraphics) {
|
||||
block->nexttype = NULL;
|
||||
block->prevtype = NULL;
|
||||
block->nextall = NULL;
|
||||
block->prevall = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void *st_getptr(lmp_Block *block) {
|
||||
return block->ptr;
|
||||
}
|
||||
|
||||
size_t st_getsize(lmp_Block *block) {
|
||||
return block->size;
|
||||
}
|
||||
|
||||
size_t st_getluatype(lmp_Block *block) {
|
||||
return block->luatype;
|
||||
}
|
||||
|
||||
lmp_Block *st_getnext(lmp_Block *block) {
|
||||
return block->next;
|
||||
}
|
||||
|
||||
lmp_Block *st_getnexttype(lmp_Block *block) {
|
||||
return usegraphics ? block->nexttype : NULL;
|
||||
}
|
||||
|
||||
lmp_Block *st_getprevtype(lmp_Block *block) {
|
||||
return usegraphics ? block->prevtype : NULL;
|
||||
}
|
||||
|
||||
lmp_Block *st_getnextall(lmp_Block *block) {
|
||||
return usegraphics ? block->nextall : NULL;
|
||||
}
|
||||
|
||||
lmp_Block *st_getprevall(lmp_Block *block) {
|
||||
return usegraphics ? block->prevall : NULL;
|
||||
}
|
||||
|
||||
void st_setsize(lmp_Block *block, size_t size) {
|
||||
block->size = size;
|
||||
}
|
||||
|
||||
void st_setptr(lmp_Block *block, void *ptr) {
|
||||
block->ptr = ptr;
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
**
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: aug 16 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** This module is responsible by defining the block structure used keep
|
||||
** information of each allocation and by implementing data structures to
|
||||
** hold these blocks. The main data structure is a hash table with predefined
|
||||
** size and separate chaining with list heads. There are other seven multiply
|
||||
** linked lists used for type filtering. However these lists are used just in
|
||||
** the graphic module and do not produce overhead when graphics are disabled.
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LMP_LMPSTRUCT_H
|
||||
#define LMP_LMPSTRUCT_H
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
/*
|
||||
** Holds memory address, size and type of each block allocated.
|
||||
** Can have connection with 3 structures (hash table, type list and all list).
|
||||
** The hash table is the module main structure, the 'type list' is the list
|
||||
** where all blocks of a specific types are linked. The 'all list' is a list
|
||||
** where all blocks are sequentially linked.
|
||||
*/
|
||||
struct lmp_block {
|
||||
void *ptr;
|
||||
size_t size;
|
||||
size_t luatype;
|
||||
struct lmp_block *next;
|
||||
struct lmp_block *nexttype;
|
||||
struct lmp_block *prevtype;
|
||||
struct lmp_block *nextall;
|
||||
struct lmp_block *prevall;
|
||||
};
|
||||
typedef struct lmp_block lmp_Block;
|
||||
|
||||
|
||||
/*
|
||||
** Sets global usegraphics, malloc and initialize the hash table.
|
||||
*/
|
||||
void st_newhash(int usegraphic);
|
||||
|
||||
/*
|
||||
** Destroy and free the hash table and if usegraphics reset filter lists.
|
||||
*/
|
||||
void st_destroyhash();
|
||||
|
||||
/*
|
||||
** Searches for a block with specified ptr address. If the block is found,
|
||||
** removes the block from the hash table. If usegraghics, also removes
|
||||
** the block from his specific 'filter list' and from 'all list'.
|
||||
*/
|
||||
lmp_Block *st_removeblock (void *ptr);
|
||||
|
||||
/*
|
||||
** Inserts the specified block into the hash table. If usegraphics, also
|
||||
** inserts the block into his specific 'filter list' and into 'all list'.
|
||||
*/
|
||||
void st_insertblock (lmp_Block *block);
|
||||
|
||||
/*
|
||||
** Initializes the specified block with the specified values and sets the
|
||||
** hash table pointer to NULL. If usegraphics, initialize the other pointers.
|
||||
*/
|
||||
void st_initblock (lmp_Block *block, void *ptr, size_t nsize, size_t luatype);
|
||||
|
||||
/*
|
||||
** Gets and Sets.
|
||||
*/
|
||||
void *st_getptr(lmp_Block *block);
|
||||
size_t st_getsize(lmp_Block *block);
|
||||
size_t st_getluatype(lmp_Block *block);
|
||||
lmp_Block *st_getnext(lmp_Block *block);
|
||||
lmp_Block *st_getnexttype(lmp_Block *block);
|
||||
lmp_Block *st_getprevtype(lmp_Block *block);
|
||||
lmp_Block *st_getnextall(lmp_Block *block);
|
||||
lmp_Block *st_getprevall(lmp_Block *block);
|
||||
|
||||
void st_setsize(lmp_Block *block, size_t size);
|
||||
void st_setptr(lmp_Block *block, void *ptr);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: mar 27 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** This module is responsible for registering the luamemprofiler lib in the
|
||||
** Lua environment. It also sets a finalizer for the luamemprofiler library
|
||||
** which restores the lua_State original function when the library is garbage
|
||||
** collected.
|
||||
** The library implements two main functions (start and stop).
|
||||
** The start function receives an optional parameter (a number containing
|
||||
** the expected memory consumption) which determines if the library will
|
||||
** display real-time information and the granularity of the blocks.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lmp.h"
|
||||
|
||||
/* Keeps the default allocation function and the ud of a lua_State */
|
||||
typedef struct lmp_allocstructure {
|
||||
lua_Alloc f;
|
||||
void *ud;
|
||||
} lmp_Alloc;
|
||||
|
||||
/*
|
||||
** Called when main program ends.
|
||||
** Restores lua_State original allocation function.
|
||||
*/
|
||||
static int finalize (lua_State *L) {
|
||||
lmp_Alloc *s;
|
||||
|
||||
/* check lmp_Alloc */
|
||||
if (!lua_isuserdata(L, -1)) {
|
||||
lua_pushstring(L, "incorrect argument");
|
||||
lua_error(L);
|
||||
}
|
||||
|
||||
/* get lmp_Alloc and restore original allocation function */
|
||||
s = (lmp_Alloc *) lua_touserdata(L, -1);
|
||||
if (s->f != lua_getallocf (L, NULL)) {
|
||||
lua_setallocf(L, s->f, s->ud);
|
||||
lmp_stop();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register finalize function as metatable */
|
||||
static void create_finalizer(lua_State *L, lua_Alloc f, void *ud) {
|
||||
lmp_Alloc *s;
|
||||
|
||||
/* create metatable with finalize function (__gc field) */
|
||||
luaL_newmetatable(L, "luamemprofiler_mt");
|
||||
lua_pushcfunction(L, finalize);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
|
||||
/* create 'alloc' userdata (one ud for each Lua_State) */
|
||||
s = (lmp_Alloc*) lua_newuserdata(L, (size_t) sizeof(lmp_Alloc));
|
||||
s->f = f;
|
||||
s->ud = ud;
|
||||
|
||||
/* set userdata metatable */
|
||||
luaL_setmetatable(L, "luamemprofiler_mt");
|
||||
|
||||
/* insert userdata into registry table so it cannot be collected */
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "luamemprofiler_ud");
|
||||
}
|
||||
|
||||
/* Main module function. Starts the library */
|
||||
static int luamemprofiler_start(lua_State *L) {
|
||||
static lua_Alloc f;
|
||||
static void *ud;
|
||||
|
||||
float memused;
|
||||
int usegraphics = 0;
|
||||
|
||||
/* get the amount of memory expected to be used AND set enable graphics */
|
||||
memused = (float) lua_tonumber(L, 1);
|
||||
if (memused)
|
||||
usegraphics = 1;
|
||||
|
||||
/* get default allocation function */
|
||||
f = lua_getallocf(L, &ud);
|
||||
|
||||
/* check if start has been called before */
|
||||
if (f == lmp_alloc) {
|
||||
/* restore default allocation function and remove library finalizer */
|
||||
lmp_Alloc *s;
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "luamemprofiler_ud");
|
||||
s = (lmp_Alloc *) lua_touserdata(L, -1);
|
||||
lua_setallocf(L, s->f, s->ud);
|
||||
lua_getmetatable(L, -1);
|
||||
lua_pushnil(L);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
|
||||
lua_pushstring(L, "calling luamemprofiler start function twice");
|
||||
lua_error(L);
|
||||
}
|
||||
|
||||
/* create data_structure and set finalizer */
|
||||
create_finalizer(L, f, ud);
|
||||
lua_setallocf(L, lmp_alloc, ud);
|
||||
|
||||
/* L is in most cases the lowest address of the heap (easiest to access) */
|
||||
lmp_start((uintptr_t) L, memused, usegraphics);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* restore default allocation function and stop the other modules */
|
||||
static int luamemprofiler_stop(lua_State *L) {
|
||||
lmp_Alloc *s;
|
||||
|
||||
/* get 'alloc' userdata and restore original allocation function */
|
||||
lua_pushstring(L, "luamemprofiler_ud");
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
s = (lmp_Alloc*) lua_touserdata(L, -1);
|
||||
if (s == NULL) {
|
||||
lua_pushstring(L, "calling luamemprofiler stop function without calling start function");
|
||||
lua_error(L);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_setallocf(L, s->f, s->ud);
|
||||
|
||||
lmp_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**********************************
|
||||
* register structs and functions *
|
||||
**********************************/
|
||||
|
||||
/* luamemprofiler function registration array */
|
||||
static const luaL_Reg luamemprofiler[] = {
|
||||
{ "start", luamemprofiler_start},
|
||||
{ "stop", luamemprofiler_stop},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* register luamemprofiler functions */
|
||||
LUALIB_API int luaopen_luamemprofiler (lua_State *L) {
|
||||
luaL_newlib(L, luamemprofiler);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,707 @@
|
|||
/*
|
||||
**
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: mar 27 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** See vmemory.h for module overview
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <lualib.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#include "graphic.h"
|
||||
#include "vmemory.h"
|
||||
#include "lmp_struct.h"
|
||||
#include "lmp.h"
|
||||
|
||||
|
||||
#define WINDOW_TITLE "luamemprofiler v1.0"
|
||||
#define ICON_PATH "logo.bmp"
|
||||
|
||||
/* screen state */
|
||||
#define LMP_PAUSE 0
|
||||
#define LMP_EXEC 1
|
||||
#define LMP_FINISH -1
|
||||
#define LMP_ZOOM_OUT 0
|
||||
#define LMP_ZOOM_IN 1
|
||||
|
||||
#define MIN_mb_SIZE 1
|
||||
#define MIN_mb_WIDTH 800
|
||||
#define MIN_mb_HEIGHT 600
|
||||
|
||||
#define BOX_XINI 10 /* MINIMUM = 10 */
|
||||
#define BOX_YINI 10 /* MINIMUM = 10 */
|
||||
#define BOX_XEND (mb_width + BOX_XINI)
|
||||
#define BOX_YEND (mb_height + BOX_YINI)
|
||||
|
||||
#define RTCOLUMN_WIDTH 150 /* right column width */
|
||||
#define BTROW_HEIGHT 70 /* bottom row height */
|
||||
|
||||
#define BASE_SPACE 10 /* space for separating text from the box */
|
||||
#define BOX_BORDER 3 /* memory box border width */
|
||||
|
||||
#define LMP_FLINE 0 /* bottom row starts writing in first line (0) */
|
||||
#define LMP_ON 1
|
||||
#define LMP_OFF 0
|
||||
|
||||
|
||||
/* filter type menu - positions to draw, bool toggled, draw Color, and text */
|
||||
struct menuitem {
|
||||
int x;
|
||||
int y;
|
||||
int toggle;
|
||||
Color color;
|
||||
const char *name;
|
||||
};
|
||||
typedef struct menuitem LMP_Menuitem;
|
||||
|
||||
|
||||
/* GLOBAL VARIABLES */
|
||||
/* one block list for each filter type */
|
||||
extern lmp_Block *lmp_string;
|
||||
extern lmp_Block *lmp_function;
|
||||
extern lmp_Block *lmp_userdata;
|
||||
extern lmp_Block *lmp_thread;
|
||||
extern lmp_Block *lmp_table;
|
||||
extern lmp_Block *lmp_other;
|
||||
extern lmp_Block *lmp_all;
|
||||
|
||||
/* one menu for each filter type */
|
||||
static LMP_Menuitem mi_string;
|
||||
static LMP_Menuitem mi_function;
|
||||
static LMP_Menuitem mi_userdata;
|
||||
static LMP_Menuitem mi_thread;
|
||||
static LMP_Menuitem mi_table;
|
||||
static LMP_Menuitem mi_other;
|
||||
|
||||
/* STATIC GLOBAL VARIABLES */
|
||||
static Screen *screen;
|
||||
static uintptr_t laddress; /* first address of the program */
|
||||
static uintptr_t baseaddr; /* base address of the memory box */
|
||||
static int state = LMP_PAUSE; /* luamemprofiler state (paused or executing) */
|
||||
static int zoom = LMP_ZOOM_OUT; /* zoom state (in or out) */
|
||||
|
||||
static int sc_width; /* sc = screen */
|
||||
static int sc_height;
|
||||
static int mb_width; /* mb = memory box */
|
||||
static int mb_height;
|
||||
static int BYTES_PER_PIXEL = 4;
|
||||
static int BLOCK_HEIGHT = 2;
|
||||
|
||||
static int statesy; /* used to update the display with state and zoom */
|
||||
|
||||
/* STATIC FUNCTIONS */
|
||||
static void drawbtrow();
|
||||
static void toggleall();
|
||||
static void drawstates();
|
||||
static void drawmembox();
|
||||
static void checkevent();
|
||||
static void clearmembox();
|
||||
static void untoggleall();
|
||||
static int istoggled(size_t luatype);
|
||||
static void drawcallstack(int fline);
|
||||
static void drawrtcolumn(float memused);
|
||||
static int setcanvassize (float memused);
|
||||
static void inverttoggle(LMP_Menuitem *mi);
|
||||
static void drawmenuitem(LMP_Menuitem *item);
|
||||
static void drawreport(const char *text, int line);
|
||||
static void drawmemblock(int addr, size_t luatype, size_t size);
|
||||
static void writeblockinfo(void *ptr,size_t luatype,size_t size,int alloctype);
|
||||
static void calcmemdata(void *ptr, size_t size, int *reladdr, size_t *relsize);
|
||||
static void initmenuitem(LMP_Menuitem *mi, int x, int y, int toggle,
|
||||
Color color, const char* name);
|
||||
|
||||
/* GLOBAL FUNCTIONS */
|
||||
void vm_start(int lowestaddress, float memused) {
|
||||
/* if memused is very low uses default value and returns it */
|
||||
memused = setcanvassize (memused);
|
||||
screen = gr_newscreen(sc_width, sc_height, ICON_PATH, WINDOW_TITLE);
|
||||
laddress = lowestaddress;
|
||||
baseaddr = laddress;
|
||||
|
||||
gr_drawbackground(screen, LMP_VM_BACKGROUND_CL);
|
||||
drawmembox();
|
||||
drawrtcolumn(memused);
|
||||
drawbtrow();
|
||||
|
||||
checkevent();
|
||||
}
|
||||
|
||||
void vm_stop() {
|
||||
char dummy;
|
||||
state = LMP_FINISH;
|
||||
drawreport("Execution finished. The report is in the Terminal.", LMP_FLINE);
|
||||
drawstates();
|
||||
printf("Press Enter To Finish!");
|
||||
scanf("%c", &dummy);
|
||||
|
||||
gr_destroyscreen(screen);
|
||||
}
|
||||
|
||||
void vm_newmemop(int memop, void *ptr, size_t luatype, size_t size) {
|
||||
int p;
|
||||
size_t mb_size;
|
||||
calcmemdata(ptr, size, &p, &mb_size); /* calculate relative address */
|
||||
if (p > 0) { /* check if is a valid address */
|
||||
/* draw full block breaking lines if necessary */
|
||||
if (istoggled(luatype))
|
||||
drawmemblock(p, luatype, mb_size);
|
||||
if (state == LMP_PAUSE) {
|
||||
/* write in 'bottom row' block information(parameters) and call stack */
|
||||
writeblockinfo(ptr, luatype, size, memop);
|
||||
}
|
||||
/* check if there is any valid event and treat it */
|
||||
checkevent();
|
||||
}
|
||||
/* DEBUG else { possible print if block is smaller than baseaddress
|
||||
printf("Lower Pointer ptr=%d laddr=%d p=%d\n", (int) ptr, laddress, p);
|
||||
} */
|
||||
}
|
||||
|
||||
/* STATIC FUNCTIONS */
|
||||
|
||||
/* uses baseaddress to calculate the memory box position of a block */
|
||||
static void calcmemdata(void *ptr, size_t size, int *reladdr, size_t *relsize) {
|
||||
*reladdr = ((uintptr_t) ptr - baseaddr) / BYTES_PER_PIXEL;
|
||||
*relsize = (size / BYTES_PER_PIXEL);
|
||||
if (*relsize == 0) {
|
||||
*relsize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* draw specified text in report area (botton row) */
|
||||
static void drawreport(const char *text, int line) {
|
||||
int x = BOX_XINI;
|
||||
int y = BOX_YEND + BASE_SPACE + (line * gr_gettextheight(screen));
|
||||
|
||||
/* if line does not fit screen size, omit line */
|
||||
if (y > sc_height - gr_gettextheight(screen)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* if line is first line, new message -> clear bottom row */
|
||||
if (line == LMP_FLINE) {
|
||||
gr_setdrawcolor(screen, LMP_VM_BACKGROUND_CL);
|
||||
gr_drawblock(screen, BOX_XINI, BOX_XEND, BOX_YEND+BASE_SPACE, BTROW_HEIGHT);
|
||||
}
|
||||
|
||||
/* validate text size */
|
||||
if (strlen(text) > (mb_width / gr_gettextwidth(screen))) {
|
||||
gr_drawtext(screen, "Sorry, but the text is too large.", x, y);
|
||||
} else {
|
||||
gr_drawtext(screen, text, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/* draw up to 3 levels of the call stack */
|
||||
static void drawcallstack(int fline) {
|
||||
char textbuff[80] = "";
|
||||
int res, i = 0;
|
||||
lua_Debug ld;
|
||||
lua_State *L = (lua_State *) laddress;
|
||||
res = lua_getstack(L, i, &ld);
|
||||
while (res == 1 && i < (BTROW_HEIGHT/gr_gettextwidth(screen))) {
|
||||
int r;
|
||||
r = lua_getinfo(L, "lnS", &ld);
|
||||
if (r != 0) {
|
||||
int line = LMP_FLINE + i + fline; /* start in fline */
|
||||
if (strcmp(ld.what, "main") == 0) { /* main program execution */
|
||||
sprintf(textbuff, "Main - line:%d", ld.currentline);
|
||||
drawreport(textbuff, line);
|
||||
break;
|
||||
}
|
||||
if (strcmp(ld.what, "Lua") == 0) { /* some function execution */
|
||||
sprintf(textbuff, "Lua - file:'%s' func:'%s' field:'%s' line:%d",
|
||||
ld.short_src, ld.name, ld.namewhat, ld.currentline);
|
||||
drawreport(textbuff, line);
|
||||
}
|
||||
if (strcmp(ld.what, "C") == 0) { /* some C function execution */
|
||||
sprintf(textbuff, "C - func'%s' field:'%s'", ld.name, ld.namewhat);
|
||||
drawreport(textbuff, line);
|
||||
}
|
||||
} else {
|
||||
printf("luamemprofiler internal error: vmemory -> debuginfo -> invalid what.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
i++;
|
||||
res = lua_getstack(L, i, &ld);
|
||||
}
|
||||
}
|
||||
|
||||
/* draw blocks in the correct place (recursive calls for big blocks) */
|
||||
static void drawmemblock(int addr, size_t luatype, size_t size) {
|
||||
int x, y;
|
||||
x = (addr % mb_width) + BOX_XINI;
|
||||
y = ((addr / mb_width) * BLOCK_HEIGHT) + BOX_YINI;
|
||||
|
||||
/* just draw into valid areas */
|
||||
if (y >= BOX_YINI && (y + BLOCK_HEIGHT) <= BOX_YEND) {
|
||||
if (x + size > BOX_XEND){ /* break block to fit membox */
|
||||
size_t extrasize = size - (BOX_XEND + 1 - x); /* +1 -> XEND is valid */
|
||||
size = size - extrasize;
|
||||
|
||||
/* recursive call for breaking one block in different lines */
|
||||
drawmemblock(addr + (size - 1), luatype, extrasize); /* -1 -> XEND */
|
||||
}
|
||||
|
||||
switch(luatype) {
|
||||
case LUA_TSTRING:
|
||||
gr_setdrawcolor(screen, LMP_VM_STRING_CL);
|
||||
break;
|
||||
case LUA_TFUNCTION:
|
||||
gr_setdrawcolor(screen, LMP_VM_FUNCTION_CL);
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
gr_setdrawcolor(screen, LMP_VM_USERDATA_CL);
|
||||
break;
|
||||
case LUA_TTHREAD:
|
||||
gr_setdrawcolor(screen, LMP_VM_THREAD_CL);
|
||||
break;
|
||||
case LUA_TTABLE:
|
||||
gr_setdrawcolor(screen, LMP_VM_TABLE_CL);
|
||||
break;
|
||||
case LUA_TFREE:
|
||||
gr_setdrawcolor(screen, LMP_VM_FREE_CL);
|
||||
break;
|
||||
default:
|
||||
gr_setdrawcolor(screen, LMP_VM_OTHER_CL);
|
||||
}
|
||||
|
||||
/* block length is size, so draw from x to "size-1" */
|
||||
gr_drawblock(screen, x, x + size - 1, y, BLOCK_HEIGHT);
|
||||
}
|
||||
/* DEBUG else { possible use when all blocks have to be drawn
|
||||
printf("draw block (%d, %d) addr = %d\n", x, y, addr); } */
|
||||
}
|
||||
|
||||
/*
|
||||
** traverse a filter list drawing all blocks. 'block' is the first block in the
|
||||
** list and 'fnextblock' is a function that returns the next block in the list
|
||||
** or NULL
|
||||
*/
|
||||
void drawblocklist(lmp_Block *block, lmp_Block* (*fnextblock) (lmp_Block*)) {
|
||||
int p;
|
||||
size_t mb_size;
|
||||
while (block != NULL) { /* list is not empty */
|
||||
calcmemdata(block->ptr, st_getsize(block), &p, &mb_size);
|
||||
if (p > 0) {
|
||||
int luatype = istoggled(block->luatype) ? block->luatype : LUA_TFREE;
|
||||
drawmemblock(p, luatype, mb_size);
|
||||
}
|
||||
block = fnextblock(block);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** redraw blocks using bigger size and new baseaddress. The new base address is
|
||||
** calculated using 'y' coordinate. All blocks above this 'y' (y included) are
|
||||
** redrawn.
|
||||
*/
|
||||
static void zoomin(int x, int y) {
|
||||
int p;
|
||||
size_t mb_size;
|
||||
lmp_Block *block;
|
||||
|
||||
zoom = LMP_ZOOM_IN; /* change zoom state */
|
||||
drawstates(); /* update display with new state */
|
||||
clearmembox(); /* clear memory box for new blocks in zoom mode */
|
||||
|
||||
/* calculates baseaddress using old baseaddress and 'y' */
|
||||
baseaddr = (((y - BOX_YINI) / BLOCK_HEIGHT) * (mb_width)
|
||||
* BYTES_PER_PIXEL) + baseaddr;
|
||||
BYTES_PER_PIXEL = BYTES_PER_PIXEL / 2; /* width 2x bigger */
|
||||
BLOCK_HEIGHT = BLOCK_HEIGHT * 2; /* height 2x bigger */
|
||||
for(block = lmp_all; block != NULL; block = st_getnextall(block)) {
|
||||
/* calculates new block values in memry box (relative address and size) */
|
||||
p = ((uintptr_t) block->ptr - baseaddr) / BYTES_PER_PIXEL;
|
||||
mb_size = (block->size / BYTES_PER_PIXEL);
|
||||
if (mb_size == 0) {
|
||||
mb_size = 1;
|
||||
}
|
||||
/* check if block is inside zoom */
|
||||
if (istoggled(block->luatype) && p >= 0 &&
|
||||
p <= (mb_width * BYTES_PER_PIXEL) * (mb_height / BLOCK_HEIGHT)) {
|
||||
drawmemblock(p, block->luatype, mb_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* redraw blocks using smaller size and old baseaddress. */
|
||||
static void zoomout() {
|
||||
zoom = LMP_ZOOM_OUT; /* change zoom state */
|
||||
drawstates(); /* update display with new state */
|
||||
clearmembox(); /* clear memory box for new blocks without zoom mode */
|
||||
|
||||
BYTES_PER_PIXEL = BYTES_PER_PIXEL * 2; /* width 2x smaller */
|
||||
BLOCK_HEIGHT = BLOCK_HEIGHT / 2; /* height 2x smaller */
|
||||
|
||||
baseaddr = laddress; /* restore baseaddress */
|
||||
drawblocklist(lmp_all, st_getnextall); /* draw all blocks */
|
||||
}
|
||||
|
||||
static void checkevent() {
|
||||
int eventtype;
|
||||
LMP_Event event;
|
||||
|
||||
if (state == LMP_EXEC) { /* normal execution - only accepts pause command */
|
||||
eventtype = gr_getevent(screen, &event); /* gets an event if exists */
|
||||
if (eventtype == LMP_EVENT_KEY && event.kevent.key == ' ') { /* pause */
|
||||
state = LMP_PAUSE;
|
||||
drawstates(); /* update display with new state */
|
||||
drawreport("Press: 'space' to resume execution; 'n' to resume until next memory operation;", LMP_FLINE);
|
||||
drawreport("'c' to clear the memory box; 's,f,u,h,t,o' to redraw blocks of specific type;", LMP_FLINE + 1);
|
||||
drawreport("'a' to redraw all blocks; left-click for zoom in and right-click for zoom out.", LMP_FLINE + 2);
|
||||
}
|
||||
}
|
||||
|
||||
while (state != LMP_EXEC) { /* execution is paused or finished */
|
||||
lmp_Block* (*fnextblock) (lmp_Block*) = st_getnexttype;
|
||||
lmp_Block *block = NULL;
|
||||
|
||||
eventtype = gr_waitevent(screen, &event); /* wait for a valid event */
|
||||
if (eventtype == LMP_EVENT_KEY) {
|
||||
switch (event.kevent.key) {
|
||||
case ' ': /* space key - continue - resumes normal execution */
|
||||
state = LMP_EXEC;
|
||||
drawstates();
|
||||
drawreport("Press 'space' to Pause execution.", LMP_FLINE);
|
||||
return;
|
||||
case 'n': /* next - execute next memory operation */
|
||||
return;
|
||||
case 's': /* draw filter type - set correct list and toggle */
|
||||
inverttoggle(&mi_string);
|
||||
block = lmp_string;
|
||||
break;
|
||||
case 'f':
|
||||
inverttoggle(&mi_function);
|
||||
block = lmp_function;
|
||||
break;
|
||||
case 'u':
|
||||
inverttoggle(&mi_userdata);
|
||||
block = lmp_userdata;
|
||||
break;
|
||||
case 'h':
|
||||
inverttoggle(&mi_thread);
|
||||
block = lmp_thread;
|
||||
break;
|
||||
case 't':
|
||||
inverttoggle(&mi_table);
|
||||
block = lmp_table;
|
||||
break;
|
||||
case 'o':
|
||||
inverttoggle(&mi_other);
|
||||
block = lmp_other;
|
||||
break;
|
||||
case 'a': /* draw all blocks */
|
||||
toggleall();
|
||||
block = lmp_all;
|
||||
fnextblock = st_getnextall;
|
||||
break;
|
||||
case 'c': /* erase all blocks from memory box */
|
||||
untoggleall();
|
||||
clearmembox();
|
||||
}
|
||||
drawblocklist(block, fnextblock);
|
||||
} else if (eventtype == LMP_EVENT_MOUSE) {
|
||||
if (event.mevent.b == LEFT_BUTTON && zoom == LMP_ZOOM_OUT) {
|
||||
zoomin(event.mevent.x, event.mevent.y);
|
||||
} else if (event.mevent.b == RIGHT_BUTTON && zoom == LMP_ZOOM_IN) {
|
||||
zoomout();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** write in bottom row the memory operation and the block info.
|
||||
** block info = allocation type, block (address, type and size) and call stack
|
||||
*/
|
||||
static void writeblockinfo(void *ptr, size_t luatype, size_t size, int alloctype) {
|
||||
char textbuff[60];
|
||||
char ltype[9];
|
||||
char atype[8];
|
||||
switch(luatype) {
|
||||
case LUA_TSTRING:
|
||||
strcpy(ltype, "String");
|
||||
break;
|
||||
case LUA_TFUNCTION:
|
||||
strcpy(ltype, "Function");
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
strcpy(ltype, "Userdata");
|
||||
break;
|
||||
case LUA_TTHREAD:
|
||||
strcpy(ltype, "Thread");
|
||||
break;
|
||||
case LUA_TTABLE:
|
||||
strcpy(ltype, "Table");
|
||||
break;
|
||||
default:
|
||||
strcpy(ltype, "Other");
|
||||
break;
|
||||
}
|
||||
switch(alloctype) {
|
||||
case LMP_VM_FREE:
|
||||
strcpy(atype, "Free");
|
||||
break;
|
||||
case LMP_VM_MALLOC:
|
||||
strcpy(atype, "Malloc");
|
||||
break;
|
||||
case LMP_VM_REALLOC:
|
||||
strcpy(atype, "Realloc");
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(textbuff, "%s | addr = %p | type = %s | size = %luB", atype,
|
||||
ptr, ltype, (unsigned long) size);
|
||||
drawreport(textbuff, LMP_FLINE);
|
||||
drawcallstack(LMP_FLINE + 1);
|
||||
}
|
||||
|
||||
/* draw border lines and clear memory box */
|
||||
static void drawmembox() {
|
||||
int i;
|
||||
|
||||
gr_setdrawcolor(screen, BLACK);
|
||||
for (i = 1; i <= BOX_BORDER; i++) {
|
||||
int x1 = BOX_XINI - i, x2 = BOX_XEND + i;
|
||||
int y1 = BOX_YINI - i, y2 = BOX_YEND + i;
|
||||
gr_drawline(screen, x1, y1, x2, y1);
|
||||
gr_drawline(screen, x1, y2, x2, y2);
|
||||
gr_drawline(screen, x1, y1, x1, y2);
|
||||
gr_drawline(screen, x2, y1, x2, y2);
|
||||
}
|
||||
clearmembox();
|
||||
}
|
||||
|
||||
/* draw one item of the right column */
|
||||
static void drawmenuitem(LMP_Menuitem *item) {
|
||||
int offset = gr_gettextwidth(screen) * strlen(item->name) + 3;
|
||||
int bx = item->x + offset;
|
||||
int by = item->y + 4;
|
||||
gr_settextcolor(screen, BLACK);
|
||||
gr_drawtext(screen, item->name, item->x, item->y);
|
||||
if (item->toggle) {
|
||||
gr_setdrawcolor(screen, item->color);
|
||||
gr_drawblock(screen, bx, bx + 10, by, 10);
|
||||
} else {
|
||||
gr_setdrawcolor(screen, LMP_VM_BACKGROUND_CL);
|
||||
gr_drawblock(screen, bx, bx + 10, by, 10);
|
||||
|
||||
gr_setdrawcolor(screen, item->color);
|
||||
gr_drawline(screen, bx, by, bx + 10, by);
|
||||
gr_drawline(screen, bx, by, bx, by + 10);
|
||||
gr_drawline(screen, bx, by+ 10, bx + 10, by + 10);
|
||||
gr_drawline(screen, bx + 10, by, bx + 10, by + 10);
|
||||
}
|
||||
}
|
||||
|
||||
/* write a line division(black) and a label(red) in (x,y) coordinate */
|
||||
static int drawl(const char *text, int x, int y) {
|
||||
int text_width = strlen(text) * gr_gettextwidth(screen);
|
||||
int center_offset = (RTCOLUMN_WIDTH - (text_width + BASE_SPACE))/2;
|
||||
|
||||
gr_setdrawcolor(screen, BLACK);
|
||||
gr_drawline(screen, x, y, sc_width - BASE_SPACE, y);
|
||||
y = y + 10;
|
||||
|
||||
gr_settextcolor(screen, RED);
|
||||
gr_drawtext(screen, text, x + center_offset, y);
|
||||
return y;
|
||||
}
|
||||
|
||||
/* write initial message in the bottom row */
|
||||
static void drawbtrow() {
|
||||
gr_settextcolor(screen, BLACK);
|
||||
drawreport("Welcome to the luamemprofiler library. Press 'space' to run the program", LMP_FLINE);
|
||||
drawreport("normally or 'n' to execute the program until next memory operation.", LMP_FLINE + 1);
|
||||
}
|
||||
|
||||
/* draw right column, including initial states (paused, zoom in) */
|
||||
static void drawrtcolumn(float memused) {
|
||||
int x = BOX_XEND + BOX_BORDER + BASE_SPACE;
|
||||
int y = BOX_YINI;
|
||||
int offset = 30;
|
||||
char textbuff[15];
|
||||
|
||||
/* draw basic information */
|
||||
y = drawl("BASIC INFO", x, y);
|
||||
y = y + offset;
|
||||
|
||||
gr_settextcolor(screen, BLACK);
|
||||
gr_drawtext(screen, "Memory Size", x, y);
|
||||
y = y + gr_gettextwidth(screen) + 5;
|
||||
sprintf(textbuff, "%.1fMb", memused);
|
||||
gr_drawtext(screen, textbuff, x, y);
|
||||
y = y + offset;
|
||||
|
||||
gr_drawtext(screen, "Granularity", x, y);
|
||||
y = y + gr_gettextwidth(screen) + 5;
|
||||
sprintf(textbuff, "1x2 px = %dB", BYTES_PER_PIXEL);
|
||||
gr_drawtext(screen, textbuff, x, y);
|
||||
y = y + offset;
|
||||
|
||||
/* draw key menu and labels */
|
||||
y = drawl("COMMANDS", x, y);
|
||||
y = y + offset;
|
||||
|
||||
gr_settextcolor(screen, BLACK);
|
||||
initmenuitem(&mi_string, x, y, LMP_ON, LMP_VM_STRING_CL, "s - String");
|
||||
drawmenuitem(&mi_string);
|
||||
y = y + offset;
|
||||
initmenuitem(&mi_function, x, y, LMP_ON, LMP_VM_FUNCTION_CL, "f - Function");
|
||||
drawmenuitem(&mi_function);
|
||||
y = y + offset;
|
||||
initmenuitem(&mi_userdata, x, y, LMP_ON, LMP_VM_USERDATA_CL, "u - Userdata");
|
||||
drawmenuitem(&mi_userdata);
|
||||
y = y + offset;
|
||||
initmenuitem(&mi_thread, x, y, LMP_ON, LMP_VM_THREAD_CL, "h - Thread");
|
||||
drawmenuitem(&mi_thread);
|
||||
y = y + offset;
|
||||
initmenuitem(&mi_table, x, y, LMP_ON, LMP_VM_TABLE_CL, "t - Table");
|
||||
drawmenuitem(&mi_table);
|
||||
y = y + offset;
|
||||
initmenuitem(&mi_other, x, y, LMP_ON, LMP_VM_OTHER_CL, "o - Other");
|
||||
drawmenuitem(&mi_other);
|
||||
y = y + offset;
|
||||
gr_drawtext(screen, "a - All", x, y);
|
||||
y = y + offset;
|
||||
gr_drawtext(screen, "c - Clear", x, y);
|
||||
y = y + offset;
|
||||
gr_drawtext(screen, "n - Next", x, y);
|
||||
y = y + offset;
|
||||
|
||||
/* draw luamemprofiler state and zoom state */
|
||||
y = drawl("STATE", x, y);
|
||||
y = y + offset;
|
||||
|
||||
statesy = y; /* set where to redraw states */
|
||||
gr_settextcolor(screen, BLACK);
|
||||
gr_drawtext(screen, "lmp: PAUSED", x, y);
|
||||
y = y + offset;
|
||||
gr_drawtext(screen, "zoom: OUT", x, y);
|
||||
}
|
||||
|
||||
/* update states (pause x execution || [zoom] in x out */
|
||||
static void drawstates() {
|
||||
int x = BOX_XEND + BOX_BORDER + BASE_SPACE;
|
||||
int y = statesy;
|
||||
int offset = 30;
|
||||
|
||||
/* erase old text */
|
||||
gr_setdrawcolor(screen, LMP_VM_BACKGROUND_CL);
|
||||
gr_drawblock(screen, x, x + RTCOLUMN_WIDTH, y, 50);
|
||||
|
||||
/* write new text */
|
||||
gr_settextcolor(screen, BLACK);
|
||||
if(state == LMP_PAUSE) {
|
||||
gr_drawtext(screen, "lmp: PAUSED", x, y);
|
||||
} else if (state == LMP_EXEC) {
|
||||
gr_drawtext(screen, "lmp: EXECUTING", x, y);
|
||||
} else if (state == LMP_FINISH) {
|
||||
gr_drawtext(screen, "lmp: FINISHED", x, y);
|
||||
}
|
||||
y = y + offset;
|
||||
|
||||
if(zoom == LMP_ZOOM_OUT) {
|
||||
gr_drawtext(screen, "zoom: OUT", x, y);
|
||||
} else if(zoom == LMP_ZOOM_IN) {
|
||||
gr_drawtext(screen, "zoom: IN", x, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* calculates and sets screen and memory box width and height */
|
||||
static int setcanvassize (float memused) {
|
||||
if (memused <= (float) MIN_mb_SIZE) {
|
||||
mb_width = MIN_mb_WIDTH;
|
||||
mb_height = MIN_mb_HEIGHT;
|
||||
memused = MIN_mb_SIZE;
|
||||
} else { /* MAX MEM FOR 800 x 600 resolution */
|
||||
int side;
|
||||
if (memused > 1) {
|
||||
BYTES_PER_PIXEL = ((int) memused) * 4;
|
||||
}
|
||||
/* (1Mb * BLOCK_HEIGHT / BYTES_PER_PIXEL / PROPORTION(4:3)) */
|
||||
side = (int) sqrt(memused*1000000*BLOCK_HEIGHT/BYTES_PER_PIXEL/(4*3))+1;
|
||||
mb_width = side * 4;
|
||||
mb_height = side * 3;
|
||||
}
|
||||
sc_width = BOX_XINI + mb_width + BOX_BORDER + BASE_SPACE + RTCOLUMN_WIDTH;
|
||||
sc_height = BOX_YINI + mb_height + BOX_BORDER + BASE_SPACE + BTROW_HEIGHT;
|
||||
return memused;
|
||||
}
|
||||
|
||||
/* paint all memory box with defined color (erase drawn blocks) */
|
||||
static void clearmembox() {
|
||||
gr_setdrawcolor(screen, LMP_VM_MEMBOX_CL);
|
||||
gr_drawblock(screen, BOX_XINI, BOX_XEND, BOX_YINI, BOX_YEND - BOX_YINI);
|
||||
}
|
||||
|
||||
static int istoggled(size_t luatype) {
|
||||
switch(luatype) {
|
||||
case LUA_TSTRING:
|
||||
return mi_string.toggle;
|
||||
case LUA_TFUNCTION:
|
||||
return mi_function.toggle;
|
||||
case LUA_TUSERDATA:
|
||||
return mi_userdata.toggle;
|
||||
case LUA_TTHREAD:
|
||||
return mi_thread.toggle;
|
||||
case LUA_TTABLE:
|
||||
return mi_table.toggle;
|
||||
default:
|
||||
return mi_other.toggle;
|
||||
}
|
||||
}
|
||||
|
||||
static void toggleall() {
|
||||
mi_string.toggle = LMP_ON;
|
||||
drawmenuitem(&mi_string);
|
||||
mi_function.toggle = LMP_ON;
|
||||
drawmenuitem(&mi_function);
|
||||
mi_userdata.toggle = LMP_ON;
|
||||
drawmenuitem(&mi_userdata);
|
||||
mi_thread.toggle = LMP_ON;
|
||||
drawmenuitem(&mi_thread);
|
||||
mi_table.toggle = LMP_ON;
|
||||
drawmenuitem(&mi_table);
|
||||
mi_other.toggle = LMP_ON;
|
||||
drawmenuitem(&mi_other);
|
||||
}
|
||||
|
||||
static void untoggleall() {
|
||||
mi_string.toggle = LMP_OFF;
|
||||
drawmenuitem(&mi_string);
|
||||
mi_function.toggle = LMP_OFF;
|
||||
drawmenuitem(&mi_function);
|
||||
mi_userdata.toggle = LMP_OFF;
|
||||
drawmenuitem(&mi_userdata);
|
||||
mi_thread.toggle = LMP_OFF;
|
||||
drawmenuitem(&mi_thread);
|
||||
mi_table.toggle = LMP_OFF;
|
||||
drawmenuitem(&mi_table);
|
||||
mi_other.toggle = LMP_OFF;
|
||||
drawmenuitem(&mi_other);
|
||||
}
|
||||
|
||||
static void initmenuitem(LMP_Menuitem *mi, int x, int y, int toggle,
|
||||
Color color, const char* name) {
|
||||
mi->x = x; mi->y = y; mi->toggle = toggle;
|
||||
mi->color = color; mi->name = name;
|
||||
}
|
||||
|
||||
/* change toggle settings and redraw menu item */
|
||||
static void inverttoggle(LMP_Menuitem *mi) {
|
||||
mi->toggle = !mi->toggle;
|
||||
drawmenuitem(mi);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
**
|
||||
** Author: Pablo Musa
|
||||
** Creation Date: mar 27 2011
|
||||
** Last Modification: aug 22 2011
|
||||
** See Copyright Notice in COPYRIGHT
|
||||
**
|
||||
** This module manages the graphical display offered by the library. It defines
|
||||
** the size of each element: right column, bottom row, memory box, box border,
|
||||
** etc. It also dynamically calculates: block's bytes per pixel based on the
|
||||
** memory consumption; the relative address of each pointer; the x, y
|
||||
** coordinate to the block; the zoom in and zoom out.
|
||||
** Finally, this module is responsible by managing the events and the
|
||||
** corresponding actions.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef LMP_VMEMORY_H
|
||||
#define LMP_VMEMORY_H
|
||||
|
||||
#include "graphic.h"
|
||||
|
||||
#define LMP_VM_FREE 0
|
||||
#define LMP_VM_MALLOC 1
|
||||
#define LMP_VM_REALLOC 2
|
||||
#define LUA_TFREE 11
|
||||
|
||||
#define LMP_VM_STRING_CL DARKRED
|
||||
#define LMP_VM_FUNCTION_CL DARKMAGENTA
|
||||
#define LMP_VM_USERDATA_CL DARKGREEN
|
||||
#define LMP_VM_THREAD_CL DARKORANGE
|
||||
#define LMP_VM_TABLE_CL DARKBLUE
|
||||
#define LMP_VM_OTHER_CL DIMGRAY
|
||||
#define LMP_VM_FREE_CL WHITE
|
||||
|
||||
#define LMP_VM_BACKGROUND_CL LTGRAY
|
||||
#define LMP_VM_MEMBOX_CL WHITE
|
||||
|
||||
|
||||
/*
|
||||
** Calculates window size (based on expected memory consumption).
|
||||
** Initializes the whole window (memory box, bottom row, right column).
|
||||
*/
|
||||
void vm_start(int lowestaddress, float memused);
|
||||
|
||||
/*
|
||||
** Calls gr_destroyscreen to destroy the window.
|
||||
*/
|
||||
void vm_stop();
|
||||
|
||||
/*
|
||||
** Module main function. It is responsible by managing new memory operations
|
||||
** and user events.
|
||||
*/
|
||||
void vm_newmemop(int memop, void *ptr, size_t luatype, size_t size);
|
||||
|
||||
#endif
|
|
@ -1,12 +1,12 @@
|
|||
===================================================================
|
||||
Number of Mallocs=13984 Total Malloc Size=1179949
|
||||
Number of Mallocs=13982 Total Malloc Size=1179789
|
||||
Number of Reallocs=12 Total Realloc Size=65520
|
||||
Number of Frees=3860 Total Free Size=369797
|
||||
Number of Frees=3857 Total Free Size=369551
|
||||
|
||||
Number of Allocs of Each Type:
|
||||
String=6142 | Function=4 | Userdata=1 | Thread=0 | Table=2606 | Other=5231
|
||||
String=6142 | Function=4 | Userdata=1 | Thread=0 | Table=2606 | Other=5229
|
||||
|
||||
Maximum Memory Used=875672 bytes
|
||||
Maximum Memory Used=875758 bytes
|
||||
|
||||
We suggest you run the application again using 349.0 as parameter
|
||||
We suggest you run the application again using -1212.4 as parameter
|
||||
===================================================================
|
||||
|
|
Loading…
Reference in New Issue