1/*---------------------------------------------------------------------------*
2 *  pmemblock.c  *
3 *                                                                           *
4 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5 *                                                                           *
6 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7 *  you may not use this file except in compliance with the License.         *
8 *                                                                           *
9 *  You may obtain a copy of the License at                                  *
10 *      http://www.apache.org/licenses/LICENSE-2.0                           *
11 *                                                                           *
12 *  Unless required by applicable law or agreed to in writing, software      *
13 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 *  See the License for the specific language governing permissions and      *
16 *  limitations under the License.                                           *
17 *                                                                           *
18 *---------------------------------------------------------------------------*/
19
20
21
22#include "pmemory.h"
23#include "ptypes.h"
24
25#if PORTABLE_MEM_MGR == PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR
26
27#ifdef PSOSIM
28#define PSOS
29#endif
30
31#ifdef PSOS
32#include <stdlib.h>
33#include <psos.h>
34#endif
35
36#ifdef __cplusplus
37extern "C"
38{
39#endif
40
41  /* Data *****************************************************************/
42
43#define NUM_POOL_BINS 32
44#define NUM_POOL_SLOTS  8
45
46  typedef struct memory_pools
47  {
48    uint32   currentNumberOfPools;
49
50    struct pool_info
51    {
52      unsigned long poolId;
53      void*   pMemory;
54      unsigned long size;
55    }
56    poolInfo[NUM_POOL_SLOTS];
57
58  }
59  MEMORY_POOL;
60
61  static MEMORY_POOL memoryPool[NUM_POOL_BINS];
62
63#define NUM_TRACKING_BINS NUM_POOL_BINS
64
65  /* Object tracking variables */
66  static struct tracking_struct
67  {
68    uint32 sCurrentAllocationSize;
69    uint32 sMaximumAllocationSize;
70    uint32 sTotalAllocationSize;
71
72    uint32  sCurrentAllocRealSize;
73    uint32  sMaximumAllocRealSize;
74    uint32  sTotalAllocRealSize;
75
76    uint32 sCurrentAllocationNumber;
77    uint32 sMaximumAllocationNumber;
78    uint32 sTotalAllocationNumber;
79
80    uint32 sCurrentAllocationNumberArray[NUM_TRACKING_BINS];
81    uint32 sMaximumAllocationNumberArray[NUM_TRACKING_BINS];
82    uint32 sTotalAllocationNumberArray[NUM_TRACKING_BINS];
83
84    uint32 sCurrentAllocationSizeArray[NUM_TRACKING_BINS];
85    uint32 sMaximumAllocationSizeArray[NUM_TRACKING_BINS];
86    uint32 sTotalAllocationSizeArray[NUM_TRACKING_BINS];
87  }
88  gMemoryTracking;
89
90
91  /* Functions *********************************************************/
92
93  static uint32 findBin(size_t size)
94  {
95    int i, bin;
96    for (i = 0, bin = 1; i < NUM_TRACKING_BINS; i++, bin <<= 1)
97    {
98      if ((int)size <= bin)
99        return i;
100    }
101
102    return 0;
103  }
104
105
106  static void MemoryTrackingInit(void)
107  {
108    int i;
109    /* Initialization of object tracking variables */
110    gMemoryTracking.sCurrentAllocationSize = 0;
111    gMemoryTracking.sMaximumAllocationSize = 0;
112    gMemoryTracking.sTotalAllocationSize = 0;
113
114    gMemoryTracking.sCurrentAllocationNumber = 0;
115    gMemoryTracking.sMaximumAllocationNumber = 0;
116    gMemoryTracking.sTotalAllocationNumber = 0;
117
118    gMemoryTracking.sCurrentAllocRealSize = 0;
119    gMemoryTracking.sMaximumAllocRealSize = 0;
120    gMemoryTracking.sTotalAllocRealSize = 0;
121
122    for (i = 0; i < NUM_TRACKING_BINS; i++)
123    {
124      gMemoryTracking.sCurrentAllocationNumberArray[i] = 0;
125      gMemoryTracking.sMaximumAllocationNumberArray[i] = 0;
126      gMemoryTracking.sTotalAllocationNumberArray[i] = 0;
127
128      gMemoryTracking.sCurrentAllocationSizeArray[i] = 0;
129      gMemoryTracking.sMaximumAllocationSizeArray[i] = 0;
130      gMemoryTracking.sTotalAllocationSizeArray[i] = 0;
131    }
132  }
133
134
135  static void MemoryTrackingAdd(size_t size)
136  {
137    /* Memory tracking code */
138    uint32 bin = findBin(size);
139    uint32 binsize = 1 << bin;
140    uint32 dummy;
141
142    /* for breakpoint setting */
143#ifdef PSOSIM
144    if (bin == 0)
145      dummy = 0;
146    if (bin == 1)
147      dummy = 0;
148    if (bin == 2)
149      dummy = 0;
150    if (bin == 3)
151      dummy = 0;
152    if (bin == 4)
153      dummy = 0;
154    if (bin == 5)
155      dummy = 0;
156    if (bin == 6)
157      dummy = 0;
158    if (bin == 7)
159      dummy = 0;
160    if (bin == 8)
161      dummy = 0;
162    if (bin == 9)
163      dummy = 0;
164    if (bin == 10)
165      dummy = 0;
166    if (bin == 11)
167      dummy = 0;
168    if (bin == 12)
169      dummy = 0;
170    if (bin == 13)
171      dummy = 0;
172    if (bin == 14)
173      dummy = 0;
174    if (bin == 15)
175      dummy = 0;
176    if (bin == 16)
177      dummy = 0;
178    if (bin == 17)
179      dummy = 0;
180    if (bin == 18)
181      dummy = 0;
182    if (bin == 19)
183      dummy = 0;
184    if (bin == 20)
185      dummy = 0;
186    if (bin == 21)
187      dummy = 0;
188    if (bin >  21)
189      dummy = 0;
190#endif /* PSOSIM */
191
192    gMemoryTracking.sCurrentAllocationSize += size;
193    gMemoryTracking.sTotalAllocationSize += size;
194    if (gMemoryTracking.sCurrentAllocationSize > gMemoryTracking.sMaximumAllocationSize)
195      gMemoryTracking.sMaximumAllocationSize = gMemoryTracking.sCurrentAllocationSize;
196
197    gMemoryTracking.sCurrentAllocRealSize += binsize;
198    gMemoryTracking.sTotalAllocRealSize += binsize;
199    if (gMemoryTracking.sCurrentAllocRealSize > gMemoryTracking.sMaximumAllocRealSize)
200      gMemoryTracking.sMaximumAllocRealSize = gMemoryTracking.sCurrentAllocRealSize;
201
202    gMemoryTracking.sCurrentAllocationNumber++;
203    gMemoryTracking.sTotalAllocationNumber++;
204    if (gMemoryTracking.sCurrentAllocationNumber > gMemoryTracking.sMaximumAllocationNumber)
205      gMemoryTracking.sMaximumAllocationNumber = gMemoryTracking.sCurrentAllocationNumber;
206
207    gMemoryTracking.sCurrentAllocationSizeArray[bin] += size;
208    gMemoryTracking.sTotalAllocationSizeArray[bin] += size;
209    if (gMemoryTracking.sCurrentAllocationSizeArray[bin] > gMemoryTracking.sMaximumAllocationSizeArray[bin])
210      gMemoryTracking.sMaximumAllocationSizeArray[bin] = gMemoryTracking.sCurrentAllocationSizeArray[bin];
211
212    gMemoryTracking.sCurrentAllocationNumberArray[bin]++;
213    gMemoryTracking.sTotalAllocationNumberArray[bin]++;
214    if (gMemoryTracking.sCurrentAllocationNumberArray[bin] > gMemoryTracking.sMaximumAllocationNumberArray[bin])
215      gMemoryTracking.sMaximumAllocationNumberArray[bin] = gMemoryTracking.sCurrentAllocationNumberArray[bin];
216  }
217
218
219  static void MemoryTrackingDelete(unsigned long size)
220  {
221    /* Memory tracking code */
222    uint32 bin = findBin(size);
223    uint32 binsize = 1 << bin;
224
225    gMemoryTracking.sCurrentAllocationSize -= size;
226    gMemoryTracking.sCurrentAllocationNumber--;
227
228    gMemoryTracking.sCurrentAllocationSizeArray[bin] -= size;
229    gMemoryTracking.sCurrentAllocationNumberArray[bin]--;
230
231    gMemoryTracking.sCurrentAllocRealSize -= binsize;
232  }
233
234
235  static void InitPools(void)
236  {
237    int i, j;
238    for (i = 0; i < NUM_POOL_BINS; i++)
239    {
240      memoryPool[i].currentNumberOfPools = 0;
241
242      for (j = 0; j < NUM_POOL_SLOTS; j++)
243      {
244        memoryPool[i].poolInfo[j].poolId = 0;
245        memoryPool[i].poolInfo[j].pMemory = NULL;
246        memoryPool[i].poolInfo[j].size = 0;
247      }
248    }
249  }
250
251
252  static void TermPools(void)
253  {
254    int i, j;
255    /* For some reason, deleting the region then freeing the memory causes a failure */
256    /* TODO: Figure out why??? */
257    for (i = 1; i < NUM_POOL_BINS; i++)
258    {
259      for (j = 0; j < (int)memoryPool[i].currentNumberOfPools; j++)
260      {
261        if (memoryPool[i].poolInfo[j].pMemory != NULL)
262        {
263          unsigned long retval = pt_delete(memoryPool[i].poolInfo[j].poolId);
264          PORT_ASSERT(retval == 0);
265
266          PORT_ASSERT_GOOD_WRITE_POINTER(memoryPool[i].poolInfo[j].pMemory);
267          free(memoryPool[i].poolInfo[j].pMemory);
268
269          memoryPool[i].poolInfo[j].poolId = 0;
270          memoryPool[i].poolInfo[j].pMemory = NULL;
271          memoryPool[i].poolInfo[j].size = 0;
272        }
273      }
274
275      memoryPool[i].currentNumberOfPools = 0;
276    }
277  }
278
279
280#define PARTITION_CONTROL_BLOCK_SIZE 0x400
281
282  static BOOL CreatePool(uint32 whichPool, uint32 poolSize)
283  {
284    static uint32 poolNumber = 0;
285
286    void*   pMemory = NULL;
287    unsigned long poolId, unused;
288
289    uint32 currentNumberOfPools = memoryPool[whichPool].currentNumberOfPools;
290
291    PORT_ASSERT((whichPool >= 0) && (whichPool < NUM_POOL_BINS));
292
293    if (currentNumberOfPools == NUM_POOL_SLOTS)
294      return FALSE;
295
296
297    if (whichPool < 2)
298    {
299      /* Invalid partition size */
300      return FALSE;
301    }
302    else
303    {
304      char name[5];
305      unsigned long retval;
306
307      pMemory = malloc(poolSize * (1 << whichPool) + PARTITION_CONTROL_BLOCK_SIZE);
308      PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
309
310      /* No memory protection */
311      if (pMemory == NULL)
312      {
313        /* No memory left in system */
314        return FALSE;
315      }
316
317
318      sprintf(name, "DP%02d", poolNumber);
319
320      retval = pt_create(name, pMemory, 0, poolSize * (1 << whichPool) + PARTITION_CONTROL_BLOCK_SIZE,
321                         1 << whichPool, PT_LOCAL | PT_DEL, &poolId, &unused);
322      if (retval != 0)
323      {
324        /* Unable to create a pSOS partition */
325        return FALSE;
326      }
327    }
328
329    memoryPool[whichPool].poolInfo[currentNumberOfPools].poolId = poolId;
330    memoryPool[whichPool].poolInfo[currentNumberOfPools].pMemory = pMemory;
331    memoryPool[whichPool].poolInfo[currentNumberOfPools].size = poolSize;
332    memoryPool[whichPool].currentNumberOfPools++;
333
334    poolNumber++;
335
336    return TRUE;
337  }
338
339  static BOOL AddPool(uint32 whichPool, uint32 poolSize)
340  {
341    if (memoryPool[whichPool].poolInfo[0].pMemory == NULL)
342      return FALSE;
343
344    return CreatePool(whichPool, poolSize);
345  }
346
347  static void* AllocateFromPsos(uint32 whichPool, uint32 poolIndex, uint32 size)
348  {
349    uint32 retval;
350    void* pMemory;
351
352    PORT_ASSERT(memoryPool[whichPool].poolInfo[poolIndex].poolId);
353
354    retval = pt_getbuf(memoryPool[whichPool].poolInfo[poolIndex].poolId, &pMemory);
355
356    /* If we got memory, then return */
357    if (retval == 0)
358    {
359      PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
360      *((unsigned long *)pMemory) = (whichPool << 27) + (poolIndex << 24) + size;
361      return (unsigned long *)pMemory + 1;
362    }
363    else
364      return NULL;
365  }
366
367  static void* SearchPoolsForMemory(uint32 whichPool, uint32 size)
368  {
369    void*   pMemory;
370    uint32    poolIndex;
371    /* Get memory from main region */
372    if (whichPool == 0)
373    {
374      pMemory = malloc(size);
375
376      /* No memory protection */
377      if (pMemory == NULL)
378      {
379        /* No memory left in system */
380        return NULL;
381      }
382
383      PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
384      *((unsigned long *)pMemory) = (whichPool << 27) + size;
385      return (unsigned long *)pMemory + 1;
386    }
387
388    /* Allocate memory from the first available bin (partition) */
389    for (poolIndex = 0; poolIndex < memoryPool[whichPool].currentNumberOfPools; poolIndex++)
390    {
391      pMemory = AllocateFromPsos(whichPool, poolIndex, size);
392      if (pMemory != NULL)
393        return pMemory;
394    }
395
396    /* Made it here because we ran out of memory in the pool, so try to add more pools */
397    if (AddPool(whichPool, memoryPool[whichPool].poolInfo[0].size >> 1) == FALSE)
398    {
399      /* All pools of this size have been consumed */
400      return NULL;
401    }
402
403    /* Allocate memory from newly created pool */
404    pMemory = AllocateFromPsos(whichPool, memoryPool[whichPool].currentNumberOfPools - 1, size);
405    if (pMemory != NULL)
406      return pMemory;
407
408    /* If we can't allocate from the newly created pool, then we have problems */
409    /* No memory protection */
410
411    /* No memory left in system */
412    return NULL;
413  }
414
415  void* PortMemBlockAllocateFromPool(uint32 size)
416  {
417    void*   pMemory = NULL;
418    int    poolIndex;
419    BOOL foundPool = FALSE;
420    uint32 whichPool;
421
422    PORT_ASSERT((size & 0xff000000) == 0);
423
424    size += 4;
425    whichPool = findBin(size); /* Add 4 so I can store info with data */
426    MemoryTrackingAdd(size);
427
428    /* If pool exists for the size needed, then use it, else find next largest pool */
429    for (poolIndex = whichPool; poolIndex < 32; poolIndex++)
430      if (memoryPool[poolIndex].poolInfo[0].pMemory != NULL)
431      {
432        foundPool = TRUE;
433        whichPool = poolIndex;
434        break;
435      }
436
437    /* If next largest pool doesn't exist, then use pool 0 (regions) */
438    if (!foundPool)
439      whichPool = 0;
440
441    /* Allocate memory from the first available bin */
442    pMemory = SearchPoolsForMemory(whichPool, size);
443    PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
444    return pMemory;
445  }
446
447  void PortMemBlockDeleteFromPool(void* pMemory)
448  {
449    unsigned long *pRealMemory = (unsigned long *)pMemory - 1;
450
451    uint32 whichPool = (*pRealMemory >> 27) & 0x0000001f;
452    uint32 whichBin = (*pRealMemory >> 24) & 0x00000007;
453
454    PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
455    MemoryTrackingDelete(*pRealMemory & 0x00ffffff);
456
457
458    if (whichPool == 0)
459    {
460      free(pRealMemory);
461    }
462    else
463    {
464      uint32 retval = pt_retbuf(memoryPool[whichPool].poolInfo[whichBin].poolId, pRealMemory);
465      PORT_ASSERT(retval == 0);
466    }
467  }
468
469  /* PortMemGetPoolSize() : return size of portable memory pool, or 0 if
470   * unknown.
471   */
472  int  PortMemBlockGetPoolSize(void)
473  {
474    return 0; /* TODO: Find size of pool: 4Mar02 */
475  }
476
477  /* PortMemBlockSetPoolSize() : set size of portable memory pool on PSOS.
478   * This must be called before PortMemoryInit(), which is called by PortInit().
479   */
480  void PortMemBlockSetPoolSize(size_t sizeInBytes)
481  {}
482
483  int  PortMemBlockInit(void)
484  {
485    InitPools();
486    CreatePool(findBin(1 <<  3),  3000);
487    CreatePool(findBin(1 <<  4), 10000);
488    CreatePool(findBin(1 <<  5),  8000);
489    CreatePool(findBin(1 <<  6), 16000);
490    CreatePool(findBin(1 <<  7),  5000);
491    CreatePool(findBin(1 <<  8),  1000);
492    CreatePool(findBin(1 <<  9),  2000);
493    CreatePool(findBin(1 << 10),    50);
494    CreatePool(findBin(1 << 11),    20);
495    CreatePool(findBin(1 << 12),    24);
496    CreatePool(findBin(1 << 13),    16);
497    CreatePool(findBin(1 << 14),    10);
498    CreatePool(findBin(1 << 15),    16);
499    CreatePool(findBin(1 << 16),     4);
500    CreatePool(findBin(1 << 18),     6);
501
502    MemoryTrackingInit();
503  }
504
505  void PortMemBlockTerm(void)
506  {
507    TermPools();
508  }
509
510  void PortMemBlockTrackDump(void)
511  {
512    int i;
513
514    printf("\nCurrent Memory Usage = %d\nMaximum Memory Usage = %d\nTotal Memory Allocation = %d\n\n",
515           gMemoryTracking.sCurrentAllocationSize, gMemoryTracking.sMaximumAllocationSize, gMemoryTracking.sTotalAllocationSize);
516
517    printf("\nCurrent Real Memory Usage = %d\nMaximum Real Memory Usage = %d\nTotal Real Memory Allocation = %d\n\n",
518           gMemoryTracking.sCurrentAllocRealSize, gMemoryTracking.sMaximumAllocRealSize, gMemoryTracking.sTotalAllocRealSize);
519
520    for (i = 0; i < NUM_TRACKING_BINS; i++)
521      printf("Max size of 2^%2d byte objects = %d\n", i, gMemoryTracking.sMaximumAllocationSizeArray[i]);
522
523    printf("\nCurrent Memory Objects = %d\nMaximum Memory Objects = %d\nTotal Memory Objects = %d\n\n",
524           gMemoryTracking.sCurrentAllocationNumber, gMemoryTracking.sMaximumAllocationNumber, gMemoryTracking.sTotalAllocationNumber);
525
526    for (i = 0; i < NUM_TRACKING_BINS; i++)
527      printf("Max number for 2^%2d byte objects = %d\n", i, gMemoryTracking.sMaximumAllocationNumberArray[i]);
528  }
529
530  /* PortMemBlockGetMaxMemUsed() : return the maximum real memory allocated.
531   * There is another function of the same name in pmalloc.c, for tracking
532   * non-psos block memory.
533   */
534  int PortMemBlockGetMaxMemUsed(void)
535  {
536    return gMemoryTracking.sMaximumAllocRealSize;
537  }
538
539#ifdef __cplusplus
540}
541#endif
542
543#endif /* PORTABLE_MEM_MGR == PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR */
544
545