Skip to content
Snippets Groups Projects
Memleak_check.hpp 9.05 KiB
Newer Older
Pietro Incardona's avatar
Pietro Incardona committed
#include "config.h"
#include <iostream>
#include <map>
#include <iomanip>
Pietro Incardona's avatar
Pietro Incardona committed

#ifndef MEMLEAK_CHECK_HPP
#define MEMLEAK_CHECK_HPP

typedef unsigned char * byte_ptr;

#ifdef SE_CLASS2

/////// POSSIBLE EVENTS /////////

#define VCLUSTER_EVENT 0x2001

#define VECTOR_EVENT 0x1102
#define VECTOR_STD_EVENT 0x1101
#define GRID_EVENT 0x1100

#define VECTOR_DIST_EVENT 0x4002
#define GRID_DIST_EVENT   0x4001

#define HEAPMEMORY_EVENT 0x0100
#define CUDAMEMORY_EVENT 0x0101

/////////////////////////////////

Pietro Incardona's avatar
Pietro Incardona committed
#include "util/se_util.hpp"
#include "ptr_info.hpp"
Pietro Incardona's avatar
Pietro Incardona committed

#define MEM_ERROR 1300lu

extern long int msg_on_alloc;
extern long int thr_on_alloc;
extern std::string col_stop;
extern long int new_data;
Pietro Incardona's avatar
Pietro Incardona committed
extern size_t delete_data;

extern std::map<byte_ptr,ptr_info> active_ptr;
Pietro Incardona's avatar
Pietro Incardona committed

extern long int process_v_cl;
extern long int process_to_print;

/*! \brief Check and remove the active pointer
 *
 * Check and remove the pointer from the active list
 *
 * \param pointer to check and remove
 *
 * \return true if the operation succeded, false if the pointer does not exist
 *
 */
static bool remove_ptr(const void * ptr)
{
	// Check if the pointer exist
	std::map<byte_ptr, ptr_info>::iterator it = active_ptr.find((byte_ptr)ptr);
Pietro Incardona's avatar
Pietro Incardona committed

	// if the element does not exist, print that something wrong happened and return
	if ( it == active_ptr.end() )
	{
Pietro Incardona's avatar
Pietro Incardona committed
		std::cout << "Error " << __FILE__ << ":" << __LINE__ << " pointer not found " << ptr << "\n";
Pietro Incardona's avatar
Pietro Incardona committed
		ACTION_ON_ERROR(MEM_ERROR);
		return false;
	}

	// erase the pointer
	active_ptr.erase((byte_ptr)ptr);

	return true;
}

#define PRJ_DEVICES 0
#define PRJ_DATA 1
#define PRJ_VCLUSTER 2
#define PRJ_IO 3
#define PRJ_PDATA 4

/*! \brief Get the color for printing unalloc pointers
 *
 * \param project_id id of the project
 * \param size size of the allocation
 * \param col color
 *
 */
inline static void get_color(size_t project_id, size_t size, std::string & col)
{
	if (size == 8)
	{
		switch (project_id)
		{
		case PRJ_DEVICES:
			col = std::string("\e[97m");
			break;
		case PRJ_DATA:
			col = std::string("\e[95m");
			break;
		case PRJ_VCLUSTER:
			col = std::string("\e[96m");
			break;
		case PRJ_IO:
			col = std::string("\e[97m");
			break;
		case PRJ_PDATA:
			col = std::string("\e[93m");
			break;
		}
	}
	else
	{
		switch (project_id)
		{
		case PRJ_DEVICES:
			col = std::string("\e[7;92m");
			break;
		case PRJ_DATA:
			col = std::string("\e[7;95m");
			break;
		case PRJ_VCLUSTER:
			col = std::string("\e[7;96m");
			break;
		case PRJ_IO:
			col = std::string("\e[7;97m");
			break;
		case PRJ_PDATA:
			col = std::string("\e[7;93m");
			break;
		}
	}
}

/*! \brief Given the structure id it convert to a human readable structure string
 *
 * \param project_id id of the project
 * \param prj string that identify the project
 *
 */
