/*
* %CopyrightBegin%
*
* Copyright Ericsson AB 2002-2009. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* %CopyrightEnd%
*/
#ifndef ERL_ALLOC_UTIL__
#define ERL_ALLOC_UTIL__
#define ERTS_ALCU_VSN_STR "2.2"
#include "erl_alloc_types.h"
typedef struct Allctr_t_ Allctr_t;
typedef struct {
UWord ycs;
UWord mmc;
} AlcUInit_t;
typedef struct {
char *name_prefix;
ErtsAlcType_t alloc_no;
int ts;
int tspec;
int tpref;
int ramv;
UWord sbct;
UWord asbcst;
UWord rsbcst;
UWord rsbcmt;
UWord rmbcmt;
UWord mmbcs;
UWord mmsbc;
UWord mmmbc;
UWord lmbcs;
UWord smbcs;
UWord mbcgs;
} AllctrInit_t;
typedef struct {
UWord blocks;
UWord carriers;
} AllctrSize_t;
#ifndef SMALL_MEMORY
#define ERTS_DEFAULT_ALCU_INIT { \
1024*1024, /* (bytes) ycs: sys_alloc carrier size */\
1024 /* (amount) mmc: max mseg carriers */\
}
#define ERTS_DEFAULT_ALLCTR_INIT { \
NULL, \
ERTS_ALC_A_INVALID, /* (number) alloc_no: allocator number */\
1, /* (bool) ts: thread safe */\
0, /* (bool) tspec: thread specific */\
0, /* (bool) tpref: thread preferred */\
0, /* (bool) ramv: realloc always moves */\
512*1024, /* (bytes) sbct: sbc threshold */\
2*1024*2024, /* (amount) asbcst: abs sbc shrink threshold */\
20, /* (%) rsbcst: rel sbc shrink threshold */\
80, /* (%) rsbcmt: rel sbc move threshold */\
50, /* (%) rmbcmt: rel mbc move threshold */\
1024*1024, /* (bytes) mmbcs: main multiblock carrier size */\
256, /* (amount) mmsbc: max mseg sbcs */\
10, /* (amount) mmmbc: max mseg mbcs */\
10*1024*1024, /* (bytes) lmbcs: largest mbc size */\
1024*1024, /* (bytes) smbcs: smallest mbc size */\
10 /* (amount) mbcgs: mbc growth stages */\
}
#else /* if SMALL_MEMORY */
#define ERTS_DEFAULT_ALCU_INIT { \
128*1024, /* (bytes) ycs: sys_alloc carrier size */\
1024 /* (amount) mmc: max mseg carriers */\
}
#define ERTS_DEFAULT_ALLCTR_INIT { \
NULL, \
ERTS_ALC_A_INVALID, /* (number) alloc_no: allocator number */\
1, /* (bool) ts: thread safe */\
0, /* (bool) tspec: thread specific */\
0, /* (bool) tpref: thread preferred */\
0, /* (bool) ramv: realloc always moves */\
64*1024, /* (bytes) sbct: sbc threshold */\
2*1024*2024, /* (amount) asbcst: abs sbc shrink threshold */\
20, /* (%) rsbcst: rel sbc shrink threshold */\
80, /* (%) rsbcmt: rel sbc move threshold */\
128*1024, /* (bytes) mmbcs: main multiblock carrier size */\
256, /* (amount) mmsbc: max mseg sbcs */\
10, /* (amount) mmmbc: max mseg mbcs */\
1024*1024, /* (bytes) lmbcs: largest mbc size */\
128*1024, /* (bytes) smbcs: smallest mbc size */\
10 /* (amount) mbcgs: mbc growth stages */\
}
#endif
void * erts_alcu_alloc(ErtsAlcType_t, void *, Uint);
void * erts_alcu_realloc(ErtsAlcType_t, void *, void *, Uint);
void * erts_alcu_realloc_mv(ErtsAlcType_t, void *, void *, Uint);
void erts_alcu_free(ErtsAlcType_t, void *, void *);
#ifdef USE_THREADS
void * erts_alcu_alloc_ts(ErtsAlcType_t, void *, Uint);
void * erts_alcu_realloc_ts(ErtsAlcType_t, void *, void *, Uint);
void * erts_alcu_realloc_mv_ts(ErtsAlcType_t, void *, void *, Uint);
void erts_alcu_free_ts(ErtsAlcType_t, void *, void *);
void * erts_alcu_alloc_thr_spec(ErtsAlcType_t, void *, Uint);
void * erts_alcu_realloc_thr_spec(ErtsAlcType_t, void *, void *, Uint);
void * erts_alcu_realloc_mv_thr_spec(ErtsAlcType_t, void *, void *, Uint);
void erts_alcu_free_thr_spec(ErtsAlcType_t, void *, void *);
void * erts_alcu_alloc_thr_pref(ErtsAlcType_t, void *, Uint);
void * erts_alcu_realloc_thr_pref(ErtsAlcType_t, void *, void *, Uint);
void * erts_alcu_realloc_mv_thr_pref(ErtsAlcType_t, void *, void *, Uint);
void erts_alcu_free_thr_pref(ErtsAlcType_t, void *, void *);
#endif
Eterm erts_alcu_au_info_options(int *, void *, Uint **, Uint *);
Eterm erts_alcu_info_options(Allctr_t *, int *, void *, Uint **, Uint *);
Eterm erts_alcu_sz_info(Allctr_t *, int, int *, void *, Uint **, Uint *);
Eterm erts_alcu_info(Allctr_t *, int, int *, void *, Uint **, Uint *);
void erts_alcu_init(AlcUInit_t *);
void erts_alcu_current_size(Allctr_t *, AllctrSize_t *);
#endif
#if defined(GET_ERL_ALLOC_UTIL_IMPL) && !defined(ERL_ALLOC_UTIL_IMPL__)
#define ERL_ALLOC_UTIL_IMPL__
#ifdef USE_THREADS
#define ERL_THREADS_EMU_INTERNAL__
#include "erl_threads.h"
#endif
#include "erl_mseg.h"
#undef ERTS_ALLOC_UTIL_HARD_DEBUG
#ifdef DEBUG
# if 1
# define ERTS_ALLOC_UTIL_HARD_DEBUG
# endif
#endif
#undef MIN
#undef MAX
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define FLOOR(X, I) (((X)/(I))*(I))
#define CEILING(X, I) ((((X) - 1)/(I) + 1)*(I))
#undef WORD_MASK
#define INV_WORD_MASK ((UWord) (sizeof(UWord) - 1))
#define WORD_MASK (~INV_WORD_MASK)
#define WORD_FLOOR(X) ((X) & WORD_MASK)
#define WORD_CEILING(X) WORD_FLOOR((X) + INV_WORD_MASK)
#undef UNIT_MASK
#define INV_UNIT_MASK ((UWord) (sizeof(Unit_t) - 1))
#define UNIT_MASK (~INV_UNIT_MASK)
#define UNIT_FLOOR(X) ((X) & UNIT_MASK)
#define UNIT_CEILING(X) UNIT_FLOOR((X) + INV_UNIT_MASK)
#define SZ_MASK (~((UWord) 0) << 3)
#define FLG_MASK (~(SZ_MASK))
#define BLK_SZ(B) \
(*((Block_t *) (B)) & SZ_MASK)
#define CARRIER_SZ(C) \
((C)->chdr & SZ_MASK)
typedef union {char c[8]; long l; double d;} Unit_t;
typedef struct Carrier_t_ Carrier_t;
struct Carrier_t_ {
UWord chdr;
Carrier_t *next;
Carrier_t *prev;
};
typedef struct {
Carrier_t *first;
Carrier_t *last;
} CarrierList_t;
typedef UWord Block_t;
typedef UWord FreeBlkFtr_t;
typedef struct {
UWord giga_no;
UWord no;
} CallCounter_t;
typedef struct {
UWord no;
UWord size;
} StatValues_t;
typedef struct {
StatValues_t curr_mseg;
StatValues_t curr_sys_alloc;
StatValues_t max;
StatValues_t max_ever;
struct {
StatValues_t curr;
StatValues_t max;
StatValues_t max_ever;
} blocks;
} CarriersStats_t;
struct Allctr_t_ {
/* Allocator name prefix */
char * name_prefix;
/* Allocator number */
ErtsAlcType_t alloc_no;
/* Alloc, realloc and free names as atoms */
struct {
Eterm alloc;
Eterm realloc;
Eterm free;
} name;
/* Version string */
char * vsn_str;
/* Options */
int t;
int ramv;
Uint sbc_threshold;
Uint sbc_move_threshold;
Uint mbc_move_threshold;
Uint main_carrier_size;
Uint max_mseg_sbcs;
Uint max_mseg_mbcs;
Uint largest_mbc_size;
Uint smallest_mbc_size;
Uint mbc_growth_stages;
#if HAVE_ERTS_MSEG
ErtsMsegOpt_t mseg_opt;
#endif
/* */
Uint mbc_header_size;
Uint sbc_header_size;
Uint min_mbc_size;
Uint min_mbc_first_free_size;
Uint min_block_size;
/* Carriers */
CarrierList_t mbc_list;
CarrierList_t sbc_list;
/* Main carrier (if there is one) */
Carrier_t * main_carrier;
/* Callback functions (first 4 are mandatory) */
Block_t * (*get_free_block) (Allctr_t *, Uint,
Block_t *, Uint);
void (*link_free_block) (Allctr_t *, Block_t *);
void (*unlink_free_block) (Allctr_t *, Block_t *);
Eterm (*info_options) (Allctr_t *, char *, int *,
void *, Uint **, Uint *);
Uint (*get_next_mbc_size) (Allctr_t *);
void (*creating_mbc) (Allctr_t *, Carrier_t *);
void (*destroying_mbc) (Allctr_t *, Carrier_t *);
void (*init_atoms) (void);
#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
void (*check_block) (Allctr_t *, Block_t *, int);
void (*check_mbc) (Allctr_t *, Carrier_t *);
#endif
#ifdef USE_THREADS
/* Mutex for this allocator */
erts_mtx_t mutex;
int thread_safe;
struct {
Allctr_t *prev;
Allctr_t *next;
} ts_list;
#endif
int atoms_initialized;
int stopped;
/* Some statistics ... */
struct {
CallCounter_t this_alloc;
CallCounter_t this_free;
CallCounter_t this_realloc;
CallCounter_t mseg_alloc;
CallCounter_t mseg_dealloc;
CallCounter_t mseg_realloc;
CallCounter_t sys_alloc;
CallCounter_t sys_free;
CallCounter_t sys_realloc;
} calls;
CarriersStats_t sbcs;
CarriersStats_t mbcs;
#ifdef DEBUG
#ifdef USE_THREADS
struct {
int saved_tid;
erts_tid_t tid;
} debug;
#endif
#endif
};
int erts_alcu_start(Allctr_t *, AllctrInit_t *);
void erts_alcu_stop(Allctr_t *);
unsigned long erts_alcu_test(unsigned long, unsigned long, unsigned long);
#endif /* #if defined(GET_ERL_ALLOC_UTIL_IMPL)
&& !defined(ERL_ALLOC_UTIL_IMPL__) */