1 /*--------------------------------------------------------------------
2  *
3  *	Copyright (c) 1991-2021 by the GMT Team (https://www.generic-mapping-tools.org/team.html)
4  *	See LICENSE.TXT file for copying and redistribution conditions.
5  *
6  *	This program is free software; you can redistribute it and/or modify
7  *	it under the terms of the GNU Lesser General Public License as published by
8  *	the Free Software Foundation; version 3 or any later version.
9  *
10  *	This program is distributed in the hope that it will be useful,
11  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *	GNU Lesser General Public License for more details.
14  *
15  *	Contact info: www.generic-mapping-tools.org
16  *--------------------------------------------------------------------*/
17 
18 /*!
19  * \file gmt_M_memory.h
20  * \brief
21  */
22 
23 #ifndef GMT_MEMORY_H
24 #define GMT_MEMORY_H
25 
26 enum GMT_enum_mem_alloc {	/* Initial memory for 2 double columns is 32 Mb */
27 	GMT_INITIAL_MEM_COL_ALLOC	= 2U,
28 	GMT_INITIAL_MEM_ROW_ALLOC	= 2097152U	/* 2^21 */
29 };
30 
31 /*! Macros to reallocate memory for groups of 2, 3 or 4 arrays at a time of the same size/type */
32 #if defined (DEBUG) || defined (MEMDEBUG)
33 #define gmt_M_malloc(C,a,n,n_alloc,type) gmt_malloc_func(C,a,n,n_alloc,sizeof(type),__SOURCE_LINE_FUNC)
34 #else
35 #define gmt_M_malloc(C,a,n,n_alloc,type) gmt_malloc_func(C,a,n,n_alloc,sizeof(type),__func__)
36 #endif
37 /* The __kp = n_alloc below is needed since NULL may be passed. __k is used to ensure only the final gmt_M_malloc call changes n_alloc (unless it is NULL) */
38 #define gmt_M_malloc2(C,a,b,n,n_alloc,type) { size_t __k, *__kp = n_alloc; __k = (__kp) ? *__kp : 0U; a = gmt_M_malloc(C,a,n,&__k,type); b = gmt_M_malloc(C,b,n,n_alloc,type); }
39 #define gmt_M_malloc3(C,a,b,c,n,n_alloc,type) { size_t __k, *__kp = n_alloc; __k = (__kp) ? *__kp : 0U; a = gmt_M_malloc(C,a,n,&__k,type); __k = (__kp) ? *__kp : 0U; b = gmt_M_malloc(C,b,n,&__k,type); c = gmt_M_malloc(C,c,n,n_alloc,type); }
40 #define gmt_M_malloc4(C,a,b,c,d,n,n_alloc,type) { size_t __k, *__kp = n_alloc; __k = (__kp) ? *__kp : 0U; a = gmt_M_malloc(C,a,n,&__k,type); __k = (__kp) ? *__kp : 0U; b = gmt_M_malloc(C,b,n,&__k,type); __k = (__kp) ? *__kp : 0U; c = gmt_M_malloc(C,c,n,&__k,type); d = gmt_M_malloc(C,d,n,n_alloc,type); }
41 
42 /*! Convenience macro for gmt_memory_func */
43 #if defined (DEBUG) || defined (MEMDEBUG)
44 #define gmt_M_memory(C,ptr,n,type) gmt_memory_func(C,ptr,n,sizeof(type),false,__SOURCE_LINE_FUNC)
45 #define gmt_M_memory_aligned(C,ptr,n,type) gmt_memory_func(C,ptr,n,sizeof(type),true,__SOURCE_LINE_FUNC)
46 #else
47 #define gmt_M_memory(C,ptr,n,type) gmt_memory_func(C,ptr,n,sizeof(type),false,__func__)
48 #define gmt_M_memory_aligned(C,ptr,n,type) gmt_memory_func(C,ptr,n,sizeof(type),true,__func__)
49 #endif
50 
51 /*! Convenience macro for gmt_free_func */
52 #if defined (DEBUG) || defined (MEMDEBUG)
53 #define gmt_M_free(C,ptr) (gmt_free_func(C,ptr,false,__SOURCE_LINE_FUNC),(ptr)=NULL)
54 #define gmt_M_free_aligned(C,ptr) (gmt_free_func(C,ptr,true,__SOURCE_LINE_FUNC),(ptr)=NULL)
55 #else
56 #define gmt_M_free(C,ptr) (gmt_free_func(C,ptr,false,__func__),(ptr)=NULL)
57 #define gmt_M_free_aligned(C,ptr) (gmt_free_func(C,ptr,true,__func__),(ptr)=NULL)
58 #endif
59 
60 /*! Convenience macro for free that explicitly sets freed pointer to NULL */
61 #define gmt_M_str_free(ptr) (free((void *)(ptr)),(ptr)=NULL)
62 
63 #ifdef MEMDEBUG
64 
65 struct MEMORY_ITEM {
66 	size_t size;	/* Size of memory allocated */
67 	void *ptr;	/* Memory pointer */
68 	char *name;	/* Source filename and line or function name */
69 	size_t ID;	/* Unique ID for this allocation */
70 	struct MEMORY_ITEM *l, *r;
71 };
72 
73 struct MEMORY_TRACKER {
74 #ifdef MEMDEBUG
75 	bool active;	/* Normally true but can be changed to focus on just some allocations */
76 	bool search;	/* Normally true but can be changed to skip searching when we know we add a new item */
77 	bool do_log;	/* true if we wish to write detailed alloc/free log */
78 	uint64_t n_ptr;		/* Number of unique pointers to allocated memory */
79 	uint64_t n_allocated;	/* Number of items allocated by gmt_M_memory */
80 	uint64_t n_reallocated;	/* Number of items reallocated by gmt_M_memory */
81 	uint64_t n_freed;	/* Number of items freed by gmt_M_free */
82 	uint64_t n_ID;		/* Running number assigned to new allocations */
83 	uint64_t find;		/* If > 0 then we look for this ID to be allocated */
84 	size_t current;		/* Memory allocated at current time */
85 	size_t maximum;		/* Highest memory count during execution */
86 	size_t largest;		/* Highest memory allocation to a single variable */
87 	size_t n_alloc;		/* Allocated size of memory pointer array */
88 	struct MEMORY_ITEM *root; /* Pointer to splay tree */
89 	FILE *fp;	/* For logging if GMT_TRACK_MEMORY is 2 */
90 #endif
91 };
92 
93 /* Items needed if -DMEMDEBUG is in effect */
94 EXTERN_MSC int gmt_memtrack_init (struct GMT_CTRL *GMT);
95 EXTERN_MSC void gmt_memtrack_report (struct GMT_CTRL *GMT);
96 
97 #endif
98 
99 #endif /* GMT_MEMORY_H */
100