~clint-fewbar/ubuntu/precise/erlang/merge-15b

« back to all changes in this revision

Viewing changes to erts/emulator/sys/common/erl_mseg.c

  • Committer: Package Import Robot
  • Author(s): Sergei Golovan
  • Date: 2011-12-15 19:20:10 UTC
  • mfrom: (1.1.18) (3.5.15 sid)
  • mto: (3.5.16 sid)
  • mto: This revision was merged to the branch mainline in revision 33.
  • Revision ID: package-import@ubuntu.com-20111215192010-jnxcfe3tbrpp0big
Tags: 1:15.b-dfsg-1
* New upstream release.
* Upload to experimental because this release breaks external drivers
  API along with ABI, so several applications are to be fixed.
* Removed SSL patch because the old SSL implementation is removed from
  the upstream distribution.
* Removed never used patch which added native code to erlang beam files.
* Removed the erlang-docbuilder binary package because the docbuilder
  application was dropped by upstream.
* Documented dropping ${erlang-docbuilder:Depends} substvar in
  erlang-depends(1) manpage.
* Made erlang-base and erlang-base-hipe provide virtual package
  erlang-abi-15.b (the number means the first erlang version, which
  provides current ABI).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * %CopyrightBegin%
3
3
 *
4
 
 * Copyright Ericsson AB 2002-2010. All Rights Reserved.
 
4
 * Copyright Ericsson AB 2002-2011. All Rights Reserved.
5
5
 *
6
6
 * The contents of this file are subject to the Erlang Public License,
7
7
 * Version 1.1, (the "License"); you may not use this file except in
35
35
#include "global.h"
36
36
#include "erl_threads.h"
37
37
#include "erl_mtrace.h"
 
38
#include "erl_time.h"
 
39
#include "erl_alloc.h"
38
40
#include "big.h"
 
41
#include "erl_thr_progress.h"
39
42
 
40
43
#if HAVE_ERTS_MSEG
41
44
 
42
 
#if defined(USE_THREADS) && !defined(ERTS_SMP)
43
 
#  define ERTS_THREADS_NO_SMP
44
 
#endif
45
 
 
46
45
#define SEGTYPE ERTS_MTRACE_SEGMENT_ID
47
46
 
48
47
#ifndef HAVE_GETPAGESIZE
74
73
 
75
74
static int atoms_initialized;
76
75
 
77
 
static Uint cache_check_interval;
 
76
typedef struct mem_kind_t MemKind;
78
77
 
79
 
static void check_cache(void *unused);
80
 
static void mseg_clear_cache(void);
81
 
static int is_cache_check_scheduled;
82
 
#ifdef ERTS_THREADS_NO_SMP
83
 
static int is_cache_check_requested;
84
 
#endif
 
78
static void mseg_clear_cache(MemKind*);
85
79
 
86
80
#if HALFWORD_HEAP
87
81
static int initialize_pmmap(void);
122
116
#error "Not supported"
123
117
#endif /* #if HAVE_MMAP */
124
118
 
 
119
#if defined(ERTS_MSEG_FAKE_SEGMENTS) && HALFWORD_HEAP
 
120
#  warning "ERTS_MSEG_FAKE_SEGMENTS will only be used for high memory segments" 
 
121
#endif 
125
122
 
126
123
#if defined(ERTS_MSEG_FAKE_SEGMENTS)
127
124
#undef CAN_PARTLY_DESTROY
128
125
#define CAN_PARTLY_DESTROY 0
129
126
#endif
130
127
 
131
 
static const ErtsMsegOpt_t default_opt = ERTS_MSEG_DEFAULT_OPT_INITIALIZER;
 
128
const ErtsMsegOpt_t erts_mseg_default_opt = {
 
129
    1,                  /* Use cache                 */
 
130
    1,                  /* Preserv data              */
 
131
    0,                  /* Absolute shrink threshold */
 
132
    0,                  /* Relative shrink threshold */
 
133
    0                   /* Scheduler specific        */
 
134
#if HALFWORD_HEAP
 
135
    ,0                  /* need low memory */
 
136
#endif
 
137
};
 
138
 
132
139
 
133
140
typedef struct cache_desc_t_ {
134
141
    void *seg;
142
149
    Uint32 no;
143
150
} CallCounter;
144
151
 
145
 
static int is_init_done;
146
152
static Uint page_size;
147
153
static Uint page_shift;
148
154
 
149
 
static struct {
 
155
typedef struct {
150
156
    CallCounter alloc;
151
157
    CallCounter dealloc;
152
158
    CallCounter realloc;
157
163
#endif
158
164
    CallCounter clear_cache;
159
165
    CallCounter check_cache;
160
 
} calls;
161
 
 
162
 
static cache_desc_t cache_descs[MAX_CACHE_SIZE];
163
 
static cache_desc_t *free_cache_descs;
164
 
static cache_desc_t *cache;
165
 
static cache_desc_t *cache_end;
166
 
static Uint cache_hits;
167
 
static Uint cache_size;
168
 
static Uint min_cached_seg_size;
169
 
static Uint max_cached_seg_size;
170
 
 
171
 
static Uint max_cache_size;
172
 
static Uint abs_max_cache_bad_fit;
173
 
static Uint rel_max_cache_bad_fit;
 
166
} ErtsMsegCalls;
 
167
 
 
168
typedef struct ErtsMsegAllctr_t_ ErtsMsegAllctr_t;
 
169
 
 
170
struct mem_kind_t {
 
171
    cache_desc_t cache_descs[MAX_CACHE_SIZE];
 
172
    cache_desc_t *free_cache_descs;
 
173
    cache_desc_t *cache;
 
174
    cache_desc_t *cache_end;
 
175
 
 
176
    Uint cache_size;
 
177
    Uint min_cached_seg_size;
 
178
    Uint max_cached_seg_size;
 
179
    Uint cache_hits;
 
180
 
 
181
    struct {
 
182
        struct {
 
183
            Uint watermark;
 
184
            Uint no;
 
185
            Uint sz;
 
186
        } current;
 
187
        struct {
 
188
            Uint no;
 
189
            Uint sz;
 
190
        } max;
 
191
        struct {
 
192
            Uint no;
 
193
            Uint sz;
 
194
        } max_ever;
 
195
    } segments;
 
196
 
 
197
    ErtsMsegAllctr_t *ma;
 
198
    const char* name;
 
199
    MemKind* next;
 
200
};/*MemKind*/
 
201
 
 
202
struct ErtsMsegAllctr_t_ {
 
203
    int ix;
 
204
 
 
205
    int is_init_done;
 
206
    int is_thread_safe;
 
207
    erts_mtx_t mtx;
 
208
 
 
209
    int is_cache_check_scheduled;
 
210
 
 
211
    MemKind* mk_list;
 
212
 
 
213
#if HALFWORD_HEAP
 
214
    MemKind low_mem;
 
215
    MemKind hi_mem;
 
216
#else
 
217
    MemKind the_mem;
 
218
#endif
 
219
 
 
220
    Uint max_cache_size;
 
221
    Uint abs_max_cache_bad_fit;
 
222
    Uint rel_max_cache_bad_fit;
 
223
 
 
224
    ErtsMsegCalls calls;
174
225
 
175
226
#if CAN_PARTLY_DESTROY
176
 
static Uint min_seg_size;
177
 
#endif
178
 
 
179
 
struct {
180
 
    struct {
181
 
        Uint watermark;
182
 
        Uint no;
183
 
        Uint sz;
184
 
    } current;
185
 
    struct {
186
 
        Uint no;
187
 
        Uint sz;
188
 
    } max;
189
 
    struct {
190
 
        Uint no;
191
 
        Uint sz;
192
 
    } max_ever;
193
 
} segments;
194
 
 
195
 
#define ERTS_MSEG_ALLOC_STAT(SZ)                                        \
196
 
do {                                                                    \
197
 
    segments.current.no++;                                              \
198
 
    if (segments.max.no < segments.current.no)                          \
199
 
        segments.max.no = segments.current.no;                          \
200
 
    if (segments.current.watermark < segments.current.no)               \
201
 
        segments.current.watermark = segments.current.no;               \
202
 
    segments.current.sz += (SZ);                                        \
203
 
    if (segments.max.sz < segments.current.sz)                          \
204
 
        segments.max.sz = segments.current.sz;                          \
205
 
} while (0)
206
 
 
207
 
#define ERTS_MSEG_DEALLOC_STAT(SZ)                                      \
208
 
do {                                                                    \
209
 
    ASSERT(segments.current.no > 0);                                    \
210
 
    segments.current.no--;                                              \
211
 
    ASSERT(segments.current.sz >= (SZ));                                \
212
 
    segments.current.sz -= (SZ);                                        \
 
227
    Uint min_seg_size;
 
228
#endif
 
229
 
 
230
};
 
231
 
 
232
typedef union {
 
233
    ErtsMsegAllctr_t mseg_alloc;
 
234
    char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsMsegAllctr_t))];
 
235
} ErtsAlgndMsegAllctr_t;
 
236
 
 
237
static int no_mseg_allocators;
 
238
static ErtsAlgndMsegAllctr_t *aligned_mseg_allctr;
 
239
 
 
240
#ifdef ERTS_SMP
 
241
 
 
242
#define ERTS_MSEG_ALLCTR_IX(IX) \
 
243
  (&aligned_mseg_allctr[(IX)].mseg_alloc)
 
244
 
 
245
#define ERTS_MSEG_ALLCTR_SS() \
 
246
  ERTS_MSEG_ALLCTR_IX((int) erts_get_scheduler_id())
 
247
 
 
248
#define ERTS_MSEG_ALLCTR_OPT(OPT) \
 
249
  ((OPT)->sched_spec ? ERTS_MSEG_ALLCTR_SS() : ERTS_MSEG_ALLCTR_IX(0))
 
250
 
 
251
#else
 
252
 
 
253
#define ERTS_MSEG_ALLCTR_IX(IX) \
 
254
  (&aligned_mseg_allctr[0].mseg_alloc)
 
255
 
 
256
#define ERTS_MSEG_ALLCTR_SS() \
 
257
  (&aligned_mseg_allctr[0].mseg_alloc)
 
258
 
 
259
#define ERTS_MSEG_ALLCTR_OPT(OPT) \
 
260
  (&aligned_mseg_allctr[0].mseg_alloc)
 
261
 
 
262
#endif
 
263
 
 
264
#define ERTS_MSEG_LOCK(MA)              \
 
265
do {                                    \
 
266
    if ((MA)->is_thread_safe)           \
 
267
        erts_mtx_lock(&(MA)->mtx);      \
 
268
} while (0)
 
269
 
 
270
#define ERTS_MSEG_UNLOCK(MA)            \
 
271
do {                                    \
 
272
    if ((MA)->is_thread_safe)           \
 
273
        erts_mtx_unlock(&(MA)->mtx);    \
 
274
} while (0)
 
275
 
 
276
#define ERTS_MSEG_ALLOC_STAT(C,SZ)                                      \
 
277
do {                                                                    \
 
278
    C->segments.current.no++;                                           \
 
279
    if (C->segments.max.no < C->segments.current.no)                    \
 
280
        C->segments.max.no = C->segments.current.no;                    \
 
281
    if (C->segments.current.watermark < C->segments.current.no)         \
 
282
        C->segments.current.watermark = C->segments.current.no;         \
 
283
    C->segments.current.sz += (SZ);                                     \
 
284
    if (C->segments.max.sz < C->segments.current.sz)                    \
 
285
        C->segments.max.sz = C->segments.current.sz;                    \
 
286
} while (0)
 
