new directory hierarchy

master
Pablo Musa 2014-06-03 21:14:59 -03:00
parent 22a001fb5e
commit 4604eee835
15 changed files with 1934 additions and 17 deletions

View File

@ -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

52
scripts/calc_screen.lua Normal file
View File

@ -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

1
scripts/gdb.sh Executable file
View File

@ -0,0 +1 @@
LD_PRELOAD=/lib/libpthread.so.0 gdb --args lua5.2 $@

25
scripts/gen_test_out.sh Executable file
View File

@ -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

21
scripts/run.sh Executable file
View File

@ -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

145
src/graphic.h Normal file
View File

@ -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

195
src/gsdl.c Normal file
View File

@ -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;
}

229
src/lmp.c Normal file
View File

@ -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");
}

39
src/lmp.h Normal file
View File

@ -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

206
src/lmp_struct.c Normal file
View File

@ -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;
}

89
src/lmp_struct.h Normal file
View File

@ -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

151
src/luamemprofiler.c Normal file
View File

@ -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;
}

707
src/vmemory.c Normal file
View File

@ -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);
}

57
src/vmemory.h Normal file
View File

@ -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

View File

@ -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
===================================================================