OSAL_Memory.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. /**************************************************************************************************
  2. Filename: OSAL_Memory.c
  3. Revised: $Date: 2009-02-05 16:41:18 -0800 (Thu, 05 Feb 2009) $
  4. Revision: $Revision: 18998 $
  5. Description: OSAL Heap Memory management functions.
  6. Copyright 2004-2007 Texas Instruments Incorporated. All rights reserved.
  7. IMPORTANT: Your use of this Software is limited to those specific rights
  8. granted under the terms of a software license agreement between the user
  9. who downloaded the software, his/her employer (which must be your employer)
  10. and Texas Instruments Incorporated (the "License"). You may not use this
  11. Software unless you agree to abide by the terms of the License. The License
  12. limits your use, and you acknowledge, that the Software may not be modified,
  13. copied or distributed unless embedded on a Texas Instruments microcontroller
  14. or used solely and exclusively in conjunction with a Texas Instruments radio
  15. frequency transceiver, which is integrated into your product. Other than for
  16. the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  17. works of, modify, distribute, perform, display or sell this Software and/or
  18. its documentation for any purpose.
  19. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  20. PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  21. INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  22. NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  23. TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  24. NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  25. LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  26. INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  27. OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  28. OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  29. (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
  30. Should you have any questions regarding your right to use this Software,
  31. contact Texas Instruments Incorporated at www.TI.com.
  32. **************************************************************************************************/
  33. /*********************************************************************
  34. * INCLUDES
  35. */
  36. #include "comdef.h"
  37. #include "OSAL_Memory.h"
  38. #include "OnBoard.h"
  39. #include "hal_assert.h"
  40. #if ( MAXMEMHEAP >= 32768 )
  41. #error MAXMEMHEAP is too big to manage!
  42. #endif
  43. // Minimum wasted bytes to justify splitting a block before allocation.
  44. #if !defined ( OSALMEM_MIN_BLKSZ )
  45. #define OSALMEM_MIN_BLKSZ 4
  46. #endif
  47. /* Profiling memory allocations showed that a significant % of very high
  48. * frequency allocations/frees are for block sizes less than or equal to 16.
  49. */
  50. #if !defined ( OSALMEM_SMALL_BLKSZ )
  51. #define OSALMEM_SMALL_BLKSZ 16
  52. #endif
  53. #if !defined ( OSALMEM_NODEBUG )
  54. #define OSALMEM_NODEBUG TRUE
  55. #endif
  56. #if !defined ( OSALMEM_PROFILER )
  57. #define OSALMEM_PROFILER FALSE
  58. #endif
  59. #if ( OSALMEM_PROFILER )
  60. #define OSALMEM_INIT 'X'
  61. #define OSALMEM_ALOC 'A'
  62. #define OSALMEM_REIN 'F'
  63. #endif
  64. /*********************************************************************
  65. * MACROS
  66. */
  67. /*
  68. * The MAC_ASSERT macro is for use during debugging.
  69. * The given expression must evaluate as "true" or else fatal error occurs.
  70. * At that point, the call stack feature of the debugger can pinpoint where
  71. * the problem occurred.
  72. *
  73. * To disable this feature and save code size, the project should define
  74. * OSALMEM_NODEBUG to TRUE.
  75. */
  76. #if ( OSALMEM_NODEBUG )
  77. #define OSALMEM_ASSERT( expr )
  78. #define OSALMEM_DEBUG( statement )
  79. #else
  80. #define OSALMEM_ASSERT( expr) HAL_ASSERT( expr )
  81. #define OSALMEM_DEBUG( statement) st( statement )
  82. #endif
  83. /*********************************************************************
  84. * TYPEDEFS
  85. */
  86. typedef uint16 osalMemHdr_t;
  87. /*********************************************************************
  88. * CONSTANTS
  89. */
  90. #define OSALMEM_IN_USE 0x8000
  91. /* This number sets the size of the small-block bucket. Although profiling
  92. * shows max simultaneous alloc of 16x18, timing without profiling overhead
  93. * shows that the best worst case is achieved with the following.
  94. */
  95. #define SMALLBLKHEAP 232
  96. // To maintain data alignment of the pointer returned, reserve the greater
  97. // space for the memory block header.
  98. #define HDRSZ ( (sizeof ( halDataAlign_t ) > sizeof( osalMemHdr_t )) ? \
  99. sizeof ( halDataAlign_t ) : sizeof( osalMemHdr_t ) )
  100. /*********************************************************************
  101. * GLOBAL VARIABLES
  102. */
  103. /*********************************************************************
  104. * EXTERNAL VARIABLES
  105. */
  106. /*********************************************************************
  107. * EXTERNAL FUNCTIONS
  108. */
  109. /*********************************************************************
  110. * LOCAL VARIABLES
  111. */
  112. static osalMemHdr_t *ff1; // First free block in the small-block bucket.
  113. static osalMemHdr_t *ff2; // First free block after the small-block bucket.
  114. #if ( OSALMEM_METRICS )
  115. static uint16 blkMax; // Max cnt of all blocks ever seen at once.
  116. static uint16 blkCnt; // Current cnt of all blocks.
  117. static uint16 blkFree; // Current cnt of free blocks.
  118. static uint16 memAlo; // Current total memory allocated.
  119. static uint16 memMax; // Max total memory ever allocated at once.
  120. #endif
  121. #if ( OSALMEM_PROFILER )
  122. #define OSALMEM_PROMAX 8
  123. /* The profiling buckets must differ by at least OSALMEM_MIN_BLKSZ; the
  124. * last bucket must equal the max alloc size. Set the bucket sizes to
  125. * whatever sizes necessary to show how your application is using memory.
  126. */
  127. static uint16 proCnt[OSALMEM_PROMAX] = {
  128. OSALMEM_SMALL_BLKSZ, 48, 112, 176, 192, 224, 256, 65535 };
  129. static uint16 proCur[OSALMEM_PROMAX] = { 0 };
  130. static uint16 proMax[OSALMEM_PROMAX] = { 0 };
  131. static uint16 proTot[OSALMEM_PROMAX] = { 0 };
  132. static uint16 proSmallBlkMiss;
  133. #endif
  134. // Memory Allocation Heap.
  135. #if defined( EXTERNAL_RAM )
  136. static byte *theHeap = (byte *)EXT_RAM_BEG;
  137. #else
  138. static halDataAlign_t _theHeap[ MAXMEMHEAP / sizeof( halDataAlign_t ) ];
  139. static uint8 *theHeap = (uint8 *)_theHeap;
  140. #endif
  141. /*********************************************************************
  142. * LOCAL FUNCTIONS
  143. */
  144. /*********************************************************************
  145. * @fn osal_mem_init
  146. *
  147. * @brief Initialize the heap memory management system.
  148. *
  149. * @param void
  150. *
  151. * @return void
  152. */
  153. void osal_mem_init( void )
  154. {
  155. osalMemHdr_t *tmp;
  156. #if ( OSALMEM_PROFILER )
  157. osal_memset( theHeap, OSALMEM_INIT, MAXMEMHEAP );
  158. #endif
  159. // Setup a NULL block at the end of the heap for fast comparisons with zero.
  160. tmp = (osalMemHdr_t *)theHeap + (MAXMEMHEAP / HDRSZ) - 1;
  161. *tmp = 0;
  162. // Setup a small-block bucket.
  163. tmp = (osalMemHdr_t *)theHeap;
  164. *tmp = SMALLBLKHEAP;
  165. // Setup the wilderness.
  166. tmp = (osalMemHdr_t *)theHeap + (SMALLBLKHEAP / HDRSZ);
  167. *tmp = ((MAXMEMHEAP / HDRSZ) * HDRSZ) - SMALLBLKHEAP - HDRSZ;
  168. // Setup a NULL block that is never freed so that the small-block bucket
  169. // is never coalesced with the wilderness.
  170. ff1 = tmp;
  171. ff2 = osal_mem_alloc( 0 );
  172. ff1 = (osalMemHdr_t *)theHeap;
  173. #if ( OSALMEM_METRICS )
  174. /* Start with the small-block bucket and the wilderness - don't count the
  175. * end-of-heap NULL block nor the end-of-small-block NULL block.
  176. */
  177. blkCnt = blkFree = 2;
  178. #endif
  179. }
  180. /*********************************************************************
  181. * @fn osal_mem_kick
  182. *
  183. * @brief Kick the ff1 pointer out past the long-lived OSAL Task blocks.
  184. * Invoke this once after all long-lived blocks have been allocated -
  185. * presently at the end of osal_init_system().
  186. *
  187. * @param void
  188. *
  189. * @return void
  190. */
  191. void osal_mem_kick( void )
  192. {
  193. halIntState_t intState;
  194. HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
  195. /* Logic in osal_mem_free() will ratchet ff1 back down to the first free
  196. * block in the small-block bucket.
  197. */
  198. ff1 = ff2;
  199. HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
  200. }
  201. /*********************************************************************
  202. * @fn osal_mem_alloc
  203. *
  204. * @brief Implementation of the allocator functionality.
  205. *
  206. * @param size - number of bytes to allocate from the heap.
  207. *
  208. * @return void * - pointer to the heap allocation; NULL if error or failure.
  209. */
  210. void *osal_mem_alloc( uint16 size )
  211. {
  212. osalMemHdr_t *prev;
  213. osalMemHdr_t *hdr;
  214. halIntState_t intState;
  215. uint16 tmp;
  216. uint8 coal = 0;
  217. OSALMEM_ASSERT( size );
  218. size += HDRSZ;
  219. // Calculate required bytes to add to 'size' to align to halDataAlign_t.
  220. if ( sizeof( halDataAlign_t ) == 2 )
  221. {
  222. size += (size & 0x01);
  223. }
  224. else if ( sizeof( halDataAlign_t ) != 1 )
  225. {
  226. const uint8 mod = size % sizeof( halDataAlign_t );
  227. if ( mod != 0 )
  228. {
  229. size += (sizeof( halDataAlign_t ) - mod);
  230. }
  231. }
  232. HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
  233. // Smaller allocations are first attempted in the small-block bucket.
  234. if ( size <= OSALMEM_SMALL_BLKSZ )
  235. {
  236. hdr = ff1;
  237. }
  238. else
  239. {
  240. hdr = ff2;
  241. }
  242. tmp = *hdr;
  243. do
  244. {
  245. if ( tmp & OSALMEM_IN_USE )
  246. {
  247. tmp ^= OSALMEM_IN_USE;
  248. coal = 0;
  249. }
  250. else
  251. {
  252. if ( coal != 0 )
  253. {
  254. #if ( OSALMEM_METRICS )
  255. blkCnt--;
  256. blkFree--;
  257. #endif
  258. *prev += *hdr;
  259. if ( *prev >= size )
  260. {
  261. hdr = prev;
  262. tmp = *hdr;
  263. break;
  264. }
  265. }
  266. else
  267. {
  268. if ( tmp >= size )
  269. {
  270. break;
  271. }
  272. coal = 1;
  273. prev = hdr;
  274. }
  275. }
  276. hdr = (osalMemHdr_t *)((uint8 *)hdr + tmp);
  277. tmp = *hdr;
  278. if ( tmp == 0 )
  279. {
  280. hdr = NULL;
  281. break;
  282. }
  283. } while ( 1 );
  284. if ( hdr != NULL )
  285. {
  286. tmp -= size;
  287. // Determine whether the threshold for splitting is met.
  288. if ( tmp >= OSALMEM_MIN_BLKSZ )
  289. {
  290. // Split the block before allocating it.
  291. osalMemHdr_t *next = (osalMemHdr_t *)((uint8 *)hdr + size);
  292. *next = tmp;
  293. *hdr = (size | OSALMEM_IN_USE);
  294. #if ( OSALMEM_METRICS )
  295. blkCnt++;
  296. if ( blkMax < blkCnt )
  297. {
  298. blkMax = blkCnt;
  299. }
  300. memAlo += size;
  301. #endif
  302. }
  303. else
  304. {
  305. #if ( OSALMEM_METRICS )
  306. memAlo += *hdr;
  307. blkFree--;
  308. #endif
  309. *hdr |= OSALMEM_IN_USE;
  310. }
  311. #if ( OSALMEM_METRICS )
  312. if ( memMax < memAlo )
  313. {
  314. memMax = memAlo;
  315. }
  316. #endif
  317. #if ( OSALMEM_PROFILER )
  318. {
  319. byte idx;
  320. size = *hdr ^ OSALMEM_IN_USE;
  321. for ( idx = 0; idx < OSALMEM_PROMAX; idx++ )
  322. {
  323. if ( size <= proCnt[idx] )
  324. {
  325. break;
  326. }
  327. }
  328. proCur[idx]++;
  329. if ( proMax[idx] < proCur[idx] )
  330. {
  331. proMax[idx] = proCur[idx];
  332. }
  333. proTot[idx]++;
  334. }
  335. #endif
  336. hdr++;
  337. #if ( OSALMEM_PROFILER )
  338. osal_memset( (byte *)hdr, OSALMEM_ALOC, (size - HDRSZ) );
  339. /* A small-block could not be allocated in the small-block bucket.
  340. * When this occurs significantly frequently, increase the size of the
  341. * bucket in order to restore better worst case run times. Set the first
  342. * profiling bucket size in proCnt[] to the small-block bucket size and
  343. * divide proSmallBlkMiss by the corresponding proTot[] size to get % miss.
  344. * Best worst case time on TrasmitApp was achieved at a 0-15% miss rate
  345. * during steady state Tx load, 0% during idle and steady state Rx load.
  346. */
  347. if ( (size <= OSALMEM_SMALL_BLKSZ) && (hdr > ff2) )
  348. {
  349. proSmallBlkMiss++;
  350. }
  351. #endif
  352. }
  353. HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
  354. return (void *)hdr;
  355. }
  356. /*********************************************************************
  357. * @fn osal_mem_free
  358. *
  359. * @brief Implementation of the de-allocator functionality.
  360. *
  361. * @param ptr - pointer to the memory to free.
  362. *
  363. * @return void
  364. */
  365. void osal_mem_free( void *ptr )
  366. {
  367. osalMemHdr_t *currHdr;
  368. halIntState_t intState;
  369. HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
  370. OSALMEM_ASSERT( ptr );
  371. currHdr = (osalMemHdr_t *)ptr - 1;
  372. // Has this block already been freed?
  373. OSALMEM_ASSERT( *currHdr & OSALMEM_IN_USE );
  374. *currHdr &= ~OSALMEM_IN_USE;
  375. #if ( OSALMEM_PROFILER )
  376. {
  377. uint16 size = *currHdr;
  378. byte idx;
  379. for ( idx = 0; idx < OSALMEM_PROMAX; idx++ )
  380. {
  381. if ( size <= proCnt[idx] )
  382. {
  383. break;
  384. }
  385. }
  386. proCur[idx]--;
  387. }
  388. #endif
  389. #if ( OSALMEM_METRICS )
  390. memAlo -= *currHdr;
  391. blkFree++;
  392. #endif
  393. if ( ff1 > currHdr )
  394. {
  395. ff1 = currHdr;
  396. }
  397. #if ( OSALMEM_PROFILER )
  398. osal_memset( (byte *)currHdr+HDRSZ, OSALMEM_REIN, (*currHdr - HDRSZ) );
  399. #endif
  400. HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
  401. }
  402. #if ( OSALMEM_METRICS )
  403. /*********************************************************************
  404. * @fn osal_heap_block_max
  405. *
  406. * @brief Return the maximum number of blocks ever allocated at once.
  407. *
  408. * @param none
  409. *
  410. * @return Maximum number of blocks ever allocated at once.
  411. */
  412. uint16 osal_heap_block_max( void )
  413. {
  414. return blkMax;
  415. }
  416. /*********************************************************************
  417. * @fn osal_heap_block_cnt
  418. *
  419. * @brief Return the current number of blocks now allocated.
  420. *
  421. * @param none
  422. *
  423. * @return Current number of blocks now allocated.
  424. */
  425. uint16 osal_heap_block_cnt( void )
  426. {
  427. return blkCnt;
  428. }
  429. /*********************************************************************
  430. * @fn osal_heap_block_free
  431. *
  432. * @brief Return the current number of free blocks.
  433. *
  434. * @param none
  435. *
  436. * @return Current number of free blocks.
  437. */
  438. uint16 osal_heap_block_free( void )
  439. {
  440. return blkFree;
  441. }
  442. /*********************************************************************
  443. * @fn osal_heap_mem_used
  444. *
  445. * @brief Return the current number of bytes allocated.
  446. *
  447. * @param none
  448. *
  449. * @return Current number of bytes allocated.
  450. */
  451. uint16 osal_heap_mem_used( void )
  452. {
  453. return memAlo;
  454. }
  455. #endif
  456. #if defined (ZTOOL_P1) || defined (ZTOOL_P2)
  457. /*********************************************************************
  458. * @fn osal_heap_high_water
  459. *
  460. * @brief Return the highest byte ever allocated in the heap.
  461. *
  462. * @param none
  463. *
  464. * @return Highest number of bytes ever used by the stack.
  465. */
  466. uint16 osal_heap_high_water( void )
  467. {
  468. #if ( OSALMEM_METRICS )
  469. return memMax;
  470. #else
  471. return MAXMEMHEAP;
  472. #endif
  473. }
  474. #endif
  475. /*********************************************************************
  476. *********************************************************************/