287
 
 
288
#define ERTS_MSEG_DEALLOC_STAT(C,SZ)                                    \
 
289
do {                                                                    \
 
290
    ASSERT(C->segments.current.no > 0);                                 \
 
291
    C->segments.current.no--;                                           \
 
292
    ASSERT(C->segments.current.sz >= (SZ));                             \
 
293
    C->segments.current.sz -= (SZ);                                     \
213
294
} while (0) 
214
295
 
215
 
#define ERTS_MSEG_REALLOC_STAT(OSZ, NSZ)                                \
 
296
#define ERTS_MSEG_REALLOC_STAT(C,OSZ, NSZ)                              \
216
297
do {                                                                    \
217
 
    ASSERT(segments.current.sz >= (OSZ));                               \
218
 
    segments.current.sz -= (OSZ);                                       \
219
 
    segments.current.sz += (NSZ);                                       \
 
298
    ASSERT(C->segments.current.sz >= (OSZ));                            \
 
299
    C->segments.current.sz -= (OSZ);                                    \
 
300
    C->segments.current.sz += (NSZ);                                    \
220
301
} while (0)
221
302
 
222
303
#define ONE_GIGA (1000000000)
223
304
 
224
 
#define ZERO_CC(CC) (calls.CC.no = 0, calls.CC.giga_no = 0)
225
 
 
226
 
#define INC_CC(CC) (calls.CC.no == ONE_GIGA - 1                         \
227
 
                    ? (calls.CC.giga_no++, calls.CC.no = 0)             \
228
 
                    : calls.CC.no++)
229
 
 
230
 
#define DEC_CC(CC) (calls.CC.no == 0                                    \
231
 
                    ? (calls.CC.giga_no--,                              \
232
 
                       calls.CC.no = ONE_GIGA - 1)                      \
233
 
                    : calls.CC.no--)
234
 
 
235
 
 
236
 
static erts_mtx_t mseg_mutex; /* Also needed when !USE_THREADS */
 
305
#define ZERO_CC(MA, CC) ((MA)->calls.CC.no = 0,                         \
 
306
                         (MA)->calls.CC.giga_no = 0)
 
307
 
 
308
#define INC_CC(MA, CC) ((MA)->calls.CC.no == ONE_GIGA - 1               \
 
309
                        ? ((MA)->calls.CC.giga_no++,                    \
 
310
                           (MA)->calls.CC.no = 0)                       \
 
311
                        : (MA)->calls.CC.no++)
 
312
 
 
313
#define DEC_CC(MA, CC) ((MA)->calls.CC.no == 0                          \
 
314
                        ? ((MA)->calls.CC.giga_no--,                    \
 
315
                           (MA)->calls.CC.no = ONE_GIGA - 1)            \
 
316
                        : (MA)->calls.CC.no--)
 
317
 
 
318
 
237
319
static erts_mtx_t init_atoms_mutex; /* Also needed when !USE_THREADS */
238
320
 
239
 
#ifdef USE_THREADS
240
 
#ifdef ERTS_THREADS_NO_SMP
241
 
static erts_tid_t main_tid;
242
 
static int async_handle = -1;
243
 
#endif
244
321
 
245
 
static void thread_safe_init(void)
 
322
static ERTS_INLINE void
 
323
schedule_cache_check(ErtsMsegAllctr_t *ma)
246
324
{
247
 
    erts_mtx_init(&init_atoms_mutex, "mseg_init_atoms");
248
 
    erts_mtx_init(&mseg_mutex, "mseg");
249
325
 
250
 
#ifdef ERTS_THREADS_NO_SMP
251
 
    main_tid = erts_thr_self();
252
 
#endif
 
326
    if (!ma->is_cache_check_scheduled && ma->is_init_done) {
 
327
        erts_set_aux_work_timeout(ma->ix,
 
328
                                  ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK,
 
329
                                  1);
 
330
        ma->is_cache_check_scheduled = 1;
 
331
    }
253
332
}
254
333
 
255
 
#endif
256
 
 
257
 
static ErlTimer cache_check_timer;
258
 
 
259
 
static ERTS_INLINE void
260
 
schedule_cache_check(void)
 
334
static ERTS_INLINE void *
 
335
mseg_create(ErtsMsegAllctr_t *ma, MemKind* mk, Uint size)
261
336
{
262
 
    if (!is_cache_check_scheduled && is_init_done) {
263
 
#ifdef ERTS_THREADS_NO_SMP
264
 
        if (!erts_equal_tids(erts_thr_self(), main_tid)) {
265
 
            if (!is_cache_check_requested) {
266
 
                is_cache_check_requested = 1;
267
 
                sys_async_ready(async_handle);
268
 
            }
 
337
    void *seg;
 
338
 
 
339
    ASSERT(size % page_size == 0);
 
340
 
 
341
#if HALFWORD_HEAP
 
342
    if (mk == &ma->low_mem) {
 
343
        seg = pmmap(size);
 
344
        if ((unsigned long) seg & CHECK_POINTER_MASK) {
 
345
            erts_fprintf(stderr,"Pointer mask failure (0x%08lx)\n",(unsigned long) seg);
 
346
            return NULL;
269
347
        }
270
 
        else
 
348
    }
 
349
    else
271
350
#endif
 
351
    {
 
352
#if defined(ERTS_MSEG_FAKE_SEGMENTS)
 
353
        seg = erts_sys_alloc(ERTS_ALC_N_INVALID, NULL, size);
 
354
#elif HAVE_MMAP
272
355
        {
273
 
            cache_check_timer.active = 0;
274
 
            erl_set_timer(&cache_check_timer,
275
 
                          check_cache,
276
 
                          NULL,
277
 
                          NULL,
278
 
                          cache_check_interval);
279
 
            is_cache_check_scheduled = 1;
280
 
#ifdef ERTS_THREADS_NO_SMP
281
 
            is_cache_check_requested = 0;
282
 
#endif
 
356
            seg = (void *) mmap((void *) 0, (size_t) size,
 
357
                                MMAP_PROT, MMAP_FLAGS, MMAP_FD, 0);
 
358
            if (seg == (void *) MAP_FAILED)
 
359
                seg = NULL;
283
360
        }
284
 
    }
285
 
}
286
 
 
287
 
#ifdef ERTS_THREADS_NO_SMP
288
 
 
289
 
static void
290
 
check_schedule_cache_check(void)
291
 
{
292
 
    erts_mtx_lock(&mseg_mutex);
293
 
    if (is_cache_check_requested
294
 
        && !is_cache_check_scheduled) {
295
 
        schedule_cache_check();
296
 
    }
297
 
    erts_mtx_unlock(&mseg_mutex);    
298
 
}
299
 
 
300
 
#endif
301
 
 
302
 
static void
303
 
mseg_shutdown(void)
304
 
{
305
 
    erts_mtx_lock(&mseg_mutex);
306
 
    mseg_clear_cache();
307
 
    erts_mtx_unlock(&mseg_mutex);
308
 
}
309
 
 
310
 
static ERTS_INLINE void *
311
 
mseg_create(Uint size)
312
 
{
313
 
    void *seg;
314
 
 
315
 
    ASSERT(size % page_size == 0);
316
 
 
317
 
#if defined(ERTS_MSEG_FAKE_SEGMENTS)
318
 
    seg = erts_sys_alloc(ERTS_ALC_N_INVALID, NULL, size);
319
 
#elif HAVE_MMAP
320
 
#if HALFWORD_HEAP
321
 
    seg = pmmap(size);
322
 
#else
323
 
    seg = (void *) mmap((void *) 0, (size_t) size,
324
 
                        MMAP_PROT, MMAP_FLAGS, MMAP_FD, 0);
325
 
    if (seg == (void *) MAP_FAILED)
326
 
        seg = NULL;
327
 
#endif
328
 
#if HALFWORD_HEAP
329
 
    if ((unsigned long) seg & CHECK_POINTER_MASK) {
330
 
        erts_fprintf(stderr,"Pointer mask failure (0x%08lx)\n",(unsigned long) seg);
331
 
        return NULL;
332
 
    }
333
 
#endif
334
 
#else
335
 
#error "Missing mseg_create() implementation"
336
 
#endif
337
 
 
338
 
    INC_CC(create);
 
361
#else
 
362
# error "Missing mseg_create() implementation"
 
363
#endif
 
364
    }
 
365
 
 
366
    INC_CC(ma, create);
339
367
 
340
368
    return seg;
341
369
}
342
370
 
343
371
static ERTS_INLINE void
344
 
mseg_destroy(void *seg, Uint size)
 
372
mseg_destroy(ErtsMsegAllctr_t *ma, MemKind* mk, void *seg, Uint size)
345
373
{
346
 
#if defined(ERTS_MSEG_FAKE_SEGMENTS)
347
 
    erts_sys_free(ERTS_ALC_N_INVALID, NULL, seg);
 
374
#ifdef DEBUG
 
375
    int res;
 
376
#endif
 
377
 
 
378
#if HALFWORD_HEAP
 
379
    if (mk == &ma->low_mem) {
 
380
#ifdef DEBUG
 
381
        res = 
 
382
#endif
 
383
            pmunmap((void *) seg, size);
 
384
    }
 
385
    else
 
386
#endif
 
387
    {
 
388
#ifdef ERTS_MSEG_FAKE_SEGMENTS
 
389
        erts_sys_free(ERTS_ALC_N_INVALID, NULL, seg);
 
390
#ifdef DEBUG
 
391
        res = 0;
 
392
#endif
348
393
#elif HAVE_MMAP
349
 
 
350
394
#ifdef DEBUG
351
 
    int res =
 
395
        res = 
352
396
#endif
353
 
#if HALFWORD_HEAP
354
 
        pmunmap((void *) seg, size);
 
397
            munmap((void *) seg, size);
355
398
#else
356
 
        munmap((void *) seg, size);
 
399
# error "Missing mseg_destroy() implementation"
357
400
#endif
 
401
    }
 
402
 
358
403
    ASSERT(size % page_size == 0);
359
404
    ASSERT(res == 0);
360
 
#else
361
 
#error "Missing mseg_destroy() implementation"
362
 
#endif
363
405
 
364
 
    INC_CC(destroy);
 
406
    INC_CC(ma, destroy);
365
407
 
366
408
}
367
409
 
368
410
#if HAVE_MSEG_RECREATE
369
411
 
370
412
static ERTS_INLINE void *
371
 
mseg_recreate(void *old_seg, Uint old_size, Uint new_size)
 
413
mseg_recreate(ErtsMsegAllctr_t *ma, MemKind* mk, void *old_seg, Uint old_size, Uint new_size)
372
414
{
373
415
    void *new_seg;
374
416
 
375
417
    ASSERT(old_size % page_size == 0);
376
418
    ASSERT(new_size % page_size == 0);
377
419
 
 
420
#if HALFWORD_HEAP
 
421
    if (mk == &ma->low_mem) {
 
422
        new_seg = (void *) pmremap((void *) old_seg,
 
423
                                   (size_t) old_size,
 
424
                                   (size_t) new_size);
 
425
    }
 
426
    else
 
427
#endif
 
428
    {
378
429
#if defined(ERTS_MSEG_FAKE_SEGMENTS)
379
 
    new_seg = erts_sys_realloc(ERTS_ALC_N_INVALID, NULL, old_seg, new_size);
 
430
        new_seg = erts_sys_realloc(ERTS_ALC_N_INVALID, NULL, old_seg, new_size);
380
431
#elif HAVE_MREMAP
381
 
#if HALFWORD_HEAP
382
 
     new_seg = (void *) pmremap((void *) old_seg,
383
 
                                (size_t) old_size,
384
 
                                (size_t) new_size);
385
 
#elif defined(__NetBSD__)
386
 
    new_seg = (void *) mremap((void *) old_seg,
387
 
                              (size_t) old_size,
388
 
                              NULL,
389
 
                              (size_t) new_size,
390
 
                              0);
391
 
    if (new_seg == (void *) MAP_FAILED)
392
 
        new_seg = NULL;
393
 
#else
394
 
    new_seg = (void *) mremap((void *) old_seg,
395
 
                              (size_t) old_size,
396
 
                              (size_t) new_size,
397
 
                              MREMAP_MAYMOVE);
398
 
    if (new_seg == (void *) MAP_FAILED)
399
 
        new_seg = NULL;
400
 
#endif
 
432
 
 
433
    #if defined(__NetBSD__)
 
434
        new_seg = (void *) mremap((void *) old_seg,
 
435
                                  (size_t) old_size,
 
436
                                  NULL,
 
437
                                  (size_t) new_size,
 
438
                                  0);
 
439
    #else
 
440
        new_seg = (void *) mremap((void *) old_seg,
 
441
                                  (size_t) old_size,
 
442
                                  (size_t) new_size,
 
443
                                  MREMAP_MAYMOVE);
 
444
    #endif
 
445
        if (new_seg == (void *) MAP_FAILED)
 
446
            new_seg = NULL;
401
447
#else
402
448
#error "Missing mseg_recreate() implementation"
403
449
#endif
 
450
    }
404
451
 
405
 
    INC_CC(recreate);
 
452
    INC_CC(ma, recreate);
406
453
 
407
454
    return new_seg;
408
455
}
409
456
 
410
457
#endif /* #if HAVE_MSEG_RECREATE */
411
458
 
 
459
#ifdef DEBUG
 
460
#define ERTS_DBG_MA_CHK_THR_ACCESS(MA)                                  \
 
461
do {                                                                    \
 
462
    if ((MA)->is_thread_safe)                                           \
 
463
        ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&(MA)->mtx)                \
 
464
                       || erts_smp_thr_progress_is_blocking()           \
 
465
                       || ERTS_IS_CRASH_DUMPING);                       \
 