inline static void get_structure(size_t struct_id, std::string & str)
{
	switch (struct_id)
	{
		case VCLUSTER_EVENT:
			str = std::string("Vcluster");
			break;
		case VECTOR_STD_EVENT:
			str = std::string("Vector_std");
			break;
		case VECTOR_EVENT:
			str = std::string("Vector_native");
			break;
		case GRID_EVENT:
			str = std::string("Grid");
			break;
		case VECTOR_DIST_EVENT:
			str = std::string("Vector distributed");
			break;
		case GRID_DIST_EVENT:
			str = std::string("Grid distributed");
			break;
		case HEAPMEMORY_EVENT:
			str = std::string("HeapMemory");
			break;
		case CUDAMEMORY_EVENT:
			str = std::string("CudaMemory");
			break;
		default:
			str = std::to_string(struct_id);
	}
}


/*! \brief Given the project id it convert to a human readable project string
 *
 * \param project_id id of the project
 * \param prj string that identify the project
 *
 */
inline static void get_project(size_t project_id, std::string & prj)
{
	switch (project_id)
	{
	case PRJ_DEVICES:
		prj = std::string("devices");
		break;
	case PRJ_DATA:
		prj = std::string("data");
		break;
	case PRJ_VCLUSTER:
		prj = std::string("vcluster");
		break;
	case PRJ_IO:
		prj = std::string("io");
		break;
	case PRJ_PDATA:
		prj = std::string("pdata");
		break;
	}
}

/*! \brief Print all active structures
Pietro Incardona's avatar
Pietro Incardona committed
 *
 * Print all active structures
static void print_alloc()
Pietro Incardona's avatar
Pietro Incardona committed
{
	std::string col;
	std::string sid;
	std::string prj;

	for (std::map<byte_ptr,ptr_info>::iterator it = active_ptr.begin(); it != active_ptr.end(); ++it)
Pietro Incardona's avatar
Pietro Incardona committed
	{
		get_color(it->second.project_id,it->second.size,col);
		get_structure(it->second.struct_id,sid);
		get_project(it->second.project_id,prj);

		std::cout << col << "Allocated memory " << (void *)it->first << "     size=" << it->second.size << "     id=" << it->second.id << "     structure id=" << std::hex <<  sid << std::dec << "    project id=" << prj << col_stop << "\n";
/* \brief When the allocation id==break_id is performed, print a message
 *
 * \param break_id
 *
 */
static void message_on_alloc(long int break_id)
{
	msg_on_alloc = break_id;
}

/* \brief When the allocation id==break_id is performed, throw
 *
 * \param throw_id
 *
 */
static void throw_on_alloc(long int throw_id)
{
	thr_on_alloc = throw_id;
}
Pietro Incardona's avatar
Pietro Incardona committed

/*! \brief Add the new allocated active pointer
 *
 * Add the new allocated active pointer
 *
 * \param new data active pointer
 * \param sz size of the new allocated memory
 *
 */
static bool check_new(const void * data, size_t sz, size_t struct_id, size_t project_id)
Pietro Incardona's avatar
Pietro Incardona committed
{
	// Add a new pointer
	new_data++;
	ptr_info & ptr = active_ptr[(byte_ptr)data];
	ptr.size = sz;
	ptr.id = new_data;
	ptr.struct_id = struct_id;
	ptr.project_id = project_id;
Pietro Incardona's avatar
Pietro Incardona committed

#ifdef SE_CLASS2_VERBOSE
	if (process_to_print < 0 || process_to_print == process_v_cl)
		std::cout << "New data: " << new_data << "   " << data << "\n";
#endif

	if  (msg_on_alloc == new_data)
		std::cout << "Detected allocation: " << __FILE__ << ":" << __LINE__ << " id=" << msg_on_alloc << "\n";

	if (thr_on_alloc == new_data)
		throw MEM_ERROR;

Pietro Incardona's avatar
Pietro Incardona committed
	return true;
}

/*! \brief check and delete a pointer
 *
 * check and delete a pointer from the list of active pointers
 *
 * \param pointer data
 * \return true if the operation to delete succeed
 *
 */
