1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2015 Rockchip Electronics Co. LTD
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Licensed under the Apache License, Version 2.0 (the "License");
5*4882a593Smuzhiyun * you may not use this file except in compliance with the License.
6*4882a593Smuzhiyun * You may obtain a copy of the License at
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * http://www.apache.org/licenses/LICENSE-2.0
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Unless required by applicable law or agreed to in writing, software
11*4882a593Smuzhiyun * distributed under the License is distributed on an "AS IS" BASIS,
12*4882a593Smuzhiyun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4882a593Smuzhiyun * See the License for the specific language governing permissions and
14*4882a593Smuzhiyun * limitations under the License.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define MODULE_TAG "mpp_mem"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include "mpp_env.h"
22*4882a593Smuzhiyun #include "mpp_mem.h"
23*4882a593Smuzhiyun #include "mpp_list.h"
24*4882a593Smuzhiyun #include "mpp_debug.h"
25*4882a593Smuzhiyun #include "mpp_common.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "os_mem.h"
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun // mpp_mem_debug bit mask
30*4882a593Smuzhiyun #define MEM_DEBUG_EN (0x00000001)
31*4882a593Smuzhiyun // NOTE: runtime log need debug enable
32*4882a593Smuzhiyun #define MEM_RUNTIME_LOG (0x00000002)
33*4882a593Smuzhiyun #define MEM_NODE_LOG (0x00000004)
34*4882a593Smuzhiyun #define MEM_EXT_ROOM (0x00000010)
35*4882a593Smuzhiyun #define MEM_POISON (0x00000020)
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun // default memory align size is set to 32
38*4882a593Smuzhiyun #define MEM_MAX_INDEX (0x7fffffff)
39*4882a593Smuzhiyun #define MEM_ALIGN 32
40*4882a593Smuzhiyun #define MEM_ALIGN_MASK (MEM_ALIGN - 1)
41*4882a593Smuzhiyun #define MEM_ALIGNED(x) (((x) + MEM_ALIGN) & (~MEM_ALIGN_MASK))
42*4882a593Smuzhiyun #define MEM_HEAD_ROOM(debug) ((debug & MEM_EXT_ROOM) ? (MEM_ALIGN) : (0))
43*4882a593Smuzhiyun #define MEM_NODE_MAX (1024)
44*4882a593Smuzhiyun #define MEM_FREE_MAX (512)
45*4882a593Smuzhiyun #define MEM_LOG_MAX (1024)
46*4882a593Smuzhiyun #define MEM_CHECK_MARK (0xdd)
47*4882a593Smuzhiyun #define MEM_HEAD_MASK (0xab)
48*4882a593Smuzhiyun #define MEM_TAIL_MASK (0xcd)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define MPP_MEM_ASSERT(cond) \
51*4882a593Smuzhiyun do { \
52*4882a593Smuzhiyun if (!(cond)) { \
53*4882a593Smuzhiyun mpp_err("found mpp_mem assert failed, start dumping:\n"); \
54*4882a593Smuzhiyun service.dump(__FUNCTION__); \
55*4882a593Smuzhiyun mpp_assert(cond); \
56*4882a593Smuzhiyun } \
57*4882a593Smuzhiyun } while (0)
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun typedef enum MppMemOps_e {
60*4882a593Smuzhiyun MEM_MALLOC,
61*4882a593Smuzhiyun MEM_REALLOC,
62*4882a593Smuzhiyun MEM_FREE,
63*4882a593Smuzhiyun MEM_FREE_DELAY,
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun MEM_OPS_BUTT,
66*4882a593Smuzhiyun } MppMemOps;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /*
69*4882a593Smuzhiyun * Here we combined valid flag with index value to keep node structure small
70*4882a593Smuzhiyun * If index >= 0 this node is valid otherwise it is invalid
71*4882a593Smuzhiyun * When we need to invalid one index use ~ to revert all bit
72*4882a593Smuzhiyun * Then max valid index is 0x7fffffff. When index goes beyond it and becomes
73*4882a593Smuzhiyun * negative value index will be reset to zero.
74*4882a593Smuzhiyun */
75*4882a593Smuzhiyun typedef struct MppMemNode_s {
76*4882a593Smuzhiyun RK_S32 index;
77*4882a593Smuzhiyun size_t size;
78*4882a593Smuzhiyun void *ptr;
79*4882a593Smuzhiyun const char *caller;
80*4882a593Smuzhiyun } MppMemNode;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun typedef struct MppMemLog_s {
83*4882a593Smuzhiyun RK_U32 index;
84*4882a593Smuzhiyun MppMemOps ops;
85*4882a593Smuzhiyun size_t size_0; // size at input
86*4882a593Smuzhiyun size_t size_1; // size at output
87*4882a593Smuzhiyun void *ptr; // ptr at input
88*4882a593Smuzhiyun void *ret; // ptr at output
89*4882a593Smuzhiyun MppMemNode *node; // node for operation
90*4882a593Smuzhiyun const char *caller;
91*4882a593Smuzhiyun } MppMemLog;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun class MppMemService
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun public:
96*4882a593Smuzhiyun // avoid any unwanted function
97*4882a593Smuzhiyun MppMemService();
98*4882a593Smuzhiyun ~MppMemService();
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun void add_node(const char *caller, void *ptr, size_t size);
101*4882a593Smuzhiyun /*
102*4882a593Smuzhiyun * try delete node will return index in nodes
103*4882a593Smuzhiyun * return 1 for need os_free call to real free
104*4882a593Smuzhiyun * return 0 for reserve memory for check
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun RK_S32 find_node(const char *caller, void *ptr, size_t *size, RK_S32 *idx);
107*4882a593Smuzhiyun /*
108*4882a593Smuzhiyun */
109*4882a593Smuzhiyun void del_node(const char *caller, void *ptr, size_t *size);
110*4882a593Smuzhiyun void* delay_del_node(const char *caller, void *ptr, size_t *size);
111*4882a593Smuzhiyun void reset_node(const char *caller, void *ptr, void *ret, size_t size);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun void chk_node(const char *caller, MppMemNode *node);
114*4882a593Smuzhiyun void chk_mem(const char *caller, void *ptr, size_t size);
115*4882a593Smuzhiyun RK_S32 chk_poison(MppMemNode *node);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun void add_log(MppMemOps ops, const char *caller, void *ptr, void *ret,
118*4882a593Smuzhiyun size_t size_0, size_t size_1);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun void dump(const char *caller);
total_now(void)121*4882a593Smuzhiyun RK_U32 total_now(void) { return m_total_size; }
total_max(void)122*4882a593Smuzhiyun RK_U32 total_max(void) { return m_total_max; }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun Mutex lock;
125*4882a593Smuzhiyun RK_U32 debug;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun private:
128*4882a593Smuzhiyun // data for node record and delay free check
129*4882a593Smuzhiyun RK_S32 nodes_max;
130*4882a593Smuzhiyun RK_S32 nodes_idx;
131*4882a593Smuzhiyun RK_S32 nodes_cnt;
132*4882a593Smuzhiyun RK_S32 frees_max;
133*4882a593Smuzhiyun RK_S32 frees_idx;
134*4882a593Smuzhiyun RK_S32 frees_cnt;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun MppMemNode *nodes;
137*4882a593Smuzhiyun MppMemNode *frees;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun // data for log record
140*4882a593Smuzhiyun RK_U32 log_index;
141*4882a593Smuzhiyun RK_S32 log_max;
142*4882a593Smuzhiyun RK_S32 log_idx;
143*4882a593Smuzhiyun RK_S32 log_cnt;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun MppMemLog *logs;
146*4882a593Smuzhiyun RK_U32 m_total_size;
147*4882a593Smuzhiyun RK_U32 m_total_max;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun MppMemService(const MppMemService &);
150*4882a593Smuzhiyun MppMemService &operator=(const MppMemService &);
151*4882a593Smuzhiyun };
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun static MppMemService service;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun static const char *ops2str[MEM_OPS_BUTT] = {
156*4882a593Smuzhiyun "malloc",
157*4882a593Smuzhiyun "realloc",
158*4882a593Smuzhiyun "free",
159*4882a593Smuzhiyun "delayed",
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun
show_mem(RK_U32 * buf,RK_S32 size)162*4882a593Smuzhiyun static void show_mem(RK_U32 *buf, RK_S32 size)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun mpp_err("dumping buf %p size %d start\n", buf, size);
165*4882a593Smuzhiyun while (size > 0) {
166*4882a593Smuzhiyun if (size >= 16) {
167*4882a593Smuzhiyun mpp_err("%08x %08x %08x %08x\n", buf[0], buf[1], buf[2], buf[3]);
168*4882a593Smuzhiyun buf += 4;
169*4882a593Smuzhiyun size -= 16;
170*4882a593Smuzhiyun } else if (size >= 12) {
171*4882a593Smuzhiyun mpp_err("%08x %08x %08x\n", buf[0], buf[1], buf[2]);
172*4882a593Smuzhiyun buf += 3;
173*4882a593Smuzhiyun size -= 12;
174*4882a593Smuzhiyun } else if (size >= 8) {
175*4882a593Smuzhiyun mpp_err("%08x %08x\n", buf[0], buf[1]);
176*4882a593Smuzhiyun buf += 2;
177*4882a593Smuzhiyun size -= 8;
178*4882a593Smuzhiyun } else if (size >= 4) {
179*4882a593Smuzhiyun mpp_err("%08x\n", buf[0]);
180*4882a593Smuzhiyun buf += 1;
181*4882a593Smuzhiyun size -= 4;
182*4882a593Smuzhiyun } else {
183*4882a593Smuzhiyun mpp_log("end with size %d\n", size);
184*4882a593Smuzhiyun break;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun mpp_err("dumping buf %p size %d end\n", buf, size);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
set_mem_ext_room(void * p,size_t size)190*4882a593Smuzhiyun static void set_mem_ext_room(void *p, size_t size)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun memset((RK_U8 *)p - MEM_ALIGN, MEM_HEAD_MASK, MEM_ALIGN);
193*4882a593Smuzhiyun memset((RK_U8 *)p + size, MEM_TAIL_MASK, MEM_ALIGN);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
MppMemService()196*4882a593Smuzhiyun MppMemService::MppMemService()
197*4882a593Smuzhiyun : debug(0),
198*4882a593Smuzhiyun nodes_max(MEM_NODE_MAX),
199*4882a593Smuzhiyun nodes_idx(0),
200*4882a593Smuzhiyun nodes_cnt(0),
201*4882a593Smuzhiyun frees_max(MEM_FREE_MAX),
202*4882a593Smuzhiyun frees_idx(0),
203*4882a593Smuzhiyun frees_cnt(0),
204*4882a593Smuzhiyun nodes(NULL),
205*4882a593Smuzhiyun frees(NULL),
206*4882a593Smuzhiyun log_index(0),
207*4882a593Smuzhiyun log_max(MEM_LOG_MAX),
208*4882a593Smuzhiyun log_idx(0),
209*4882a593Smuzhiyun log_cnt(0),
210*4882a593Smuzhiyun logs(NULL),
211*4882a593Smuzhiyun m_total_size(0),
212*4882a593Smuzhiyun m_total_max(0)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun mpp_env_get_u32("mpp_mem_debug", &debug, 0);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun // add more flag if debug enabled
217*4882a593Smuzhiyun if (debug)
218*4882a593Smuzhiyun debug |= MEM_DEBUG_EN;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun if (debug & MEM_DEBUG_EN) {
221*4882a593Smuzhiyun mpp_env_get_u32("mpp_mem_node_max", (RK_U32 *)&nodes_max, MEM_NODE_MAX);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun mpp_log_f("mpp_mem_debug enabled %x max node %d\n",
224*4882a593Smuzhiyun debug, nodes_max);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun size_t size = nodes_max * sizeof(MppMemNode);
227*4882a593Smuzhiyun os_malloc((void **)&nodes, MEM_ALIGN, size);
228*4882a593Smuzhiyun mpp_assert(nodes);
229*4882a593Smuzhiyun memset(nodes, 0xff, size);
230*4882a593Smuzhiyun add_node(__FUNCTION__, nodes, size);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun size = frees_max * sizeof(MppMemNode);
233*4882a593Smuzhiyun os_malloc((void **)&frees, MEM_ALIGN, size);
234*4882a593Smuzhiyun mpp_assert(frees);
235*4882a593Smuzhiyun memset(frees, 0xff, size);
236*4882a593Smuzhiyun add_node(__FUNCTION__, frees, size);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun size = log_max * sizeof(MppMemLog);
239*4882a593Smuzhiyun os_malloc((void **)&logs, MEM_ALIGN, size);
240*4882a593Smuzhiyun mpp_assert(logs);
241*4882a593Smuzhiyun add_node(__FUNCTION__, logs, size);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun add_node(__FUNCTION__, this, sizeof(MppMemService));
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
~MppMemService()247*4882a593Smuzhiyun MppMemService::~MppMemService()
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun if (debug & MEM_DEBUG_EN) {
250*4882a593Smuzhiyun AutoMutex auto_lock(&lock);
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun RK_S32 i = 0;
253*4882a593Smuzhiyun MppMemNode *node = nodes;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun // delete self node first
256*4882a593Smuzhiyun size_t size = 0;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun del_node(__FUNCTION__, this, &size);
259*4882a593Smuzhiyun del_node(__FUNCTION__, nodes, &size);
260*4882a593Smuzhiyun del_node(__FUNCTION__, frees, &size);
261*4882a593Smuzhiyun del_node(__FUNCTION__, logs, &size);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun // then check leak memory
264*4882a593Smuzhiyun if (nodes_cnt) {
265*4882a593Smuzhiyun for (i = 0; i < nodes_max; i++, node++) {
266*4882a593Smuzhiyun if (node->index >= 0) {
267*4882a593Smuzhiyun mpp_log("found idx %8d mem %10p size %d leaked\n",
268*4882a593Smuzhiyun node->index, node->ptr, node->size);
269*4882a593Smuzhiyun nodes_cnt--;
270*4882a593Smuzhiyun add_log(MEM_FREE, __FUNCTION__, node->ptr, NULL,
271*4882a593Smuzhiyun node->size, 0);
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun mpp_assert(nodes_cnt == 0);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun // finally release all delay free memory
279*4882a593Smuzhiyun if (frees_cnt) {
280*4882a593Smuzhiyun node = frees;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun for (i = 0; i < frees_max; i++, node++) {
283*4882a593Smuzhiyun if (node->index >= 0) {
284*4882a593Smuzhiyun os_free((RK_U8 *)node->ptr - MEM_HEAD_ROOM(debug));
285*4882a593Smuzhiyun node->index = ~node->index;
286*4882a593Smuzhiyun frees_cnt--;
287*4882a593Smuzhiyun add_log(MEM_FREE_DELAY, __FUNCTION__, node->ptr, NULL,
288*4882a593Smuzhiyun node->size, 0);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun mpp_assert(frees_cnt == 0);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun os_free(nodes);
296*4882a593Smuzhiyun os_free(frees);
297*4882a593Smuzhiyun os_free(logs);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
add_node(const char * caller,void * ptr,size_t size)301*4882a593Smuzhiyun void MppMemService::add_node(const char *caller, void *ptr, size_t size)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun RK_S32 i = 0;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (debug & MEM_NODE_LOG)
306*4882a593Smuzhiyun mpp_log("mem cnt: %5d total %8d inc size %8d at %s\n",
307*4882a593Smuzhiyun nodes_cnt, m_total_size, size, caller);
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (nodes_cnt >= nodes_max) {
310*4882a593Smuzhiyun mpp_err("******************************************************\n");
311*4882a593Smuzhiyun mpp_err("* Reach max limit of mpp_mem counter %5d *\n", nodes_max);
312*4882a593Smuzhiyun mpp_err("* Increase limit by setup env mpp_mem_node_max or *\n");
313*4882a593Smuzhiyun mpp_err("* recompile mpp with larger macro MEM_NODE_MAX value *\n");
314*4882a593Smuzhiyun mpp_err("******************************************************\n");
315*4882a593Smuzhiyun mpp_abort();
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun MppMemNode *node = nodes;
319*4882a593Smuzhiyun for (i = 0; i < nodes_max; i++, node++) {
320*4882a593Smuzhiyun if (node->index < 0) {
321*4882a593Smuzhiyun node->index = nodes_idx++;
322*4882a593Smuzhiyun node->size = size;
323*4882a593Smuzhiyun node->ptr = ptr;
324*4882a593Smuzhiyun node->caller = caller;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun // NOTE: reset node index on revert
327*4882a593Smuzhiyun if (nodes_idx < 0)
328*4882a593Smuzhiyun nodes_idx = 0;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun nodes_cnt++;
331*4882a593Smuzhiyun m_total_size += size;
332*4882a593Smuzhiyun if (m_total_size > m_total_max)
333*4882a593Smuzhiyun m_total_max = m_total_size;
334*4882a593Smuzhiyun break;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
find_node(const char * caller,void * ptr,size_t * size,RK_S32 * idx)339*4882a593Smuzhiyun RK_S32 MppMemService::find_node(const char *caller, void *ptr, size_t *size, RK_S32 *idx)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun RK_S32 i = 0;
342*4882a593Smuzhiyun MppMemNode *node = nodes;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun MPP_MEM_ASSERT(nodes_cnt <= nodes_max);
345*4882a593Smuzhiyun for (i = 0; i < nodes_max; i++, node++) {
346*4882a593Smuzhiyun if (node->index >= 0 && node->ptr == ptr) {
347*4882a593Smuzhiyun *size = node->size;
348*4882a593Smuzhiyun *idx = i;
349*4882a593Smuzhiyun return 1;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun mpp_err("%s can NOT found node with ptr %p\n", caller, ptr);
354*4882a593Smuzhiyun mpp_abort();
355*4882a593Smuzhiyun return 0;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
del_node(const char * caller,void * ptr,size_t * size)358*4882a593Smuzhiyun void MppMemService::del_node(const char *caller, void *ptr, size_t *size)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun RK_S32 i = 0;
361*4882a593Smuzhiyun MppMemNode *node = nodes;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun MPP_MEM_ASSERT(nodes_cnt <= nodes_max);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun for (i = 0; i < nodes_max; i++, node++) {
366*4882a593Smuzhiyun if (node->index >= 0 && node->ptr == ptr) {
367*4882a593Smuzhiyun *size = node->size;
368*4882a593Smuzhiyun node->index = ~node->index;
369*4882a593Smuzhiyun nodes_cnt--;
370*4882a593Smuzhiyun m_total_size -= node->size;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (debug & MEM_NODE_LOG)
373*4882a593Smuzhiyun mpp_log("mem cnt: %5d total %8d dec size %8d at %s\n",
374*4882a593Smuzhiyun nodes_cnt, m_total_size, node->size, caller);
375*4882a593Smuzhiyun return ;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun mpp_err("%s fail to find node with ptr %p\n", caller, ptr);
380*4882a593Smuzhiyun mpp_abort();
381*4882a593Smuzhiyun return ;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
delay_del_node(const char * caller,void * ptr,size_t * size)384*4882a593Smuzhiyun void *MppMemService::delay_del_node(const char *caller, void *ptr, size_t *size)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun RK_S32 i = 0;
387*4882a593Smuzhiyun MppMemNode *node = nodes;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun // clear output first
390*4882a593Smuzhiyun void *ret = NULL;
391*4882a593Smuzhiyun *size = 0;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun // find the node to save
394*4882a593Smuzhiyun MPP_MEM_ASSERT(nodes_cnt <= nodes_max);
395*4882a593Smuzhiyun for (i = 0; i < nodes_max; i++, node++) {
396*4882a593Smuzhiyun if (node->index >= 0 && node->ptr == ptr) {
397*4882a593Smuzhiyun chk_node(caller, node);
398*4882a593Smuzhiyun break;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun MPP_MEM_ASSERT(i < nodes_max);
403*4882a593Smuzhiyun if (debug & MEM_NODE_LOG)
404*4882a593Smuzhiyun mpp_log("mem cnt: %5d total %8d dec size %8d at %s\n",
405*4882a593Smuzhiyun nodes_cnt, m_total_size, node->size, caller);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun MppMemNode *free_node = NULL;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun MPP_MEM_ASSERT(frees_cnt <= frees_max);
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (frees_cnt) {
412*4882a593Smuzhiyun MppMemNode *tmp = frees;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun // NODE: check all data here
415*4882a593Smuzhiyun for (i = 0; i < frees_max; i++, tmp++) {
416*4882a593Smuzhiyun if (tmp->index >= 0) {
417*4882a593Smuzhiyun chk_node(caller, tmp);
418*4882a593Smuzhiyun chk_poison(tmp);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun if (frees_cnt >= frees_max) {
424*4882a593Smuzhiyun // free list full start del
425*4882a593Smuzhiyun RK_S32 frees_last = frees_idx - frees_cnt;
426*4882a593Smuzhiyun if (frees_last < 0)
427*4882a593Smuzhiyun frees_last += frees_max;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun free_node = &frees[frees_last];
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (free_node->index >= 0) {
432*4882a593Smuzhiyun chk_node(caller, free_node);
433*4882a593Smuzhiyun chk_poison(free_node);
434*4882a593Smuzhiyun ret = free_node->ptr;
435*4882a593Smuzhiyun *size = free_node->size;
436*4882a593Smuzhiyun free_node->index = ~free_node->index;
437*4882a593Smuzhiyun frees_cnt--;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun MPP_MEM_ASSERT(frees_cnt <= frees_max);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun // free list is NOT full just store
444*4882a593Smuzhiyun free_node = &frees[frees_idx];
445*4882a593Smuzhiyun frees_idx++;
446*4882a593Smuzhiyun if (frees_idx >= frees_max)
447*4882a593Smuzhiyun frees_idx = 0;
448*4882a593Smuzhiyun if (frees_cnt < frees_max)
449*4882a593Smuzhiyun frees_cnt++;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun MPP_MEM_ASSERT(frees_cnt <= frees_max);
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun memcpy(&frees[frees_idx], node, sizeof(*node));
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun if ((debug & MEM_POISON) && (node->size < 1024))
456*4882a593Smuzhiyun memset(node->ptr, MEM_CHECK_MARK, node->size);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun node->index = ~node->index;
459*4882a593Smuzhiyun m_total_size -= node->size;
460*4882a593Smuzhiyun nodes_cnt--;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun return ret;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
chk_node(const char * caller,MppMemNode * node)465*4882a593Smuzhiyun void MppMemService::chk_node(const char *caller, MppMemNode *node)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun if ((debug & MEM_EXT_ROOM) == 0)
468*4882a593Smuzhiyun return ;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun chk_mem(caller, node->ptr, node->size);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
chk_mem(const char * caller,void * ptr,size_t size)473*4882a593Smuzhiyun void MppMemService::chk_mem(const char *caller, void *ptr, size_t size)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun if ((debug & MEM_EXT_ROOM) == 0)
476*4882a593Smuzhiyun return ;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun RK_S32 i = 0;
479*4882a593Smuzhiyun RK_U8 *p = (RK_U8 *)ptr - MEM_ALIGN;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun for (i = 0; i < MEM_ALIGN; i++) {
482*4882a593Smuzhiyun if (p[i] != MEM_HEAD_MASK) {
483*4882a593Smuzhiyun mpp_err("%s checking ptr %p head room found error!\n", caller, ptr);
484*4882a593Smuzhiyun dump(caller);
485*4882a593Smuzhiyun show_mem((RK_U32 *)p, MEM_ALIGN);
486*4882a593Smuzhiyun mpp_abort();
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun p = (RK_U8 *)ptr + size;
491*4882a593Smuzhiyun for (i = 0; i < MEM_ALIGN; i++) {
492*4882a593Smuzhiyun if (p[i] != MEM_TAIL_MASK) {
493*4882a593Smuzhiyun mpp_err("%s checking ptr %p tail room found error!\n", caller, ptr);
494*4882a593Smuzhiyun dump(caller);
495*4882a593Smuzhiyun show_mem((RK_U32 *)p, MEM_ALIGN);
496*4882a593Smuzhiyun mpp_abort();
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun
chk_poison(MppMemNode * node)501*4882a593Smuzhiyun RK_S32 MppMemService::chk_poison(MppMemNode *node)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun if ((debug & MEM_POISON) == 0)
504*4882a593Smuzhiyun return 0;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun // check oldest memory and free it
507*4882a593Smuzhiyun RK_U8 *node_ptr = (RK_U8 *)node->ptr;
508*4882a593Smuzhiyun RK_S32 size = node->size;
509*4882a593Smuzhiyun RK_S32 i = 0;
510*4882a593Smuzhiyun RK_S32 start = -1;
511*4882a593Smuzhiyun RK_S32 end = -1;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun if (size >= 1024)
514*4882a593Smuzhiyun return 0;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun for (; i < size; i++) {
517*4882a593Smuzhiyun if (node_ptr[i] != MEM_CHECK_MARK) {
518*4882a593Smuzhiyun if (start < 0) {
519*4882a593Smuzhiyun start = i;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun end = i + 1;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if (start >= 0 || end >= 0) {
526*4882a593Smuzhiyun mpp_err_f("found memory %p size %d caller %s overwrite from %d to %d\n",
527*4882a593Smuzhiyun node_ptr, size, node->caller, start, end);
528*4882a593Smuzhiyun dump(node->caller);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun return end - start;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
reset_node(const char * caller,void * ptr,void * ret,size_t size)534*4882a593Smuzhiyun void MppMemService::reset_node(const char *caller, void *ptr, void *ret, size_t size)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun RK_S32 i = 0;
537*4882a593Smuzhiyun MppMemNode *node = nodes;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun if (debug & MEM_NODE_LOG)
540*4882a593Smuzhiyun mpp_log("mem cnt: %5d total %8d equ size %8d at %s\n",
541*4882a593Smuzhiyun nodes_cnt, m_total_size, size, __FUNCTION__);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun MPP_MEM_ASSERT(nodes_cnt <= nodes_max);
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun for (i = 0; i < nodes_max; i++, node++) {
546*4882a593Smuzhiyun if (node->index >= 0 && node->ptr == ptr) {
547*4882a593Smuzhiyun m_total_size += size;
548*4882a593Smuzhiyun m_total_size -= node->size;
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun node->ptr = ret;
551*4882a593Smuzhiyun node->size = size;
552*4882a593Smuzhiyun node->caller = caller;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun if (debug & MEM_EXT_ROOM)
555*4882a593Smuzhiyun set_mem_ext_room(ret, size);
556*4882a593Smuzhiyun break;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
add_log(MppMemOps ops,const char * caller,void * ptr,void * ret,size_t size_0,size_t size_1)561*4882a593Smuzhiyun void MppMemService::add_log(MppMemOps ops, const char *caller,
562*4882a593Smuzhiyun void *ptr, void *ret, size_t size_0, size_t size_1)
563*4882a593Smuzhiyun {
564*4882a593Smuzhiyun MppMemLog *log = &logs[log_idx];
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun if (service.debug & MEM_RUNTIME_LOG)
567*4882a593Smuzhiyun mpp_log("%-7s ptr %010p %010p size %8u %8u at %s\n",
568*4882a593Smuzhiyun ops2str[ops], ptr, ret, size_0, size_1, caller);
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun log->index = log_index++;
571*4882a593Smuzhiyun log->ops = ops;
572*4882a593Smuzhiyun log->size_0 = size_0;
573*4882a593Smuzhiyun log->size_1 = size_1;
574*4882a593Smuzhiyun log->ptr = ptr;
575*4882a593Smuzhiyun log->ret = ret;
576*4882a593Smuzhiyun log->node = NULL;
577*4882a593Smuzhiyun log->caller = caller;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun log_idx++;
580*4882a593Smuzhiyun if (log_idx >= log_max)
581*4882a593Smuzhiyun log_idx = 0;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun if (log_cnt < log_max)
584*4882a593Smuzhiyun log_cnt++;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
dump(const char * caller)587*4882a593Smuzhiyun void MppMemService::dump(const char *caller)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun RK_S32 i;
590*4882a593Smuzhiyun MppMemNode *node = nodes;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun mpp_log("mpp_mem enter status dumping from %s:\n", caller);
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun mpp_log("mpp_mem node count %d:\n", nodes_cnt);
595*4882a593Smuzhiyun if (nodes_cnt) {
596*4882a593Smuzhiyun for (i = 0; i < nodes_max; i++, node++) {
597*4882a593Smuzhiyun if (node->index < 0)
598*4882a593Smuzhiyun continue;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun mpp_log("mpp_memory index %d caller %-32s size %-8u ptr %p\n",
601*4882a593Smuzhiyun node->index, node->caller, node->size, node->ptr);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun node = frees;
606*4882a593Smuzhiyun mpp_log("mpp_mem free count %d:\n", frees_cnt);
607*4882a593Smuzhiyun if (frees_cnt) {
608*4882a593Smuzhiyun for (i = 0; i < frees_max; i++, node++) {
609*4882a593Smuzhiyun if (node->index < 0)
610*4882a593Smuzhiyun continue;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun mpp_log("mpp_freed index %d caller %-32s size %-8u ptr %p\n",
613*4882a593Smuzhiyun node->index, node->caller, node->size, node->ptr);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun RK_S32 start = log_idx - log_cnt;
618*4882a593Smuzhiyun RK_S32 tmp_cnt = log_cnt;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun if (start < 0)
621*4882a593Smuzhiyun start += log_max;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun mpp_log("mpp_mem enter log dumping:\n");
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun while (tmp_cnt) {
626*4882a593Smuzhiyun MppMemLog *log = &logs[start];
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun mpp_log("idx %-8d op: %-7s from %-32s ptr %10p %10p size %7d %7d\n",
629*4882a593Smuzhiyun log->index, ops2str[log->ops], log->caller,
630*4882a593Smuzhiyun log->ptr, log->ret, log->size_0, log->size_1);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun start++;
633*4882a593Smuzhiyun if (start >= log_max)
634*4882a593Smuzhiyun start = 0;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun tmp_cnt--;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun
mpp_osal_malloc(const char * caller,size_t size)640*4882a593Smuzhiyun void *mpp_osal_malloc(const char *caller, size_t size)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun RK_U32 debug = service.debug;
643*4882a593Smuzhiyun size_t size_align = MEM_ALIGNED(size);
644*4882a593Smuzhiyun size_t size_real = (debug & MEM_EXT_ROOM) ? (size_align + 2 * MEM_ALIGN) :
645*4882a593Smuzhiyun (size_align);
646*4882a593Smuzhiyun void *ptr;
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun os_malloc(&ptr, MEM_ALIGN, size_real);
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun if (debug) {
651*4882a593Smuzhiyun AutoMutex auto_lock(&service.lock);
652*4882a593Smuzhiyun service.add_log(MEM_MALLOC, caller, NULL, ptr, size, size_real);
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun if (ptr) {
655*4882a593Smuzhiyun if (debug & MEM_EXT_ROOM) {
656*4882a593Smuzhiyun ptr = (RK_U8 *)ptr + MEM_ALIGN;
657*4882a593Smuzhiyun set_mem_ext_room(ptr, size);
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun service.add_node(caller, ptr, size);
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun return ptr;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
mpp_osal_calloc(const char * caller,size_t size)667*4882a593Smuzhiyun void *mpp_osal_calloc(const char *caller, size_t size)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun void *ptr = mpp_osal_malloc(caller, size);
670*4882a593Smuzhiyun if (ptr)
671*4882a593Smuzhiyun memset(ptr, 0, size);
672*4882a593Smuzhiyun return ptr;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
mpp_osal_realloc(const char * caller,void * ptr,size_t size)675*4882a593Smuzhiyun void *mpp_osal_realloc(const char *caller, void *ptr, size_t size)
676*4882a593Smuzhiyun {
677*4882a593Smuzhiyun RK_U32 debug = service.debug;
678*4882a593Smuzhiyun void *ret;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun if (NULL == ptr)
681*4882a593Smuzhiyun return mpp_osal_malloc(caller, size);
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun if (0 == size) {
684*4882a593Smuzhiyun mpp_err("warning: realloc %p to zero size\n", ptr);
685*4882a593Smuzhiyun return NULL;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun size_t size_align = MEM_ALIGNED(size);
689*4882a593Smuzhiyun size_t size_real = (debug & MEM_EXT_ROOM) ? (size_align + 2 * MEM_ALIGN) :
690*4882a593Smuzhiyun (size_align);
691*4882a593Smuzhiyun void *ptr_real = (RK_U8 *)ptr - MEM_HEAD_ROOM(debug);
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun os_realloc(ptr_real, &ret, MEM_ALIGN, size_align);
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun if (NULL == ret) {
696*4882a593Smuzhiyun // if realloc fail the original buffer will be kept the same.
697*4882a593Smuzhiyun mpp_err("mpp_realloc ptr %p to size %d failed\n", ptr, size);
698*4882a593Smuzhiyun } else {
699*4882a593Smuzhiyun AutoMutex auto_lock(&service.lock);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun // if realloc success reset the node and record
702*4882a593Smuzhiyun if (debug) {
703*4882a593Smuzhiyun void *ret_ptr = (debug & MEM_EXT_ROOM) ?
704*4882a593Smuzhiyun ((RK_U8 *)ret + MEM_ALIGN) : (ret);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun service.reset_node(caller, ptr, ret_ptr, size);
707*4882a593Smuzhiyun service.add_log(MEM_REALLOC, caller, ptr, ret_ptr, size, size_real);
708*4882a593Smuzhiyun ret = ret_ptr;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun return ret;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
mpp_osal_free(const char * caller,void * ptr)715*4882a593Smuzhiyun void mpp_osal_free(const char *caller, void *ptr)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun RK_U32 debug = service.debug;
718*4882a593Smuzhiyun if (NULL == ptr)
719*4882a593Smuzhiyun return;
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun if (!debug) {
722*4882a593Smuzhiyun os_free(ptr);
723*4882a593Smuzhiyun return ;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun size_t size = 0;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun AutoMutex auto_lock(&service.lock);
729*4882a593Smuzhiyun if (debug & MEM_POISON) {
730*4882a593Smuzhiyun // NODE: keep this node and delete delay node
731*4882a593Smuzhiyun void *ret = service.delay_del_node(caller, ptr, &size);
732*4882a593Smuzhiyun if (ret)
733*4882a593Smuzhiyun os_free((RK_U8 *)ret - MEM_ALIGN);
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun service.add_log(MEM_FREE_DELAY, caller, ptr, ret, size, 0);
736*4882a593Smuzhiyun } else {
737*4882a593Smuzhiyun void *ptr_real = (RK_U8 *)ptr - MEM_HEAD_ROOM(debug);
738*4882a593Smuzhiyun // NODE: delete node and return size here
739*4882a593Smuzhiyun service.del_node(caller, ptr, &size);
740*4882a593Smuzhiyun service.chk_mem(caller, ptr, size);
741*4882a593Smuzhiyun os_free(ptr_real);
742*4882a593Smuzhiyun service.add_log(MEM_FREE, caller, ptr, ptr_real, size, 0);
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun /* dump memory status */
mpp_show_mem_status()747*4882a593Smuzhiyun void mpp_show_mem_status()
748*4882a593Smuzhiyun {
749*4882a593Smuzhiyun AutoMutex auto_lock(&service.lock);
750*4882a593Smuzhiyun if (service.debug & MEM_DEBUG_EN)
751*4882a593Smuzhiyun service.dump(__FUNCTION__);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
mpp_mem_total_now()754*4882a593Smuzhiyun RK_U32 mpp_mem_total_now()
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun AutoMutex auto_lock(&service.lock);
757*4882a593Smuzhiyun return service.total_now();
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
mpp_mem_total_max()760*4882a593Smuzhiyun RK_U32 mpp_mem_total_max()
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun AutoMutex auto_lock(&service.lock);
763*4882a593Smuzhiyun return service.total_max();
764*4882a593Smuzhiyun }
765