466
    else                                                                \
 
467
        ERTS_LC_ASSERT((MA)->ix == (int) erts_get_scheduler_id()        \
 
468
                       || erts_smp_thr_progress_is_blocking()           \
 
469
                       || ERTS_IS_CRASH_DUMPING);                       \
 
470
} while (0)
 
471
#define ERTS_DBG_MK_CHK_THR_ACCESS(MK) \
 
472
  ERTS_DBG_MA_CHK_THR_ACCESS((MK)->ma)
 
473
#else
 
474
#define ERTS_DBG_MA_CHK_THR_ACCESS(MA)
 
475
#define ERTS_DBG_MK_CHK_THR_ACCESS(MK)
 
476
#endif
412
477
 
413
478
static ERTS_INLINE cache_desc_t * 
414
 
alloc_cd(void)
 
479
alloc_cd(MemKind* mk)
415
480
{    
416
 
    cache_desc_t *cd = free_cache_descs;
417
 
    ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&mseg_mutex));
 
481
    cache_desc_t *cd = mk->free_cache_descs;
 
482
    ERTS_DBG_MK_CHK_THR_ACCESS(mk);
418
483
    if (cd)
419
 
        free_cache_descs = cd->next;
 
484
        mk->free_cache_descs = cd->next;
420
485
    return cd;
421
486
}
422
487
 
423
488
static ERTS_INLINE void
424
 
free_cd(cache_desc_t *cd)
 
489
free_cd(MemKind* mk, cache_desc_t *cd)
425
490
{
426
 
    ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&mseg_mutex));
427
 
    cd->next = free_cache_descs;
428
 
    free_cache_descs = cd;
 
491
    ERTS_DBG_MK_CHK_THR_ACCESS(mk);
 
492
    cd->next = mk->free_cache_descs;
 
493
    mk->free_cache_descs = cd;
429
494
}
430
495
 
431
496
 
432
497
static ERTS_INLINE void
433
 
link_cd(cache_desc_t *cd)
 
498
link_cd(MemKind* mk, cache_desc_t *cd)
434
499
{
435
 
    ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&mseg_mutex));
436
 
    if (cache)
437
 
        cache->prev = cd;
438
 
    cd->next = cache;
 
500
    ERTS_DBG_MK_CHK_THR_ACCESS(mk);
 
501
    if (mk->cache)
 
502
        mk->cache->prev = cd;
 
503
    cd->next = mk->cache;
439
504
    cd->prev = NULL;
440
 
    cache = cd;
 
505
    mk->cache = cd;
441
506
 
442
 
    if (!cache_end) {
 
507
    if (!mk->cache_end) {
443
508
        ASSERT(!cd->next);
444
 
        cache_end = cd;
 
509
        mk->cache_end = cd;
445
510
    }
446
511
 
447
 
    cache_size++;
 
512
    mk->cache_size++;
448
513
}
449
514
 
 
515
#if CAN_PARTLY_DESTROY
450
516
static ERTS_INLINE void
451
 
end_link_cd(cache_desc_t *cd)
 
517
end_link_cd(MemKind* mk, cache_desc_t *cd)
452
518
{
453
 
    ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&mseg_mutex));
454
 
    if (cache_end)
455
 
        cache_end->next = cd;
 
519
    ERTS_DBG_MK_CHK_THR_ACCESS(mk);
 
520
    if (mk->cache_end)
 
521
        mk->cache_end->next = cd;
456
522
    cd->next = NULL;
457
 
    cd->prev = cache_end;
458
 
    cache_end = cd;
 
523
    cd->prev = mk->cache_end;
 
524
    mk->cache_end = cd;
459
525
 
460
 
    if (!cache) {
 
526
    if (!mk->cache) {
461
527
        ASSERT(!cd->prev);
462
 
        cache = cd;
 
528
        mk->cache = cd;
463
529
    }
464
530
 
465
 
    cache_size++;
 
531
    mk->cache_size++;
466
532
}
 
533
#endif
467
534
 
468
535
static ERTS_INLINE void
469
 
unlink_cd(cache_desc_t *cd)
 
536
unlink_cd(MemKind* mk, cache_desc_t *cd)
470
537
{
471
 
    ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&mseg_mutex));
 
538
    ERTS_DBG_MK_CHK_THR_ACCESS(mk);
472
539
    if (cd->next)
473
540
        cd->next->prev = cd->prev;
474
541
    else
475
 
        cache_end = cd->prev;
 
542
        mk->cache_end = cd->prev;
476
543
    
477
544
    if (cd->prev)
478
545
        cd->prev->next = cd->next;
479
546
    else
480
 
        cache = cd->next;
481
 
    ASSERT(cache_size > 0);
482
 
    cache_size--;
 
547
        mk->cache = cd->next;
 
548
    ASSERT(mk->cache_size > 0);
 
549
    mk->cache_size--;
483
550
}
484
551
 
485
552
static ERTS_INLINE void
486
 
check_cache_limits(void)
 
553
check_cache_limits(MemKind* mk)
487
554
{
488
555
    cache_desc_t *cd;
489
 
    ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&mseg_mutex));
490
 
    max_cached_seg_size = 0;
491
 
    min_cached_seg_size = ~((Uint) 0);
492
 
    for (cd = cache; cd; cd = cd->next) {
493
 
        if (cd->size < min_cached_seg_size)
494
 
            min_cached_seg_size = cd->size;
495
 
        if (cd->size > max_cached_seg_size)
496
 
            max_cached_seg_size = cd->size;
 
556
    ERTS_DBG_MK_CHK_THR_ACCESS(mk);
 
557
    mk->max_cached_seg_size = 0;
 
558
    mk->min_cached_seg_size = ~((Uint) 0);
 
559
    for (cd = mk->cache; cd; cd = cd->next) {
 
560
        if (cd->size < mk->min_cached_seg_size)
 
561
            mk->min_cached_seg_size = cd->size;
 
562
        if (cd->size > mk->max_cached_seg_size)
 
563
            mk->max_cached_seg_size = cd->size;
497
564
    }
498
 
 
499
565
}
500
566
 
501
567
static ERTS_INLINE void
502
 
adjust_cache_size(int force_check_limits)
 
568
adjust_cache_size(MemKind* mk, int force_check_limits)
503
569
{
504
570
    cache_desc_t *cd;
505
571
    int check_limits = force_check_limits;
506
 
    Sint max_cached = ((Sint) segments.current.watermark
507
 
                       - (Sint) segments.current.no);
508
 
    ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&mseg_mutex));
509
 
    while (((Sint) cache_size) > max_cached && ((Sint) cache_size) > 0) {
510
 
        ASSERT(cache_end);
511
 
        cd = cache_end;
 
572
    Sint max_cached = ((Sint) mk->segments.current.watermark
 
573
                       - (Sint) mk->segments.current.no);
 
574
    ERTS_DBG_MK_CHK_THR_ACCESS(mk);
 
575
    while (((Sint) mk->cache_size) > max_cached && ((Sint) mk->cache_size) > 0) {
 
576
        ASSERT(mk->cache_end);
 
577
        cd = mk->cache_end;
512
578
        if (!check_limits &&
513
 
            !(min_cached_seg_size < cd->size
514
 
              && cd->size < max_cached_seg_size)) {
 
579
            !(mk->min_cached_seg_size < cd->size
 
580
              && cd->size < mk->max_cached_seg_size)) {
515
581
            check_limits = 1;
516
582
        }
517
583
        if (erts_mtrace_enabled)
518
584
            erts_mtrace_crr_free(SEGTYPE, SEGTYPE, cd->seg);
519
 
        mseg_destroy(cd->seg, cd->size);
520
 
        unlink_cd(cd);
521
 
        free_cd(cd);
 
585
        mseg_destroy(mk->ma, mk, cd->seg, cd->size);
 
586
        unlink_cd(mk,cd);
 
587
        free_cd(mk,cd);
522
588
    }
523
589
 
524
590
    if (check_limits)
525
 
        check_cache_limits();
526
 
 
527
 
}
528
 
 
529
 
static void
530
 
check_cache(void *unused)
531
 
{
532
 
    erts_mtx_lock(&mseg_mutex);
533
 
 
534
 
    is_cache_check_scheduled = 0;
535
 
 
536
 
    if (segments.current.watermark > segments.current.no)
537
 
        segments.current.watermark--;
538
 
    adjust_cache_size(0);
539
 
 
540
 
    if (cache_size)
541
 
        schedule_cache_check();
542
 
 
543
 
    INC_CC(check_cache);
544
 
 
545
 
    erts_mtx_unlock(&mseg_mutex);
546
 
}
547
 
 
548
 
static void
549
 
mseg_clear_cache(void)
550
 