static bool check_delete(const void * data)
{
	if (data == NULL)	return true;
	// Delete the pointer
	delete_data++;
	bool result = remove_ptr(data);

#ifdef SE_CLASS2_VERBOSE
	if (process_to_print < 0 || process_to_print == process_v_cl)
		std::cout << "Delete data: " << delete_data << "   " << data << "\n";
#endif

	return result;
}

/*! \brief check if the access is valid
 *
 * check if the access is valid
 *
 * \param ptr pointer we are going to access
 * \param size_access is the size in byte of the data we are fetching
 *
 * \return true if the pointer is valid
 *
 */
static bool check_valid(const void * ptr, size_t size_access)
{
	if (active_ptr.size() == 0)
	{
		std::cerr << "Error invalid pointer: " << __FILE__ << ":" << __LINE__ << "  " << ptr << "\n";
Pietro Incardona's avatar
Pietro Incardona committed
		ACTION_ON_ERROR(MEM_ERROR);
		return false;
	}

	// get the upper bound

	std::map<byte_ptr, ptr_info>::iterator l_b = active_ptr.upper_bound((byte_ptr)ptr);

	// if there is no memory that satisfy the request
	if (l_b == active_ptr.begin())
	{
		if (process_to_print < 0 || process_to_print == process_v_cl)
		{
			std::cerr << "Error invalid pointer: " << __FILE__ << ":" << __LINE__ << "  " << ptr << "   base allocation id=" << l_b->second.id << "\n";
			ACTION_ON_ERROR(MEM_ERROR);
		}
		return false;
	}

Pietro Incardona's avatar
Pietro Incardona committed
	//! subtract one
	l_b--;

	// if there is no memory that satisfy the request
	if (l_b == active_ptr.end())
	{
		if (process_to_print < 0 || process_to_print == process_v_cl)
		{
			std::cerr << "Error invalid pointer: " << __FILE__ << ":" << __LINE__ << "  " << ptr << "   base allocation id=" << l_b->second.id  << "\n";
Pietro Incardona's avatar
Pietro Incardona committed
			ACTION_ON_ERROR(MEM_ERROR);
		}
		return false;
	}

	// check if ptr is in the range

	size_t sz = l_b->second.size;
Pietro Incardona's avatar
Pietro Incardona committed

	if (((unsigned char *)l_b->first) + sz < ((unsigned char *)ptr) + size_access)
	{
		if (process_to_print < 0 || process_to_print == process_v_cl)
		{
			std::cerr << "Error invalid pointer: " << __FILE__ << ":" << __LINE__ << "  "  << ptr << "   base allocation id=" << l_b->second.id << "\n";
Pietro Incardona's avatar
Pietro Incardona committed
			ACTION_ON_ERROR(MEM_ERROR);
		}
		return false;

/*! \brief check if the access is valid
 *
 * check if the access is valid
 *
 * \param ptr pointer we are going to access
 * \param size_access is the size in byte of the data we are fetching
 *
 * \return true if the pointer is valid
 *
 */
static long int check_whoami(const void * ptr, size_t size_access)
{
	if (active_ptr.size() == 0)
		return -1;

	// get the upper bound

	std::map<byte_ptr, ptr_info>::iterator l_b = active_ptr.upper_bound((byte_ptr)ptr);

	// if there is no memory that satisfy the request
	if (l_b == active_ptr.begin())
		return -1;

	//! subtract one
	l_b--;

	// if there is no memory that satisfy the request
	if (l_b == active_ptr.end())
		return -1;

	// check if ptr is in the range

	size_t sz = l_b->second.size;

	if (((unsigned char *)l_b->first) + sz < ((unsigned char *)ptr) + size_access)
		return -1;

	return l_b->second.id;
}

Pietro Incardona's avatar
Pietro Incardona committed
/*! \brief In case of Parallel application it set the process that print the
 *
 * \param p_to_print is < 0 (Mean all)
 *
 */
static void set_process_to_print(long int p_to_print)
{
	process_to_print = p_to_print;
}

#else



#endif
#endif