{
551
 
    segments.current.watermark = 0;
552
 
 
553
 
    adjust_cache_size(1);
554
 
 
555
 
    ASSERT(!cache);
556
 
    ASSERT(!cache_end);
557
 
    ASSERT(!cache_size);
558
 
 
559
 
    segments.current.watermark = segments.current.no;
560
 
 
561
 
    INC_CC(clear_cache);
 
591
        check_cache_limits(mk);
 
592
}
 
593
 
 
594
static Uint
 
595
check_one_cache(MemKind* mk)
 
596
{
 
597
    if (mk->segments.current.watermark > mk->segments.current.no)
 
598
        mk->segments.current.watermark--;
 
599
    adjust_cache_size(mk, 0);
 
600
 
 
601
    if (mk->cache_size)
 
602
        schedule_cache_check(mk->ma);
 
603
    return mk->cache_size;
 
604
}
 
605
 
 
606
static void do_cache_check(ErtsMsegAllctr_t *ma)
 
607
{
 
608
    int empty_cache = 1;
 
609
    MemKind* mk;
 
610
 
 
611
    ERTS_MSEG_LOCK(ma);
 
612
 
 
613
    for (mk=ma->mk_list; mk; mk=mk->next) {
 
614
        if (check_one_cache(mk))
 
615
            empty_cache = 0;
 
616
    }
 
617
 
 
618
    if (empty_cache) {
 
619
        ma->is_cache_check_scheduled = 0;
 
620
        erts_set_aux_work_timeout(ma->ix,
 
621
                                  ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK,
 
622
                                  0);
 
623
    }
 
624
 
 
625
    INC_CC(ma, check_cache);
 
626
 
 
627
    ERTS_MSEG_UNLOCK(ma);
 
628
}
 
629
 
 
630
void erts_mseg_cache_check(void)
 
631
{
 
632
    do_cache_check(ERTS_MSEG_ALLCTR_SS());
 
633
}
 
634
 
 
635
static void
 
636
mseg_clear_cache(MemKind* mk)
 
637
{
 
638
    mk->segments.current.watermark = 0;
 
639
 
 
640
    adjust_cache_size(mk, 1);
 
641
 
 
642
    ASSERT(!mk->cache);
 
643
    ASSERT(!mk->cache_end);
 
644
    ASSERT(!mk->cache_size);
 
645
 
 
646
    mk->segments.current.watermark = mk->segments.current.no;
 
647
 
 
648
    INC_CC(mk->ma, clear_cache);
 
649
}
 
650
 
 
651
static ERTS_INLINE MemKind* memkind(ErtsMsegAllctr_t *ma,
 
652
                                    const ErtsMsegOpt_t *opt)
 
653
{
 
654
#if HALFWORD_HEAP
 
655
    return opt->low_mem ? &ma->low_mem : &ma->hi_mem;
 
656
#else
 
657
    return &ma->the_mem;
 
658
#endif
562
659
}
563
660
 
564
661
static void *
565
 
mseg_alloc(ErtsAlcType_t atype, Uint *size_p, const ErtsMsegOpt_t *opt)
 
662
mseg_alloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, Uint *size_p,
 
663
           const ErtsMsegOpt_t *opt)
566
664
{
567
 
 
568
665
    Uint max, min, diff_size, size;
569
666
    cache_desc_t *cd, *cand_cd;
570
667
    void *seg;
 
668
    MemKind* mk = memkind(ma, opt);
571
669
 
572
 
    INC_CC(alloc);
 
670
    INC_CC(ma, alloc);
573
671
 
574
672
    size = PAGE_CEILING(*size_p);
575
673
 
576
674
#if CAN_PARTLY_DESTROY
577
 
    if (size < min_seg_size)    
578
 
        min_seg_size = size;
 
675
    if (size < ma->min_seg_size)        
 
676
        ma->min_seg_size = size;
579
677
#endif
580
678
 
581
679
    if (!opt->cache) {
582
680
    create_seg:
583
 
        adjust_cache_size(0);
584
 
        seg = mseg_create(size);
 
681
        adjust_cache_size(mk,0);
 
682
        seg = mseg_create(ma, mk, size);
585
683
        if (!seg) {
586
 
            mseg_clear_cache();
587
 
            seg = mseg_create(size);
 
684
            mseg_clear_cache(mk);
 
685
            seg = mseg_create(ma, mk, size);
588
686
            if (!seg)
589
687
                size = 0;
590
688
        }
593
691
        if (seg) {
594
692
            if (erts_mtrace_enabled)
595
693
                erts_mtrace_crr_alloc(seg, atype, ERTS_MTRACE_SEGMENT_ID, size);
596
 
            ERTS_MSEG_ALLOC_STAT(size);
 
694
            ERTS_MSEG_ALLOC_STAT(mk,size);
597
695
        }
598
696
        return seg;
599
697
    }
600
698
 
601
 
    if (size > max_cached_seg_size)
 
699
    if (size > mk->max_cached_seg_size)
602
700
        goto create_seg;
603
701
 
604
 
    if (size < min_cached_seg_size) {
605
 
 
606
 
        diff_size = min_cached_seg_size - size;
607
 
 
608
 
        if (diff_size > abs_max_cache_bad_fit)
 
702
    if (size < mk->min_cached_seg_size) {
 
703
 
 
704
        diff_size = mk->min_cached_seg_size - size;
 
705
 
 
706
        if (diff_size > ma->abs_max_cache_bad_fit)
609
707
            goto create_seg;
610
708
 
611
 
        if (100*PAGES(diff_size) > rel_max_cache_bad_fit*PAGES(size))
 
709
        if (100*PAGES(diff_size) > ma->rel_max_cache_bad_fit*PAGES(size))
612
710
            goto create_seg;
613
711
 
614
712
    }
617
715
    min = ~((Uint) 0);
618
716
    cand_cd = NULL;
619
717
 
620
 
    for (cd = cache; cd; cd = cd->next) {
 
718
    for (cd = mk->cache; cd; cd = cd->next) {
621
719
        if (cd->size >= size) {
622
720
            if (!cand_cd) {
623
721
                cand_cd = cd;
638
736
            min = cd->size;
639
737
    }
640
738
 
641
 
    min_cached_seg_size = min;
642
 
    max_cached_seg_size = max;
 
739
    mk->min_cached_seg_size = min;
 
740
    mk->max_cached_seg_size = max;
643
741
 
644
742
    if (!cand_cd)
645
743
        goto create_seg;
646
744
 
647
745
    diff_size = cand_cd->size - size;
648
746
 
649
 
    if (diff_size > abs_max_cache_bad_fit
650
 
        || 100*PAGES(diff_size) > rel_max_cache_bad_fit*PAGES(size)) {
651
 
        if (max_cached_seg_size < cand_cd->size)        
652
 
            max_cached_seg_size = cand_cd->size;
653
 
        if (min_cached_seg_size > cand_cd->size)
654
 
            min_cached_seg_size = cand_cd->size;
 
747
    if (diff_size > ma->abs_max_cache_bad_fit
 
748
        || 100*PAGES(diff_size) > ma->rel_max_cache_bad_fit*PAGES(size)) {
 
749
        if (mk->max_cached_seg_size < cand_cd->size)
 
750
            mk->max_cached_seg_size = cand_cd->size;
 
751
        if (mk->min_cached_seg_size > cand_cd->size)
 
752
            mk->min_cached_seg_size = cand_cd->size;
655
753
        goto create_seg;
656
754
    }
657
755
 
658
 
    cache_hits++;
 
756
    mk->cache_hits++;
659
757
 
660
758
    size = cand_cd->size;
661
759
    seg = cand_cd->seg;
662
760
 
663
 
    unlink_cd(cand_cd);
664
 
    free_cd(cand_cd);
 
761
    unlink_cd(mk,cand_cd);
 
762
    free_cd(mk,cand_cd);
665
763
 
666
764
    *size_p = size;
667
765
 
671
769
    }
672
770
 
673
771
    if (seg)
674
 
        ERTS_MSEG_ALLOC_STAT(size);
 
772
        ERTS_MSEG_ALLOC_STAT(mk,size);
 
773
 
675
774
    return seg;
676
775
}
677
776
 
678
777
 
679
778
static void
680
 
mseg_dealloc(ErtsAlcType_t atype, void *seg, Uint size,
 
779
mseg_dealloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, Uint size,
681
780
             const ErtsMsegOpt_t *opt)
682
781
{
 
782
    MemKind* mk = memkind(ma, opt);
683
783
    cache_desc_t *cd;
684
784
 
685
 
    ERTS_MSEG_DEALLOC_STAT(size);
 
785
    ERTS_MSEG_DEALLOC_STAT(mk,size);
686
786
 
687
 
    if (!opt->cache || max_cache_size == 0) {
 
787
    if (!opt->cache || ma->max_cache_size == 0) {
688
788
        if (erts_mtrace_enabled)
689
789
            erts_mtrace_crr_free(atype, SEGTYPE, seg);
690
 
        mseg_destroy(seg, size);
 
790
        mseg_destroy(ma, mk, seg, size);
691
791
    }
692
792
    else {
693
793
        int check_limits = 0;
694
794
        
695
 
        if (size < min_cached_seg_size)
696
 
            min_cached_seg_size = size;
697
 
        if (size > max_cached_seg_size)
698
 
            max_cached_seg_size = size;
 
795
        if (size < mk->min_cached_seg_size)
 
796
            mk->min_cached_seg_size = size;
 
797
        if (size > mk->max_cached_seg_size)
 
798
            mk->max_cached_seg_size = size;
699
799
 
700
 
        if (!free_cache_descs) {
701
 
            cd = cache_end;
702
 
            if (!(min_cached_seg_size < cd->size
703
 
                  && cd->size < max_cached_seg_size)) {
 
800
        if (!mk->free_cache_descs) {
 
801
            cd = mk->cache_end;
 
802
            if (!(mk->min_cached_seg_size < cd->size
 
803
                  && cd->size < mk->max_cached_seg_size)) {
704
804
                check_limits = 1;
705
805
            }
706
806
            if (erts_mtrace_enabled)
707
807
                erts_mtrace_crr_free(SEGTYPE, SEGTYPE, cd->seg);
708
 
            mseg_destroy(cd->seg, cd->size);
709
 
            unlink_cd(cd);
710
 
            free_cd(cd);
 
808
            mseg_destroy(ma, mk, cd->seg, cd->size);
 
809
            unlink_cd(mk,cd);
 
810
            free_cd(mk,cd);
711
811
        }
712
812
 
713
 
        cd = alloc_cd();
 
813
        cd = alloc_cd(mk);
714
814
        ASSERT(cd);
715
815
        cd->seg = seg;
716
816
        cd->size = size;
717
 
        link_cd(cd);
 
817
        link_cd(mk,cd);
718
818
 
719
819
        if (erts_mtrace_enabled) {
720
820
            erts_mtrace_crr_free(atype, SEGTYPE, seg);
724
824
        /* ASSERT(segments.current.watermark >= segments.current.no + cache_size); */
725
825
 
726
826
        if (check_limits)
727
 
            check_cache_limits();
 
827
            check_cache_limits(mk);
728
828
 
729
 
        schedule_cache_check();
 
829
        schedule_cache_check(ma);
730
830
 
731
831
    }
732
832
 
733
 
    INC_CC(dealloc);
 
833
    INC_CC(ma, dealloc);
734
834
}
735
835
 
736
836
static void *
737
 
mseg_realloc(ErtsAlcType_t atype, void *seg, Uint old_size, Uint *new_size_p,
738
 
             const ErtsMsegOpt_t *opt)
 
837
mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
 
838
             Uint old_size, Uint *new_size_p, const ErtsMsegOpt_t *opt)
739
839
{
 
840
    MemKind* mk;
740
841
    void *new_seg;
741
842
    Uint new_size;
742
843
 
743
844
    if (!seg || !old_size) {
744
 
        new_seg = mseg_alloc(atype, new_size_p, opt);
745
 
        DEC_CC(alloc);
 
845
        new_seg = mseg_alloc(ma, atype, new_size_p, opt);
 
846
        DEC_CC(ma, alloc);
746
847
        return new_seg;
747
848
    }
748
849
 
749
850
    if (!(*new_size_p)) {
750
 
        mseg_dealloc(atype, seg, old_size, opt);
751
 
        DEC_CC(dealloc);
 
851
        mseg_dealloc(ma, atype, seg, old_size, opt);
 
852
        DEC_CC(ma, dealloc);
752
853
        return NULL;
753
854
    }
754
855
 
 
856
    mk = memkind(ma, opt);
755
857
    new_seg = seg;
756
858
    new_size = PAGE_CEILING(*new_size_p);
757
859
 
761
863
        Uint shrink_sz = old_size - new_size;
762
864
 
763
865
#if CAN_PARTLY_DESTROY
764
 
        if (new_size < min_seg_size)    
765
 
            min_seg_size = new_size;
 
866
        if (new_size < ma->min_seg_size)        
 
867
            ma->min_seg_size = new_size;
766
868
#endif
767
869
 
768
870
        if (shrink_sz < opt->abs_shrink_th
773
875
 
774
876
#if CAN_PARTLY_DESTROY
775
877
 
776
 
            if (shrink_sz > min_seg_size
777
 
                && free_cache_descs
 
878
            if (shrink_sz > ma->min_seg_size
 
879
                && mk->free_cache_descs
778
880
                && opt->cache) {
779
881
                cache_desc_t *cd;
780
882
 
781
 
                cd = alloc_cd();
 
883
                cd = alloc_cd(mk);
782
884
                ASSERT(cd);
783
885
                cd->seg = ((char *) seg) + new_size;
784
886
                cd->size = shrink_sz;
785
 
                end_link_cd(cd);
 
887
                end_link_cd(mk,cd);
786
888
 
787
889
                if (erts_mtrace_enabled) {
788
890
                    erts_mtrace_crr_realloc(new_seg,
792
894
                                            new_size);
793
895
                    erts_mtrace_crr_alloc(cd->seg, SEGTYPE, SEGTYPE, cd->size);
794
896
                }
795
 
                schedule_cache_check();
 
897
                schedule_cache_check(ma);
796
898
            }
797
899
            else {
798
900
                if (erts_mtrace_enabled)
801
903
                                            SEGTYPE,
802
904
                                            seg,
803
905
                                            new_size);
804
 
                mseg_destroy(((char *) seg) + new_size, shrink_sz);
 
906
                mseg_destroy(ma, mk, ((char *) seg) + new_size, shrink_sz);
805
907
            }
806
908
 
807
909
#elif HAVE_MSEG_RECREATE
810
912
 
811
913
#else
812
914
 
813
 
            new_seg = mseg_alloc(atype, &new_size, opt);
 
915
            new_seg = mseg_alloc(ma, atype, &new_size, opt);
814
916
            if (!new_seg)
815
917
                new_size = old_size;
816
918
            else {
817
919
                sys_memcpy(((char *) new_seg),
818
920
                           ((char *) seg),
819
921
                           MIN(new_size, old_size));
820
 
                mseg_dealloc(atype, seg, old_size, opt);
 
922
                mseg_dealloc(ma, atype, seg, old_size, opt);
821
923
            }
822
924
 
823
925
#endif
827
929
    else {
828
930
 
829
931
        if (!opt->preserv) {
830
 
            mseg_dealloc(atype, seg, old_size, opt);
831
 
            new_seg = mseg_alloc(atype, &new_size, opt);
 
932
            mseg_dealloc(ma, atype, seg, old_size, opt);
 
933
            new_seg = mseg_alloc(ma, atype, &new_size, opt);
832
934
        }
833
935
        else {
834
936
#if HAVE_MSEG_RECREATE
835
937
#if !CAN_PARTLY_DESTROY
836
938
        do_recreate:
837
939
#endif
838
 
            new_seg = mseg_recreate((void *) seg, old_size, new_size);
 
940
            new_seg = mseg_recreate(ma, mk, (void *) seg, old_size, new_size);
839
941
            if (erts_mtrace_enabled)
840
942
                erts_mtrace_crr_realloc(new_seg, atype, SEGTYPE, seg, new_size);
841
943
            if (!new_seg)
842
944
                new_size = old_size;
843
945
#else
844
 
            new_seg = mseg_alloc(atype, &new_size, opt);
 
946
            new_seg = mseg_alloc(ma, atype, &new_size, opt);
845
947
            if (!new_seg)
846
948
                new_size = old_size;
847
949
            else {
848
950
                sys_memcpy(((char *) new_seg),
849
951
                           ((char *) seg),
850
952
                           MIN(new_size, old_size));
851
 
                mseg_dealloc(atype, seg, old_size, opt);
 
953
                mseg_dealloc(ma, atype, seg, old_size, opt);
852
954
            }
853
955
#endif
854
956
        }
855
957
    }
856
958
 
857
 
    INC_CC(realloc);
 
959
    INC_CC(ma, realloc);
858
960
 
859
961
    *new_size_p = new_size;
860
962
 
861
 
    ERTS_MSEG_REALLOC_STAT(old_size, new_size);
 
963
    ERTS_MSEG_REALLOC_STAT(mk, old_size, new_size);
862
964
 
863
965
    return new_seg;
864
966
}
872
974
    Eterm amcbf;
873
975
    Eterm rmcbf;
874
976
    Eterm mcs;
875
 
    Eterm cci;
876
977
 
 
978
    Eterm memkind;
 
979
    Eterm name;
877
980
    Eterm status;
878
981
    Eterm cached_segments;
879
982
    Eterm cache_hits;
906
1009
#define AM_INIT(AM) atom_init(&am.AM, #AM)
907
1010
 
908
1011
static void
909
 
init_atoms(void)
 
1012
init_atoms(ErtsMsegAllctr_t *ma)
910
1013
{
911
1014
#ifdef DEBUG
912
1015
    Eterm *atom;
913
1016
#endif
914
1017
 
915
 
    erts_mtx_unlock(&mseg_mutex);
 
1018
    ERTS_MSEG_UNLOCK(ma);
916
1019
    erts_mtx_lock(&init_atoms_mutex);
917
1020
 
918
1021
    if (!atoms_initialized) {
923
1026
#endif
924
1027
 
925
1028
        AM_INIT(version);
 
1029
        AM_INIT(memkind);
 
1030
        AM_INIT(name);
926
1031
 
927
1032
        AM_INIT(options);
928
1033
        AM_INIT(amcbf);
929
1034
        AM_INIT(rmcbf);
930
1035
        AM_INIT(mcs);
931
 
        AM_INIT(cci);
932
1036
 
933
1037
        AM_INIT(status);
934
1038
        AM_INIT(cached_segments);
956
1060
#endif
957
1061
    }
958
1062
 
959
 
    erts_mtx_lock(&mseg_mutex);
 
1063
    ERTS_MSEG_LOCK(ma);
960
1064
    atoms_initialized = 1;
961
1065
    erts_mtx_unlock(&init_atoms_mutex);
962
1066
}
1013
1117
}
1014
1118
 
1015
1119
static Eterm
1016
 
info_options(char *prefix,
 
1120
info_options(ErtsMsegAllctr_t *ma,
 
1121
             char *prefix,
1017
1122
             int *print_to_p,
1018
1123
             void *print_to_arg,
1019
1124
             Uint **hpp,
1024
1129
    if (print_to_p) {
1025
1130
        int to = *print_to_p;
1026
1131
        void *arg = print_to_arg;
1027
 
        erts_print(to, arg, "%samcbf: %bpu\n", prefix, abs_max_cache_bad_fit);
1028
 
        erts_print(to, arg, "%srmcbf: %bpu\n", prefix, rel_max_cache_bad_fit);
1029
 
        erts_print(to, arg, "%smcs: %bpu\n", prefix, max_cache_size);
1030
 
        erts_print(to, arg, "%scci: %bpu\n", prefix, cache_check_interval);
 
1132
        erts_print(to, arg, "%samcbf: %beu\n", prefix, ma->abs_max_cache_bad_fit);
 
1133
        erts_print(to, arg, "%srmcbf: %beu\n", prefix, ma->rel_max_cache_bad_fit);
 
1134
        erts_print(to, arg, "%smcs: %beu\n", prefix, ma->max_cache_size);
1031
1135
    }
1032
1136
 
1033
1137
    if (hpp || szp) {
1034
1138
 
1035
1139
        if (!atoms_initialized)
1036
 
            init_atoms();
 
1140
            init_atoms(ma);
1037
1141
 
1038
1142
        res = NIL;
1039
1143
        add_2tup(hpp, szp, &res,
1040
 
                 am.cci,
1041
 
                 bld_uint(hpp, szp, cache_check_interval));
1042
 
        add_2tup(hpp, szp, &res,
1043
1144
                 am.mcs,
1044
 
                 bld_uint(hpp, szp, max_cache_size));
 
1145
                 bld_uint(hpp, szp, ma->max_cache_size));
1045
1146
        add_2tup(hpp, szp, &res,
1046
1147
                 am.rmcbf,
1047
 
                 bld_uint(hpp, szp, rel_max_cache_bad_fit));
 
1148
                 bld_uint(hpp, szp, ma->rel_max_cache_bad_fit));
1048
1149
        add_2tup(hpp, szp, &res,
1049
1150
                 am.amcbf,
1050
 
                 bld_uint(hpp, szp, abs_max_cache_bad_fit));
 
1151
                 bld_uint(hpp, szp, ma->abs_max_cache_bad_fit));
1051
1152
 
1052
1153
    }
1053
1154
 
1055
1156
}
1056
1157
 
1057
1158
static Eterm
1058
 
info_calls(int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp)
 
1159
info_calls(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp)
1059
1160
{
1060
1161
    Eterm res = THE_NON_VALUE;
1061
1162
 
1062
1163
    if (print_to_p) {
1063
1164
 
1064
 
#define PRINT_CC(TO, TOA, CC)                                           \
1065
 
    if (calls.CC.giga_no == 0)                                          \
1066
 
        erts_print(TO, TOA, "mseg_%s calls: %bpu\n", #CC, calls.CC.no); \
1067
 
    else                                                                \
1068
 
        erts_print(TO, TOA, "mseg_%s calls: %bpu%09bpu\n", #CC,         \
1069
 
                   calls.CC.giga_no, calls.CC.no)
 
1165
#define PRINT_CC(TO, TOA, CC)                                                   \
 
1166
    if (ma->calls.CC.giga_no == 0)                                              \
 
1167
        erts_print(TO, TOA, "mseg_%s calls: %b32u\n", #CC, ma->calls.CC.no);    \
 
1168
    else                                                                        \
 
1169
        erts_print(TO, TOA, "mseg_%s calls: %b32u%09b32u\n", #CC,               \
 
1170
                   ma->calls.CC.giga_no, ma->calls.CC.no)
1070
1171
 
1071
1172
        int to = *print_to_p;
1072
1173
        void *arg = print_to_arg;
1092
1193
 
1093
1194
        add_3tup(hpp, szp, &res,
1094
1195
                 am.mseg_check_cache,
1095
 
                 bld_unstable_uint(hpp, szp, calls.check_cache.giga_no),
1096
 
                 bld_unstable_uint(hpp, szp, calls.check_cache.no));
 
1196
                 bld_unstable_uint(hpp, szp, ma->calls.check_cache.giga_no),
 
1197
                 bld_unstable_uint(hpp, szp, ma->calls.check_cache.no));
1097
1198
        add_3tup(hpp, szp, &res,
1098
1199
                 am.mseg_clear_cache,
1099
 
                 bld_unstable_uint(hpp, szp, calls.clear_cache.giga_no),
1100
 
                 bld_unstable_uint(hpp, szp, calls.clear_cache.no));
 
1200
                 bld_unstable_uint(hpp, szp, ma->calls.clear_cache.giga_no),
 
1201
                 bld_unstable_uint(hpp, szp, ma->calls.clear_cache.no));
1101
1202
 
1102
1203
#if HAVE_MSEG_RECREATE
1103
1204
        add_3tup(hpp, szp, &res,
1104
1205
                 am.mseg_recreate,
1105
 
                 bld_unstable_uint(hpp, szp, calls.recreate.giga_no),
1106
 
                 bld_unstable_uint(hpp, szp, calls.recreate.no));
 
1206
                 bld_unstable_uint(hpp, szp, ma->calls.recreate.giga_no),
 
1207
                 bld_unstable_uint(hpp, szp, ma->calls.recreate.no));
1107
1208
#endif
1108
1209
        add_3tup(hpp, szp, &res,
1109
1210
                 am.mseg_destroy,
1110
 
                 bld_unstable_uint(hpp, szp, calls.destroy.giga_no),
1111
 
                 bld_unstable_uint(hpp, szp, calls.destroy.no));
 
1211
                 bld_unstable_uint(hpp, szp, ma->calls.destroy.giga_no),
 
1212
                 bld_unstable_uint(hpp, szp, ma->calls.destroy.no));
1112
1213
        add_3tup(hpp, szp, &res,
1113
1214
                 am.mseg_create,
1114
 
                 bld_unstable_uint(hpp, szp, calls.create.giga_no),
1115
 
                 bld_unstable_uint(hpp, szp, calls.create.no));
 
1215
                 bld_unstable_uint(hpp, szp, ma->calls.create.giga_no),
 
1216
                 bld_unstable_uint(hpp, szp, ma->calls.create.no));
1116
1217
 
1117
1218
 
1118
1219
        add_3tup(hpp, szp, &res,
1119
1220
                 am.mseg_realloc,
1120
 
                 bld_unstable_uint(hpp, szp, calls.realloc.giga_no),
1121
 
                 bld_unstable_uint(hpp, szp, calls.realloc.no));
 
1221
                 bld_unstable_uint(hpp, szp, ma->calls.realloc.giga_no),
 
1222
                 bld_unstable_uint(hpp, szp, ma->calls.realloc.no));
1122
1223
        add_3tup(hpp, szp, &res,
1123
1224
                 am.mseg_dealloc,
1124
 
                 bld_unstable_uint(hpp, szp, calls.dealloc.giga_no),
1125
 
                 bld_unstable_uint(hpp, szp, calls.dealloc.no));
 
1225
                 bld_unstable_uint(hpp, szp, ma->calls.dealloc.giga_no),
 
1226
                 bld_unstable_uint(hpp, szp, ma->calls.dealloc.no));
1126
1227
        add_3tup(hpp, szp, &res,
1127
1228
                 am.mseg_alloc,
1128
 
                 bld_unstable_uint(hpp, szp, calls.alloc.giga_no),
1129
 
                 bld_unstable_uint(hpp, szp, calls.alloc.no));
 
1229
                 bld_unstable_uint(hpp, szp, ma->calls.alloc.giga_no),
 
1230
                 bld_unstable_uint(hpp, szp, ma->calls.alloc.no));
1130
1231
    }
1131
1232
 
1132
1233
    return res;
1133
1234
}
1134
1235
 
1135
1236
static Eterm
1136
 
info_status(int *print_to_p,
1137
 
            void *print_to_arg,
1138
 
            int begin_new_max_period,
1139
 
            Uint **hpp,
1140
 
            Uint *szp)
 
1237
info_status(ErtsMsegAllctr_t *ma, MemKind* mk, int *print_to_p, void *print_to_arg,
 
1238
            int begin_new_max_period, Uint **hpp, Uint *szp)
1141
1239
{
1142
1240
    Eterm res = THE_NON_VALUE;
1143
1241
    
1144
 
    if (segments.max_ever.no < segments.max.no)
1145
 
        segments.max_ever.no = segments.max.no;
1146
 
    if (segments.max_ever.sz < segments.max.sz)
1147
 
        segments.max_ever.sz = segments.max.sz;
 
1242
    if (mk->segments.max_ever.no < mk->segments.max.no)
 
1243
        mk->segments.max_ever.no = mk->segments.max.no;
 
1244
    if (mk->segments.max_ever.sz < mk->segments.max.sz)
 
1245
        mk->segments.max_ever.sz = mk->segments.max.sz;
1148
1246
 
1149
1247
    if (print_to_p) {
1150
1248
        int to = *print_to_p;
1151
1249
        void *arg = print_to_arg;
1152
1250
 
1153
 
        erts_print(to, arg, "cached_segments: %bpu\n", cache_size);
1154
 
        erts_print(to, arg, "cache_hits: %bpu\n", cache_hits);
1155
 
        erts_print(to, arg, "segments: %bpu %bpu %bpu\n",
1156
 
                   segments.current.no, segments.max.no, segments.max_ever.no);
1157
 
        erts_print(to, arg, "segments_size: %bpu %bpu %bpu\n",
1158
 
                   segments.current.sz, segments.max.sz, segments.max_ever.sz);
1159
 
        erts_print(to, arg, "segments_watermark: %bpu\n",
1160
 
                   segments.current.watermark);
 
1251
        erts_print(to, arg, "cached_segments: %beu\n", mk->cache_size);
 
1252
        erts_print(to, arg, "cache_hits: %beu\n", mk->cache_hits);
 
1253
        erts_print(to, arg, "segments: %beu %beu %beu\n",
 
1254
                   mk->segments.current.no, mk->segments.max.no, mk->segments.max_ever.no);
 
1255
        erts_print(to, arg, "segments_size: %beu %beu %beu\n",
 
1256
                   mk->segments.current.sz, mk->segments.max.sz, mk->segments.max_ever.sz);
 
1257
        erts_print(to, arg, "segments_watermark: %beu\n",
 
1258
                   mk->segments.current.watermark);
1161
1259
    }
1162
1260
 
1163
1261
    if (hpp || szp) {
1164
1262
        res = NIL;
1165
1263
        add_2tup(hpp, szp, &res,
1166
1264
                 am.segments_watermark,
1167
 
                 bld_unstable_uint(hpp, szp, segments.current.watermark));
 
1265
                 bld_unstable_uint(hpp, szp, mk->segments.current.watermark));
1168
1266
        add_4tup(hpp, szp, &res,
1169
1267
                 am.segments_size,
1170
 
                 bld_unstable_uint(hpp, szp, segments.current.sz),
1171
 
                 bld_unstable_uint(hpp, szp, segments.max.sz),
1172
 
                 bld_unstable_uint(hpp, szp, segments.max_ever.sz));
 
1268
                 bld_unstable_uint(hpp, szp, mk->segments.current.sz),
 
1269
                 bld_unstable_uint(hpp, szp, mk->segments.max.sz),
 
1270
                 bld_unstable_uint(hpp, szp, mk->segments.max_ever.sz));
1173
1271
        add_4tup(hpp, szp, &res,
1174
1272
                 am.segments,
1175
 
                 bld_unstable_uint(hpp, szp, segments.current.no),
1176
 
                 bld_unstable_uint(hpp, szp, segments.max.no),
1177
 
                 bld_unstable_uint(hpp, szp, segments.max_ever.no));
 
1273
                 bld_unstable_uint(hpp, szp, mk->segments.current.no),
 
1274
                 bld_unstable_uint(hpp, szp, mk->segments.max.no),
 
1275
                 bld_unstable_uint(hpp, szp, mk->segments.max_ever.no));
1178
1276
        add_2tup(hpp, szp, &res,
1179
1277
                 am.cache_hits,
1180
 
                 bld_unstable_uint(hpp, szp, cache_hits));
 
1278
                 bld_unstable_uint(hpp, szp, mk->cache_hits));
1181
1279
        add_2tup(hpp, szp, &res,
1182
1280
                 am.cached_segments,
1183
 
                 bld_unstable_uint(hpp, szp, cache_size));
 
1281
                 bld_unstable_uint(hpp, szp, mk->cache_size));
1184
1282
 
1185
1283
    }
1186
1284
 
1187
1285
    if (begin_new_max_period) {
1188
 
        segments.max.no = segments.current.no;
1189
 
        segments.max.sz = segments.current.sz;
1190
 
    }
1191
 
 
1192
 
    return res;
1193
 
}
 
1286
        mk->segments.max.no = mk->segments.current.no;
 
1287
        mk->segments.max.sz = mk->segments.current.sz;
 
1288
    }
 
1289
 
 
1290
    return res;
 
1291
}
 
1292
 
 
1293
static Eterm info_memkind(ErtsMsegAllctr_t *ma, MemKind* mk, int *print_to_p, void *print_to_arg,
 
1294
                          int begin_max_per, Uint **hpp, Uint *szp)
 
1295
{
 
1296
    Eterm res = THE_NON_VALUE;
 
1297
    Eterm atoms[3];
 
1298
    Eterm values[3];
 
1299
 
 
1300
    if (print_to_p) {
 
1301
        erts_print(*print_to_p, print_to_arg, "memory kind: %s\n", mk->name);
 
1302
    }
 
1303
    if (hpp || szp) {
 
1304
        atoms[0] = am.name;
 
1305
        atoms[1] = am.status;
 
1306
        atoms[2] = am.calls;
 
1307
        values[0] = erts_bld_string(hpp, szp, mk->name);
 
1308
    }
 
1309
    values[1] = info_status(ma, mk, print_to_p, print_to_arg, begin_max_per, hpp, szp);
 
1310
    values[2] = info_calls(ma, print_to_p, print_to_arg, hpp, szp);
 
1311
 
 
1312
    if (hpp || szp)
 
1313
        res = bld_2tup_list(hpp, szp, 3, atoms, values);
 
1314
 
 
1315
    return res;
 
1316
}
 
1317
 
1194
1318
 
1195
1319
static Eterm
1196
 
info_version(int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp)
 
1320
info_version(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp)
1197
1321
{
1198
1322
    Eterm res = THE_NON_VALUE;
1199
1323
 
1214
1338
\*                                                                           */
1215
1339
 
1216
1340
Eterm
1217
 
erts_mseg_info_options(int *print_to_p, void *print_to_arg,
 
1341
erts_mseg_info_options(int ix,
 
1342
                       int *print_to_p, void *print_to_arg,
1218
1343
                       Uint **hpp, Uint *szp)
1219
1344
{
 
1345
    ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(ix);
1220
1346
    Eterm res;
1221
1347
 
1222
 
    erts_mtx_lock(&mseg_mutex);
1223
 
 
1224
 
    res = info_options("option ", print_to_p, print_to_arg, hpp, szp);
1225
 
 
1226
 
    erts_mtx_unlock(&mseg_mutex);
 
1348
    ERTS_MSEG_LOCK(ma);
 
1349
 
 
1350
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
 
1351
 
 
1352
    res = info_options(ma, "option ", print_to_p, print_to_arg, hpp, szp);
 
1353
 
 
1354
    ERTS_MSEG_UNLOCK(ma);
1227
1355
 
1228
1356
    return res;
1229
1357
}
1230
1358
 
1231
1359
Eterm
1232
 
erts_mseg_info(int *print_to_p,
 
1360
erts_mseg_info(int ix,
 
1361
               int *print_to_p,
1233
1362
               void *print_to_arg,
1234
1363
               int begin_max_per,
1235
1364
               Uint **hpp,
1236
1365
               Uint *szp)
1237
1366
{
 
1367
    ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(ix);
1238
1368
    Eterm res = THE_NON_VALUE;
1239
1369
    Eterm atoms[4];
1240
1370
    Eterm values[4];
1241
 
 
1242
 
    erts_mtx_lock(&mseg_mutex);
 
1371
    Uint n = 0;
 
1372
 
 
1373
    ERTS_MSEG_LOCK(ma);
 
1374
 
 
1375
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
1243
1376
 
1244
1377
    if (hpp || szp) {
1245
1378
        
1246
1379
        if (!atoms_initialized)
1247
 
            init_atoms();
 
1380
            init_atoms(ma);
1248
1381
 
1249
1382
        atoms[0] = am.version;
1250
1383
        atoms[1] = am.options;
1251
 
        atoms[2] = am.status;
1252
 
        atoms[3] = am.calls;
 
1384
        atoms[2] = am.memkind;
 
1385
        atoms[3] = am.memkind;
1253
1386
    }
1254
 
 
1255
 
    values[0] = info_version(print_to_p, print_to_arg, hpp, szp);
1256
 
    values[1] = info_options("option ", print_to_p, print_to_arg, hpp, szp);
1257
 
    values[2] = info_status(print_to_p, print_to_arg, begin_max_per, hpp, szp);
1258
 
    values[3] = info_calls(print_to_p, print_to_arg, hpp, szp);
1259
 
 
 
1387
    values[n++] = info_version(ma, print_to_p, print_to_arg, hpp, szp);
 
1388
    values[n++] = info_options(ma, "option ", print_to_p, print_to_arg, hpp, szp);
 
1389
#if HALFWORD_HEAP
 
1390
    values[n++] = info_memkind(ma, &ma->low_mem, print_to_p, print_to_arg, begin_max_per, hpp, szp);
 
1391
    values[n++] = info_memkind(ma, &ma->hi_mem, print_to_p, print_to_arg, begin_max_per, hpp, szp);
 
1392
#else
 
1393
    values[n++] = info_memkind(ma, &ma->the_mem, print_to_p, print_to_arg, begin_max_per, hpp, szp);
 
1394
#endif
1260
1395
    if (hpp || szp)
1261
 
        res = bld_2tup_list(hpp, szp, 4, atoms, values);
 
1396
        res = bld_2tup_list(hpp, szp, n, atoms, values);
1262
1397
 
1263
 
    erts_mtx_unlock(&mseg_mutex);
 
1398
    ERTS_MSEG_UNLOCK(ma);
1264
1399
 
1265
1400
    return res;
1266
1401
}
1268
1403
void *
1269
1404
erts_mseg_alloc_opt(ErtsAlcType_t atype, Uint *size_p, const ErtsMsegOpt_t *opt)
1270
1405
{
 
1406
    ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_OPT(opt);
1271
1407
    void *seg;
1272
 
    erts_mtx_lock(&mseg_mutex);
1273
 
    seg = mseg_alloc(atype, size_p, opt);
1274
 
    erts_mtx_unlock(&mseg_mutex);
 
1408
    ERTS_MSEG_LOCK(ma);
 
1409
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
 
1410
    seg = mseg_alloc(ma, atype, size_p, opt);
 
1411
    ERTS_MSEG_UNLOCK(ma);
1275
1412
    return seg;
1276
1413
}
1277
1414
 
1278
1415
void *
1279
1416
erts_mseg_alloc(ErtsAlcType_t atype, Uint *size_p)
1280
1417
{
1281
 
    return erts_mseg_alloc_opt(atype, size_p, &default_opt);
1282
 
}
1283
 
 
1284
 
void
1285
 
erts_mseg_dealloc_opt(ErtsAlcType_t atype, void *seg, Uint size,
 
1418
    return erts_mseg_alloc_opt(atype, size_p, &erts_mseg_default_opt);
 
1419
}
 
1420
 
 
1421
void
 
1422
erts_mseg_dealloc_opt(ErtsAlcType_t atype, void *seg,
 
1423
                      Uint size, const ErtsMsegOpt_t *opt)
 
1424
{
 
1425
    ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_OPT(opt);
 
1426
    ERTS_MSEG_LOCK(ma);
 
1427
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
 
1428
    mseg_dealloc(ma, atype, seg, size, opt);
 
1429
    ERTS_MSEG_UNLOCK(ma);
 
1430
}
 
1431
 
 
1432
void
 
1433
erts_mseg_dealloc(ErtsAlcType_t atype, void *seg, Uint size)
 
1434
{
 
1435
    erts_mseg_dealloc_opt(atype, seg, size, &erts_mseg_default_opt);
 
1436
}
 
1437
 
 
1438
void *
 
1439
erts_mseg_realloc_opt(ErtsAlcType_t atype, void *seg,
 
1440
                      Uint old_size, Uint *new_size_p,
1286
1441
                      const ErtsMsegOpt_t *opt)
1287
1442
{
1288
 
    erts_mtx_lock(&mseg_mutex);
1289
 
    mseg_dealloc(atype, seg, size, opt);
1290
 
    erts_mtx_unlock(&mseg_mutex);
1291
 
}
1292
 
 
1293
 
void
1294
 
erts_mseg_dealloc(ErtsAlcType_t atype, void *seg, Uint size)
1295
 
{
1296
 
    erts_mseg_dealloc_opt(atype, seg, size, &default_opt);
1297
 
}
1298
 
 
1299
 
void *
1300
 
erts_mseg_realloc_opt(ErtsAlcType_t atype, void *seg, Uint old_size,
1301
 
                      Uint *new_size_p, const ErtsMsegOpt_t *opt)
1302
 
{
 
1443
    ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_OPT(opt);
1303
1444
    void *new_seg;
1304
 
    erts_mtx_lock(&mseg_mutex);
1305
 
    new_seg = mseg_realloc(atype, seg, old_size, new_size_p, opt);
1306
 
    erts_mtx_unlock(&mseg_mutex);
 
1445
    ERTS_MSEG_LOCK(ma);
 
1446
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
 
1447
    new_seg = mseg_realloc(ma, atype, seg, old_size, new_size_p, opt);
 
1448
    ERTS_MSEG_UNLOCK(ma);
1307
1449
    return new_seg;
1308
1450
}
1309
1451
 
1310
1452
void *
1311
 
erts_mseg_realloc(ErtsAlcType_t atype, void *seg, Uint old_size,
1312
 
                  Uint *new_size_p)
 
1453
erts_mseg_realloc(ErtsAlcType_t atype, void *seg,
 
1454
                  Uint old_size, Uint *new_size_p)
1313
1455
{
1314
 
    return erts_mseg_realloc_opt(atype, seg, old_size, new_size_p, &default_opt);
 
1456
    return erts_mseg_realloc_opt(atype, seg, old_size, new_size_p,
 
1457
                                 &erts_mseg_default_opt);
1315
1458
}
1316
1459
 
1317
1460
void
1318
1461
erts_mseg_clear_cache(void)
1319
1462
{
1320
 
    erts_mtx_lock(&mseg_mutex);
1321
 
    mseg_clear_cache();
1322
 
    erts_mtx_unlock(&mseg_mutex);
 
1463
    ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_SS();
 
1464
    MemKind* mk;
 
1465
 
 
1466
start:
 
1467
 
 
1468
    ERTS_MSEG_LOCK(ma);
 
1469
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
 
1470
    for (mk=ma->mk_list; mk; mk=mk->next) {
 
1471
        mseg_clear_cache(mk);
 
1472
    }
 
1473
    ERTS_MSEG_UNLOCK(ma);
 
1474
 
 
1475
    if (ma->ix != 0) {
 
1476
        ma = ERTS_MSEG_ALLCTR_IX(0);
 
1477
        goto start;
 
1478
    }
1323
1479
}
1324
1480
 
1325
1481
Uint
1326
 
erts_mseg_no(void)
 
1482
erts_mseg_no(const ErtsMsegOpt_t *opt)
1327
1483
{
1328
 
    Uint n;
1329
 
    erts_mtx_lock(&mseg_mutex);
1330
 
    n = segments.current.no;
1331
 
    erts_mtx_unlock(&mseg_mutex);
 
1484
    ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_OPT(opt);
 
1485
    MemKind* mk;
 
1486
    Uint n = 0;
 
1487
    ERTS_MSEG_LOCK(ma);
 
1488
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
 
1489
    for (mk=ma->mk_list; mk; mk=mk->next) {
 
1490
        n += mk->segments.current.no;
 
1491
    }
 
1492
    ERTS_MSEG_UNLOCK(ma);
1332
1493
    return n;
1333
1494
}
1334
1495
 
1338
1499
    return page_size;
1339
1500
}
1340
1501
 
 
1502
static void mem_kind_init(ErtsMsegAllctr_t *ma, MemKind* mk, const char* name)
 
1503
{
 
1504
    unsigned i;
 
1505
 
 
1506
    mk->cache = NULL;
 
1507
    mk->cache_end = NULL;
 
1508
    mk->max_cached_seg_size = 0;
 
1509
    mk->min_cached_seg_size = ~((Uint) 0);
 
1510
    mk->cache_size = 0;
 
1511
    mk->cache_hits = 0;
 
1512
 
 
1513
    if (ma->max_cache_size > 0) {
 
1514
        for (i = 0; i < ma->max_cache_size - 1; i++)
 
1515
            mk->cache_descs[i].next = &mk->cache_descs[i + 1];
 
1516
        mk->cache_descs[ma->max_cache_size - 1].next = NULL;
 
1517
        mk->free_cache_descs = &mk->cache_descs[0];
 
1518
    }
 
1519
    else
 
1520
        mk->free_cache_descs = NULL;
 
1521
 
 
1522
    mk->segments.current.watermark = 0;
 
1523
    mk->segments.current.no = 0;
 
1524
    mk->segments.current.sz = 0;
 
1525
    mk->segments.max.no = 0;
 
1526
    mk->segments.max.sz = 0;
 
1527
    mk->segments.max_ever.no = 0;
 
1528
    mk->segments.max_ever.sz = 0;
 
1529
 
 
1530
    mk->ma = ma;
 
1531
    mk->name = name;
 
1532
    mk->next = ma->mk_list;
 
1533
    ma->mk_list = mk;
 
1534
}
 
1535
 
 
1536
 
 
1537
 
 
1538
 
1341
1539
void
1342
1540
erts_mseg_init(ErtsMsegInit_t *init)
1343
1541
{
1344
 
    unsigned i;
 
1542
    int i;
 
1543
    UWord x;
 
1544
 
 
1545
#ifdef ERTS_SMP
 
1546
    no_mseg_allocators = init->nos + 1;
 
1547
#else
 
1548
    no_mseg_allocators = 1;
 
1549
#endif
 
1550
 
 
1551
    x = (UWord) malloc(sizeof(ErtsAlgndMsegAllctr_t)
 
1552
                       *no_mseg_allocators
 
1553
                       + (ERTS_CACHE_LINE_SIZE-1));
 
1554
    if (x & ERTS_CACHE_LINE_MASK)
 
1555
        x = (x & ~ERTS_CACHE_LINE_MASK) + ERTS_CACHE_LINE_SIZE;
 
1556
    ASSERT((x & ERTS_CACHE_LINE_MASK) == 0);
 
1557
    aligned_mseg_allctr = (ErtsAlgndMsegAllctr_t *) x;
1345
1558
 
1346
1559
    atoms_initialized = 0;
1347
 
    is_init_done = 0;
1348
 
 
1349
 
    /* Options ... */
1350
 
 
1351
 
    abs_max_cache_bad_fit       = init->amcbf;
1352
 
    rel_max_cache_bad_fit       = init->rmcbf;
1353
 
    max_cache_size              = init->mcs;
1354
 
    cache_check_interval        = init->cci;
1355
 
 
1356
 
    /* */
1357
 
 
1358
 
#ifdef USE_THREADS
1359
 
    thread_safe_init();
1360
 
#endif
 
1560
 
 
1561
    erts_mtx_init(&init_atoms_mutex, "mseg_init_atoms");
1361
1562
 
1362
1563
#if HAVE_MMAP && !defined(MAP_ANON)
1363
1564
    mmap_fd = open("/dev/zero", O_RDWR);
1375
1576
    while ((page_size >> page_shift) != 1) {
1376
1577
        if ((page_size & (1 << (page_shift - 1))) != 0)
1377
1578
            erl_exit(ERTS_ABORT_EXIT,
1378
 
                     "erts_mseg: Unexpected page_size %bpu\n", page_size);
 
1579
                     "erts_mseg: Unexpected page_size %beu\n", page_size);
1379
1580
        page_shift++;
1380
1581
    }
1381
1582
 
1382
 
    sys_memzero((void *) &calls, sizeof(calls));
 
1583
    for (i = 0; i < no_mseg_allocators; i++) {
 
1584
        ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(i);
 
1585
 
 
1586
        ma->ix = i;
 
1587
 
 
1588
        ma->is_init_done = 0;
 
1589
 
 
1590
        if (i != 0)
 
1591
            ma->is_thread_safe = 0;
 
1592
        else {
 
1593
            ma->is_thread_safe = 1;
 
1594
            erts_mtx_init(&ma->mtx, "mseg");
 
1595
        }
 
1596
 
 
1597
        ma->is_cache_check_scheduled = 0;
 
1598
 
 
1599
        /* Options ... */
 
1600
 
 
1601
        ma->abs_max_cache_bad_fit = init->amcbf;
 
1602
        ma->rel_max_cache_bad_fit = init->rmcbf;
 
1603
        ma->max_cache_size = init->mcs;
 
1604
 
 
1605
        if (ma->max_cache_size > MAX_CACHE_SIZE)
 
1606
            ma->max_cache_size = MAX_CACHE_SIZE;
 
1607
 
 
1608
        ma->mk_list = NULL;
 
1609
 
 
1610
#if HALFWORD_HEAP
 
1611
        mem_kind_init(ma, &ma->low_mem, "low memory");
 
1612
        mem_kind_init(ma, &ma->hi_mem, "high memory");
 
1613
#else
 
1614
        mem_kind_init(ma, &ma->the_mem, "all memory");
 
1615
#endif
 
1616
 
 
1617
        sys_memzero((void *) &ma->calls, sizeof(ErtsMsegCalls));
1383
1618
 
1384
1619
#if CAN_PARTLY_DESTROY
1385
 
    min_seg_size = ~((Uint) 0);
1386
 
#endif
1387
 
 
1388
 
    cache = NULL;
1389
 
    cache_end = NULL;
1390
 
    cache_hits = 0;
1391
 
    max_cached_seg_size = 0;
1392
 
    min_cached_seg_size = ~((Uint) 0);
1393
 
    cache_size = 0;
1394
 
 
1395
 
    is_cache_check_scheduled = 0;
1396
 
#ifdef ERTS_THREADS_NO_SMP
1397
 
    is_cache_check_requested = 0;
1398
 
#endif
1399
 
 
1400
 
    if (max_cache_size > MAX_CACHE_SIZE)
1401
 
        max_cache_size = MAX_CACHE_SIZE;
1402
 
 
1403
 
    if (max_cache_size > 0) {
1404
 
        for (i = 0; i < max_cache_size - 1; i++)
1405
 
            cache_descs[i].next = &cache_descs[i + 1];
1406
 
        cache_descs[max_cache_size - 1].next = NULL;
1407
 
        free_cache_descs = &cache_descs[0];
1408
 
    }
1409
 
    else
1410
 
        free_cache_descs = NULL;
1411
 
 
1412
 
    segments.current.watermark = 0;
1413
 
    segments.current.no = 0;
1414
 
    segments.current.sz = 0;
1415
 
    segments.max.no = 0;
1416
 
    segments.max.sz = 0;
1417
 
    segments.max_ever.no = 0;
1418
 
    segments.max_ever.sz = 0;
1419
 
}
1420
 
 
 
1620
        ma->min_seg_size = ~((Uint) 0);
 
1621
#endif
 
1622
    }
 
1623
}
 
1624
 
 
1625
 
 
1626
static ERTS_INLINE Uint tot_cache_size(ErtsMsegAllctr_t *ma)
 
1627
{
 
1628
    MemKind* mk;
 
1629
    Uint sz = 0;
 
1630
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
 
1631
    for (mk=ma->mk_list; mk; mk=mk->next) {
 
1632
        sz += mk->cache_size;
 
1633
    }
 
1634
    return sz;
 
1635
}
1421
1636
 
1422
1637
/*
1423
1638
 * erts_mseg_late_init() have to be called after all allocators,
1426
1641
void
1427
1642
erts_mseg_late_init(void)
1428
1643
{
1429
 
#ifdef ERTS_THREADS_NO_SMP
1430
 
    int handle =
1431
 
        erts_register_async_ready_callback(
1432
 
            check_schedule_cache_check);
1433
 
#endif
1434
 
    erts_mtx_lock(&mseg_mutex);
1435
 
    is_init_done = 1;
1436
 
#ifdef ERTS_THREADS_NO_SMP
1437
 
    async_handle = handle;
1438
 
#endif
1439
 
    if (cache_size)
1440
 
        schedule_cache_check();
1441
 
    erts_mtx_unlock(&mseg_mutex);
1442
 
}
1443
 
 
1444
 
void
1445
 
erts_mseg_exit(void)
1446
 
{
1447
 
    mseg_shutdown();
 
1644
    ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_SS();
 
1645
    ERTS_MSEG_LOCK(ma);
 
1646
    ERTS_DBG_MA_CHK_THR_ACCESS(ma);
 
1647
    ma->is_init_done = 1;
 
1648
    if (tot_cache_size(ma))
 
1649
        schedule_cache_check(ma);
 
1650
    ERTS_MSEG_UNLOCK(ma);
1448
1651
}
1449
1652
 
1450
1653
#endif /* #if HAVE_ERTS_MSEG */
1473
1676
        erts_mseg_clear_cache();
1474
1677
        return (unsigned long) 0;
1475
1678
    case 0x405:
1476
 
        return (unsigned long) erts_mseg_no();
 
1679
        return (unsigned long) erts_mseg_no(&erts_mseg_default_opt);
1477
1680
    case 0x406: {
 
1681
        ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(0);
1478
1682
        unsigned long res;
1479
 
        erts_mtx_lock(&mseg_mutex);
1480
 
        res = (unsigned long) cache_size;
1481
 
        erts_mtx_unlock(&mseg_mutex);
 
1683
        ERTS_MSEG_LOCK(ma);
 
1684
        res = (unsigned long) tot_cache_size(ma);
 
1685
        ERTS_MSEG_UNLOCK(ma);
1482
1686
        return res;
1483
1687
    }
1484
1688
#else /* #if HAVE_ERTS_MSEG */
1568
1772
        return NULL;
1569
1773
    }
1570
1774
 
1571
 
 
 
1775
#if HAVE_MMAP
1572
1776
    res = mmap(ptr, sz,
1573
1777
               PROT_READ | PROT_WRITE, MAP_PRIVATE |
1574
1778
               MAP_ANONYMOUS | MAP_FIXED,
1575
1779
               -1 , 0);
 
1780
#else
 
1781
#  error "Missing mmap support"
 
1782
#endif
1576
1783
 
1577
1784
    if (res == MAP_FAILED) {
1578
1785
#ifdef HARDDEBUG
1672
1879
                MAP_NORESERVE | EXTRA_MAP_FLAGS,
1673
1880
                -1 , 0);
1674
1881
#ifdef HARDDEBUG
1675
 
    printf("rsz = %ld, pages = %ld, rptr = %p\r\n",
1676
 
           (unsigned long) rsz, (unsigned long) (rsz / pagsz),
1677
 
           (void *) rptr);
1678
 
#endif
 
1882
    printf("p=%p, rsz = %ld, pages = %ld, got range = %p -> %p\r\n",
 
1883
           p, (unsigned long) rsz, (unsigned long) (rsz / pagsz),
 
1884
           (void *) rptr, (void*)(rptr + rsz));
 
1885
#endif
 
1886
    if ((UWord)(rptr + rsz) > RANGE_MAX) {
 
1887
        size_t rsz_trunc = RANGE_MAX - (UWord)rptr;
 
1888
#ifdef HARDDEBUG
 
1889
        printf("Reducing mmap'ed memory from %lu to %lu Mb, reduced range = %p -> %p\r\n",
 
1890
                rsz/(1024*1024), rsz_trunc/(1024*1024), rptr, rptr+rsz_trunc);
 
1891
#endif
 
1892
        munmap((void*)RANGE_MAX, rsz - rsz_trunc);
 
1893
        rsz = rsz_trunc;
 
1894
    }
1679
1895
    if (!do_map(rptr,pagsz)) {
1680
1896
        erl_exit(1,"Could not actually mmap first page for halfword emulator...\n");
1681
1897
    }
1756
1972
    FreeBlock *last;
1757
1973
    FreeBlock *nb = (FreeBlock *) p;
1758
1974
 
 
1975
    ASSERT(((unsigned long)p & CHECK_POINTER_MASK)==0);
1759
1976
    if (real_size > pagsz) {
1760
1977
        if (do_unmap(((char *) p) + pagsz,real_size - pagsz)) {
1761
1978
            return 1;