diff options
-rw-r--r-- | erts/emulator/beam/erl_alloc_util.c | 1204 | ||||
-rw-r--r-- | erts/emulator/beam/erl_alloc_util.h | 43 | ||||
-rw-r--r-- | erts/emulator/test/alloc_SUITE.erl | 79 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 21 | ||||
-rw-r--r-- | erts/emulator/test/send_term_SUITE.erl | 24 | ||||
-rwxr-xr-x | erts/emulator/utils/make_alloc_types | 3 | ||||
-rw-r--r-- | erts/preloaded/ebin/erlang.beam | bin | 108564 -> 108508 bytes | |||
-rw-r--r-- | erts/preloaded/src/erlang.erl | 58 | ||||
-rw-r--r-- | lib/kernel/src/erts_debug.erl | 53 | ||||
-rw-r--r-- | lib/observer/src/observer_alloc_wx.erl | 21 | ||||
-rw-r--r-- | lib/runtime_tools/src/erts_alloc_config.erl | 25 | ||||
-rw-r--r-- | lib/runtime_tools/src/runtime_tools.app.src | 2 | ||||
-rw-r--r-- | lib/tools/doc/src/instrument.xml | 10 | ||||
-rw-r--r-- | lib/tools/src/instrument.erl | 7 | ||||
-rw-r--r-- | lib/tools/src/tools.app.src | 2 | ||||
-rw-r--r-- | lib/tools/test/instrument_SUITE.erl | 22 |
16 files changed, 889 insertions, 685 deletions
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index bfc2f5992c..8123f99375 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -481,244 +481,265 @@ static void check_blk_carrier(Allctr_t *, Block_t *); /* Statistics updating ... */ #ifdef DEBUG -#define DEBUG_CHECK_CARRIER_NO_SZ(AP) \ - ASSERT(((AP)->sbcs.curr.norm.mseg.no \ - && (AP)->sbcs.curr.norm.mseg.size) \ - || (!(AP)->sbcs.curr.norm.mseg.no \ - && !(AP)->sbcs.curr.norm.mseg.size)); \ - ASSERT(((AP)->sbcs.curr.norm.sys_alloc.no \ - && (AP)->sbcs.curr.norm.sys_alloc.size) \ - || (!(AP)->sbcs.curr.norm.sys_alloc.no \ - && !(AP)->sbcs.curr.norm.sys_alloc.size)); \ - ASSERT(((AP)->mbcs.curr.norm.mseg.no \ - && (AP)->mbcs.curr.norm.mseg.size) \ - || (!(AP)->mbcs.curr.norm.mseg.no \ - && !(AP)->mbcs.curr.norm.mseg.size)); \ - ASSERT(((AP)->mbcs.curr.norm.sys_alloc.no \ - && (AP)->mbcs.curr.norm.sys_alloc.size) \ - || (!(AP)->mbcs.curr.norm.sys_alloc.no \ - && !(AP)->mbcs.curr.norm.sys_alloc.size)); + +#define DEBUG_CHECK_CARRIER_NO_SZ_1(CSTATS) \ + do { \ + int ix__; \ + for (ix__ = ERTS_CRR_ALLOC_MIN; ix__ <= ERTS_CRR_ALLOC_MAX; ix__++) { \ + UWord no__ = (CSTATS)->carriers[ix__].no; \ + UWord size__= (CSTATS)->carriers[ix__].size; \ + ASSERT((no__ > 0 && size__ > 0) || (no__ == 0 && size__ == 0)); \ + } \ + } while (0) + +#define DEBUG_CHECK_CARRIER_NO_SZ(AP) \ + do { \ + DEBUG_CHECK_CARRIER_NO_SZ_1(&(AP)->sbcs); \ + DEBUG_CHECK_CARRIER_NO_SZ_1(&(AP)->mbcs); \ + } while (0) #else #define DEBUG_CHECK_CARRIER_NO_SZ(AP) #endif -#define STAT_SBC_ALLOC(AP, BSZ) \ - (AP)->sbcs.blocks.curr.size += (BSZ); \ - if ((AP)->sbcs.blocks.max.size < (AP)->sbcs.blocks.curr.size) \ - (AP)->sbcs.blocks.max.size = (AP)->sbcs.blocks.curr.size; \ - if ((AP)->sbcs.max.no < ((AP)->sbcs.curr.norm.mseg.no \ - + (AP)->sbcs.curr.norm.sys_alloc.no)) \ - (AP)->sbcs.max.no = ((AP)->sbcs.curr.norm.mseg.no \ - + (AP)->sbcs.curr.norm.sys_alloc.no); \ - if ((AP)->sbcs.max.size < ((AP)->sbcs.curr.norm.mseg.size \ - + (AP)->sbcs.curr.norm.sys_alloc.size)) \ - (AP)->sbcs.max.size = ((AP)->sbcs.curr.norm.mseg.size \ - + (AP)->sbcs.curr.norm.sys_alloc.size) - -#define STAT_MSEG_SBC_ALLOC(AP, CSZ, BSZ) \ -do { \ - (AP)->sbcs.curr.norm.mseg.no++; \ - (AP)->sbcs.curr.norm.mseg.size += (CSZ); \ - STAT_SBC_ALLOC((AP), (BSZ)); \ - DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ -} while (0) - -#define STAT_SYS_ALLOC_SBC_ALLOC(AP, CSZ, BSZ) \ -do { \ - (AP)->sbcs.curr.norm.sys_alloc.no++; \ - (AP)->sbcs.curr.norm.sys_alloc.size += (CSZ); \ - STAT_SBC_ALLOC((AP), (BSZ)); \ - DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ -} while (0) - - -#define STAT_SBC_FREE(AP, BSZ) \ - ASSERT((AP)->sbcs.blocks.curr.size >= (BSZ)); \ - (AP)->sbcs.blocks.curr.size -= (BSZ) - -#define STAT_MSEG_SBC_FREE(AP, CSZ, BSZ) \ -do { \ - ASSERT((AP)->sbcs.curr.norm.mseg.no > 0); \ - (AP)->sbcs.curr.norm.mseg.no--; \ - ASSERT((AP)->sbcs.curr.norm.mseg.size >= (CSZ)); \ - (AP)->sbcs.curr.norm.mseg.size -= (CSZ); \ - STAT_SBC_FREE((AP), (BSZ)); \ - DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ -} while (0) - -#define STAT_SYS_ALLOC_SBC_FREE(AP, CSZ, BSZ) \ -do { \ - ASSERT((AP)->sbcs.curr.norm.sys_alloc.no > 0); \ - (AP)->sbcs.curr.norm.sys_alloc.no--; \ - ASSERT((AP)->sbcs.curr.norm.sys_alloc.size >= (CSZ)); \ - (AP)->sbcs.curr.norm.sys_alloc.size -= (CSZ); \ - STAT_SBC_FREE((AP), (BSZ)); \ - DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ -} while (0) - -#define STAT_MBC_ALLOC(AP) \ - if ((AP)->mbcs.max.no < ((AP)->mbcs.curr.norm.mseg.no \ - + (AP)->mbcs.curr.norm.sys_alloc.no)) \ - (AP)->mbcs.max.no = ((AP)->mbcs.curr.norm.mseg.no \ - + (AP)->mbcs.curr.norm.sys_alloc.no); \ - if ((AP)->mbcs.max.size < ((AP)->mbcs.curr.norm.mseg.size \ - + (AP)->mbcs.curr.norm.sys_alloc.size)) \ - (AP)->mbcs.max.size = ((AP)->mbcs.curr.norm.mseg.size \ - + (AP)->mbcs.curr.norm.sys_alloc.size) - - -#define STAT_MSEG_MBC_ALLOC(AP, CSZ) \ -do { \ - (AP)->mbcs.curr.norm.mseg.no++; \ - (AP)->mbcs.curr.norm.mseg.size += (CSZ); \ - STAT_MBC_ALLOC((AP)); \ - DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ -} while (0) - -#define STAT_SYS_ALLOC_MBC_ALLOC(AP, CSZ) \ -do { \ - (AP)->mbcs.curr.norm.sys_alloc.no++; \ - (AP)->mbcs.curr.norm.sys_alloc.size += (CSZ); \ - STAT_MBC_ALLOC((AP)); \ - DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ -} while (0) - -#define STAT_MBC_CPOOL_FETCH(AP, CRR) \ -do { \ - UWord csz__ = CARRIER_SZ((CRR)); \ - if (IS_MSEG_CARRIER((CRR))) \ - STAT_MSEG_MBC_ALLOC((AP), csz__); \ - else \ - STAT_SYS_ALLOC_MBC_ALLOC((AP), csz__); \ - set_new_allctr_abandon_limit(AP); \ - (AP)->mbcs.blocks.curr.no += (CRR)->cpool.blocks[(AP)->alloc_no]; \ - if ((AP)->mbcs.blocks.max.no < (AP)->mbcs.blocks.curr.no) \ - (AP)->mbcs.blocks.max.no = (AP)->mbcs.blocks.curr.no; \ - (AP)->mbcs.blocks.curr.size += \ - (CRR)->cpool.blocks_size[(AP)->alloc_no]; \ - if ((AP)->mbcs.blocks.max.size < (AP)->mbcs.blocks.curr.size) \ - (AP)->mbcs.blocks.max.size = (AP)->mbcs.blocks.curr.size; \ -} while (0) - -#define STAT_MSEG_MBC_FREE(AP, CSZ) \ -do { \ - ASSERT((AP)->mbcs.curr.norm.mseg.no > 0); \ - (AP)->mbcs.curr.norm.mseg.no--; \ - ASSERT((AP)->mbcs.curr.norm.mseg.size >= (CSZ)); \ - (AP)->mbcs.curr.norm.mseg.size -= (CSZ); \ - DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ -} while (0) - -#define STAT_SYS_ALLOC_MBC_FREE(AP, CSZ) \ -do { \ - ASSERT((AP)->mbcs.curr.norm.sys_alloc.no > 0); \ - (AP)->mbcs.curr.norm.sys_alloc.no--; \ - ASSERT((AP)->mbcs.curr.norm.sys_alloc.size >= (CSZ)); \ - (AP)->mbcs.curr.norm.sys_alloc.size -= (CSZ); \ - DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ -} while (0) - -#define STAT_MBC_FREE(AP, CRR) \ -do { \ - UWord csz__ = CARRIER_SZ((CRR)); \ - if (IS_MSEG_CARRIER((CRR))) { \ - STAT_MSEG_MBC_FREE((AP), csz__); \ - } else { \ - STAT_SYS_ALLOC_MBC_FREE((AP), csz__); \ - } \ - set_new_allctr_abandon_limit(AP); \ -} while (0) - -#define STAT_MBC_ABANDON(AP, CRR) \ -do { \ - STAT_MBC_FREE(AP, CRR); \ - ERTS_ALC_CPOOL_ASSERT((AP)->mbcs.blocks.curr.no \ - >= (CRR)->cpool.blocks[(AP)->alloc_no]); \ - (AP)->mbcs.blocks.curr.no -= (CRR)->cpool.blocks[(AP)->alloc_no]; \ - ERTS_ALC_CPOOL_ASSERT((AP)->mbcs.blocks.curr.size \ - >= (CRR)->cpool.blocks_size[(AP)->alloc_no]); \ - (AP)->mbcs.blocks.curr.size -= (CRR)->cpool.blocks_size[(AP)->alloc_no]; \ -} while (0) - -#define STAT_MBC_BLK_ALLOC_CRR(AP, CRR, BSZ) \ -do { \ - (CRR)->cpool.blocks[(AP)->alloc_no]++; \ - (CRR)->cpool.blocks_size[(AP)->alloc_no] += (BSZ); \ - (CRR)->cpool.total_blocks_size += (BSZ); \ -} while (0) - -#define STAT_MBC_BLK_ALLOC(AP, CRR, BSZ, FLGS) \ -do { \ - CarriersStats_t *cstats__ = &(AP)->mbcs; \ - cstats__->blocks.curr.no++; \ - if (cstats__->blocks.max.no < cstats__->blocks.curr.no) \ - cstats__->blocks.max.no = cstats__->blocks.curr.no; \ - cstats__->blocks.curr.size += (BSZ); \ - if (cstats__->blocks.max.size < cstats__->blocks.curr.size) \ - cstats__->blocks.max.size = cstats__->blocks.curr.size; \ - STAT_MBC_BLK_ALLOC_CRR((AP), (CRR), (BSZ)); \ -} while (0) +/* Carrier statistics */ + +#define STAT_CRR_UPDATED_1(CSTATS) \ + do { \ + UWord no_sum__, size_sum__; \ + int i__; \ + no_sum__ = size_sum__ = 0; \ + for (i__ = ERTS_CRR_ALLOC_MIN; i__ <= ERTS_CRR_ALLOC_MAX; i__++) { \ + ASSERT(ERTS_UWORD_MAX - no_sum__ > (CSTATS)->carriers[i__].no); \ + ASSERT(ERTS_UWORD_MAX - size_sum__ > (CSTATS)->carriers[i__].size); \ + no_sum__ += (CSTATS)->carriers[i__].no; \ + size_sum__ += (CSTATS)->carriers[i__].size; \ + } \ + if ((CSTATS)->max.no < no_sum__) { \ + (CSTATS)->max.no = no_sum__; \ + } \ + if ((CSTATS)->max.size < size_sum__) { \ + (CSTATS)->max.size = size_sum__; \ + } \ + } while (0) + +#define STAT_CRR_ALLOC_1(TYPE, CSTATS, SIZE) \ + do { \ + ASSERT(ERTS_UWORD_MAX - (CSTATS)->carriers[(TYPE)].no > 1); \ + ASSERT(ERTS_UWORD_MAX - (CSTATS)->carriers[(TYPE)].size > (SIZE)); \ + (CSTATS)->carriers[(TYPE)].no += 1; \ + (CSTATS)->carriers[(TYPE)].size += (SIZE); \ + STAT_CRR_UPDATED_1(CSTATS); \ + } while (0) + +#define STAT_CRR_FREE_1(TYPE, CSTATS, SIZE) \ + do { \ + ASSERT((CSTATS)->carriers[(TYPE)].no >= 1); \ + ASSERT((CSTATS)->carriers[(TYPE)].size >= (SIZE)); \ + (CSTATS)->carriers[(TYPE)].no -= 1; \ + (CSTATS)->carriers[(TYPE)].size -= (SIZE); \ + STAT_CRR_UPDATED_1(CSTATS); \ + } while (0) + +#define STAT_MSEG_SBC_ALLOC(AP, CSZ, BSZ) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->sbcs; \ + STAT_CRR_ALLOC_1(ERTS_CRR_ALLOC_MSEG, cstats__, CSZ); \ + STAT_BLK_ALLOC_1(cstats__, (AP)->alloc_no, 1, (BSZ)); \ + DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ + } while (0) + +#define STAT_SYS_ALLOC_SBC_ALLOC(AP, CSZ, BSZ) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->sbcs; \ + STAT_CRR_ALLOC_1(ERTS_CRR_ALLOC_SYS, cstats__, CSZ); \ + STAT_BLK_ALLOC_1(cstats__, (AP)->alloc_no, 1, (BSZ)); \ + DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ + } while (0) + +#define STAT_MSEG_SBC_FREE(AP, CSZ, BSZ) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->sbcs; \ + STAT_CRR_FREE_1(ERTS_CRR_ALLOC_MSEG, cstats__, CSZ); \ + STAT_BLK_FREE_1(cstats__, (AP)->alloc_no, 1, (BSZ)); \ + DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ + } while (0) + +#define STAT_SYS_ALLOC_SBC_FREE(AP, CSZ, BSZ) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->sbcs; \ + STAT_CRR_FREE_1(ERTS_CRR_ALLOC_SYS, cstats__, CSZ); \ + STAT_BLK_FREE_1(cstats__, (AP)->alloc_no, 1, (BSZ)); \ + DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ + } while (0) + +#define STAT_MSEG_MBC_ALLOC(AP, CSZ) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->mbcs; \ + STAT_CRR_ALLOC_1(ERTS_CRR_ALLOC_MSEG, cstats__, CSZ); \ + DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ + } while (0) + +#define STAT_SYS_ALLOC_MBC_ALLOC(AP, CSZ) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->mbcs; \ + STAT_CRR_ALLOC_1(ERTS_CRR_ALLOC_SYS, cstats__, CSZ); \ + DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ + } while (0) + +#define STAT_MSEG_MBC_FREE(AP, CSZ) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->mbcs; \ + STAT_CRR_FREE_1(ERTS_CRR_ALLOC_MSEG, cstats__, CSZ); \ + DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ + } while (0) + +#define STAT_SYS_ALLOC_MBC_FREE(AP, CSZ) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->mbcs; \ + STAT_CRR_FREE_1(ERTS_CRR_ALLOC_SYS, cstats__, CSZ); \ + DEBUG_CHECK_CARRIER_NO_SZ((AP)); \ + } while (0) + +#define STAT_MBC_FREE(AP, CRR) \ + do { \ + UWord csz__ = CARRIER_SZ((CRR)); \ + if (IS_MSEG_CARRIER((CRR))) { \ + STAT_MSEG_MBC_FREE((AP), csz__); \ + } else { \ + STAT_SYS_ALLOC_MBC_FREE((AP), csz__); \ + } \ + set_new_allctr_abandon_limit(AP); \ + } while (0) + +/* Block statistics */ + +#define STAT_BLK_UPDATED_1(BSTATS) \ + do { \ + if ((BSTATS)->max.no < (BSTATS)->curr.no) { \ + (BSTATS)->max.no = (BSTATS)->curr.no; \ + } \ + if ((BSTATS)->max.size < (BSTATS)->curr.size) { \ + (BSTATS)->max.size = (BSTATS)->curr.size; \ + } \ + } while (0) + +#define STAT_BLK_ALLOC_1(CSTATS, ALLOC_NO, COUNT, SIZE) \ + do { \ + BlockStats_t *bstats__ = \ + &(CSTATS)->blocks[(ALLOC_NO) - ERTS_ALC_A_MIN]; \ + ASSERT(ERTS_UWORD_MAX - bstats__->curr.no > (COUNT)); \ + ASSERT(ERTS_UWORD_MAX - bstats__->curr.size > (SIZE)); \ + bstats__->curr.no += (COUNT); \ + bstats__->curr.size += (SIZE); \ + STAT_BLK_UPDATED_1(bstats__); \ + } while (0) + +#define STAT_BLK_FREE_1(CSTATS, ALLOC_NO, COUNT, SIZE) \ + do { \ + BlockStats_t *bstats__ = \ + &(CSTATS)->blocks[(ALLOC_NO) - ERTS_ALC_A_MIN]; \ + ASSERT(bstats__->curr.no >= (COUNT)); \ + ASSERT(bstats__->curr.size >= (SIZE)); \ + bstats__->curr.no -= (COUNT); \ + bstats__->curr.size -= (SIZE); \ + STAT_BLK_UPDATED_1(bstats__); \ + } while (0) + +#define STAT_MBC_CPOOL_FETCH(AP, CRR) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->mbcs; \ + UWord csz__ = CARRIER_SZ((CRR)); \ + int alloc_no__; \ + if (IS_MSEG_CARRIER((CRR))) { \ + STAT_MSEG_MBC_ALLOC((AP), csz__); \ + } else { \ + STAT_SYS_ALLOC_MBC_ALLOC((AP), csz__); \ + } \ + set_new_allctr_abandon_limit(AP); \ + for (alloc_no__ = ERTS_ALC_A_MIN; \ + alloc_no__ <= ERTS_ALC_A_MAX; \ + alloc_no__++) { \ + int ix__ = alloc_no__ - ERTS_ALC_A_MIN; \ + UWord count = (CRR)->cpool.blocks[ix__]; \ + UWord size = (CRR)->cpool.blocks_size[ix__]; \ + STAT_BLK_ALLOC_1(cstats__, alloc_no__, count, size); \ + } \ + } while (0) + +#define STAT_MBC_CPOOL_ABANDON(AP, CRR) \ + do { \ + CarriersStats_t *cstats__ = &(AP)->mbcs; \ + int alloc_no__; \ + STAT_MBC_FREE(AP, CRR); \ + for (alloc_no__ = ERTS_ALC_A_MIN; \ + alloc_no__ <= ERTS_ALC_A_MAX; \ + alloc_no__++) { \ + int ix__ = alloc_no__ - ERTS_ALC_A_MIN; \ + UWord count = (CRR)->cpool.blocks[ix__]; \ + UWord size = (CRR)->cpool.blocks_size[ix__]; \ + STAT_BLK_FREE_1(cstats__, alloc_no__, count, size); \ + } \ + } while (0) -static ERTS_INLINE int +static ERTS_INLINE void stat_cpool_mbc_blk_free(Allctr_t *allctr, - ErtsAlcType_t type, - Carrier_t *crr, - Carrier_t **busy_pcrr_pp, - UWord blksz) + int alloc_no, + Carrier_t *crr, + Carrier_t **busy_pcrr_pp, + UWord blksz) { - Allctr_t *orig_allctr; - int alloc_no; - - alloc_no = ERTS_ALC_T2A(type); - - ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks[alloc_no] > 0); - crr->cpool.blocks[alloc_no]--; - ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks_size[alloc_no] >= blksz); - crr->cpool.blocks_size[alloc_no] -= blksz; - ERTS_ALC_CPOOL_ASSERT(crr->cpool.total_blocks_size >= blksz); - crr->cpool.total_blocks_size -= blksz; - - if (allctr->alloc_no == alloc_no && (!busy_pcrr_pp || !*busy_pcrr_pp)) { + if (!busy_pcrr_pp || !*busy_pcrr_pp) { /* This is a local block, so we should not update the pool * statistics. */ - return 0; - } - - /* This is either a foreign block that's been fetched from the pool, or any - * block that's in the pool. The carrier's owner keeps the statistics for - * both pooled and foreign blocks. */ - - orig_allctr = crr->cpool.orig_allctr; + CarriersStats_t *cstats__ = &allctr->mbcs; + STAT_BLK_FREE_1(cstats__, alloc_no, 1, blksz); + } else { + Allctr_t *orig_allctr = crr->cpool.orig_allctr; + int ix = alloc_no - ERTS_ALC_A_MIN; - ERTS_ALC_CPOOL_ASSERT(alloc_no != allctr->alloc_no || - (crr == *busy_pcrr_pp && allctr == orig_allctr)); + ERTS_ALC_CPOOL_ASSERT(crr == *busy_pcrr_pp && allctr == orig_allctr); #ifdef ERTS_ALC_CPOOL_DEBUG - ERTS_ALC_CPOOL_ASSERT( - erts_atomic_dec_read_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no]) >= 0); - ERTS_ALC_CPOOL_ASSERT( - erts_atomic_add_read_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no], - -((erts_aint_t) blksz)) >= 0); + ERTS_ALC_CPOOL_ASSERT( + erts_atomic_dec_read_nob( + &orig_allctr->cpool.stat.no_blocks[ix]) >= 0); + ERTS_ALC_CPOOL_ASSERT( + erts_atomic_add_read_nob(&orig_allctr->cpool.stat.blocks_size[ix], + -((erts_aint_t) blksz)) >= 0); #else - erts_atomic_dec_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no]); - erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no], - -((erts_aint_t) blksz)); + erts_atomic_dec_nob(&orig_allctr->cpool.stat.no_blocks[ix]); + erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[ix], + -((erts_aint_t) blksz)); #endif - - return 1; + } } -#define STAT_MBC_BLK_FREE(AP, TYPE, CRR, BPCRRPP, BSZ, FLGS) \ -do { \ - if (!stat_cpool_mbc_blk_free((AP), (TYPE), (CRR), (BPCRRPP), (BSZ))) { \ - CarriersStats_t *cstats__ = &(AP)->mbcs; \ - ASSERT(cstats__->blocks.curr.no > 0); \ - cstats__->blocks.curr.no--; \ - ASSERT(cstats__->blocks.curr.size >= (BSZ)); \ - cstats__->blocks.curr.size -= (BSZ); \ - } \ -} while (0) +#define STAT_MBC_BLK_ALLOC(AP, CRR, BSZ) \ + do { \ + int alloc_no__ = (AP)->alloc_no; \ + int ix__ = alloc_no__ - ERTS_ALC_A_MIN; \ + ASSERT(ERTS_UWORD_MAX - (CRR)->cpool.blocks[ix__] > 1); \ + ASSERT(ERTS_UWORD_MAX - (CRR)->cpool.blocks_size[ix__] > (BSZ)); \ + ASSERT(ERTS_UWORD_MAX - (CRR)->cpool.total_blocks_size > (BSZ)); \ + (CRR)->cpool.blocks[ix__] += 1; \ + (CRR)->cpool.blocks_size[ix__] += (BSZ); \ + (CRR)->cpool.total_blocks_size += (BSZ); \ + STAT_BLK_ALLOC_1(&(AP)->mbcs, alloc_no__, 1, (BSZ)); \ + } while (0) + +#define STAT_MBC_BLK_FREE(AP, TYPE, CRR, BPCRRPP, BSZ) \ + do { \ + int alloc_no__ = ERTS_ALC_T2A(TYPE); \ + int ix__ = (alloc_no__) - ERTS_ALC_A_MIN; \ + ASSERT((CRR)->cpool.blocks[ix__] >= 1); \ + ASSERT((CRR)->cpool.blocks_size[ix__] >= (BSZ)); \ + ASSERT((CRR)->cpool.total_blocks_size >= (BSZ)); \ + (CRR)->cpool.blocks[ix__] -= 1; \ + (CRR)->cpool.blocks_size[ix__] -= (BSZ); \ + (CRR)->cpool.total_blocks_size -= (BSZ); \ + stat_cpool_mbc_blk_free((AP), alloc_no__, (CRR), (BPCRRPP), (BSZ)); \ + } while (0) /* Debug stuff... */ #ifdef DEBUG @@ -1211,9 +1232,14 @@ static Uint get_next_mbc_size(Allctr_t *allctr) { Uint size; - int cs = (allctr->mbcs.curr.norm.mseg.no - + allctr->mbcs.curr.norm.sys_alloc.no - - (allctr->main_carrier ? 1 : 0)); + int cs; + int i; + + cs = 0; + for (i = ERTS_CRR_ALLOC_MIN; i <= ERTS_CRR_ALLOC_MAX; i++) { + cs += allctr->mbcs.carriers[i].no; + } + cs -= (allctr->main_carrier ? 1 : 0); ASSERT(cs >= 0); ASSERT(allctr->largest_mbc_size >= allctr->smallest_mbc_size); @@ -2285,8 +2311,14 @@ check_abandon_carrier(Allctr_t *allctr, Block_t *fblk, Carrier_t **busy_pcrr_pp) if (allctr->cpool.disable_abandon) return; - if (allctr->mbcs.blocks.curr.size > allctr->cpool.abandon_limit) - return; + { + int ix = allctr->alloc_no - ERTS_ALC_A_MIN; + + /* We only consider the current allocation type; . */ + if (allctr->mbcs.blocks[ix].curr.size > allctr->cpool.abandon_limit) { + return; + } + } ncrr_in_pool = erts_atomic_read_nob(&allctr->cpool.stat.no_carriers); if (ncrr_in_pool >= allctr->cpool.in_pool_limit) @@ -2515,7 +2547,7 @@ mbc_alloc_finalize(Allctr_t *allctr, } ERTS_ALC_CPOOL_ALLOC_OP(allctr); - STAT_MBC_BLK_ALLOC(allctr, crr, blk_sz, alcu_flgs); + STAT_MBC_BLK_ALLOC(allctr, crr, blk_sz); ASSERT(IS_ALLOCED_BLK(blk)); ASSERT(blk_sz == MBC_BLK_SZ(blk)); @@ -2734,7 +2766,7 @@ mbc_free(Allctr_t *allctr, ErtsAlcType_t type, void *p, Carrier_t **busy_pcrr_pp ERTS_ALC_CPOOL_FREE_OP(allctr); - STAT_MBC_BLK_FREE(allctr, type, crr, busy_pcrr_pp, blk_sz, alcu_flgs); + STAT_MBC_BLK_FREE(allctr, type, crr, busy_pcrr_pp, blk_sz); is_first_blk = IS_MBC_FIRST_ABLK(allctr, blk); is_last_blk = IS_LAST_BLK(blk); @@ -2934,8 +2966,8 @@ mbc_realloc(Allctr_t *allctr, ErtsAlcType_t type, void *p, Uint size, crr = ABLK_TO_MBC(blk); ERTS_ALC_CPOOL_REALLOC_OP(allctr); - STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz, alcu_flgs); - STAT_MBC_BLK_ALLOC(allctr, crr, blk_sz, alcu_flgs); + STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz); + STAT_MBC_BLK_ALLOC(allctr, crr, blk_sz); ASSERT(MBC_BLK_SZ(blk) >= allctr->min_block_size); @@ -3038,8 +3070,8 @@ mbc_realloc(Allctr_t *allctr, ErtsAlcType_t type, void *p, Uint size, } ERTS_ALC_CPOOL_REALLOC_OP(allctr); - STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz, alcu_flgs); - STAT_MBC_BLK_ALLOC(allctr, crr, blk_sz, alcu_flgs); + STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz); + STAT_MBC_BLK_ALLOC(allctr, crr, blk_sz); ASSERT(IS_ALLOCED_BLK(blk)); ASSERT(blk_sz == MBC_BLK_SZ(blk)); @@ -3186,7 +3218,7 @@ mbc_realloc(Allctr_t *allctr, ErtsAlcType_t type, void *p, Uint size, 0); ERTS_ALC_CPOOL_FREE_OP(allctr); - STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz, alcu_flgs); + STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz); return new_p; } @@ -3357,27 +3389,17 @@ cpool_insert(Allctr_t *allctr, Carrier_t *crr) erts_aint_t val; ErtsAlcCPoolData_t *sentinel = allctr->cpool.sentinel; Allctr_t *orig_allctr = crr->cpool.orig_allctr; + int ix; ERTS_ALC_CPOOL_ASSERT(allctr->alloc_no == ERTS_ALC_A_TEST /* testcase */ || erts_thr_progress_is_managed_thread()); - { - int alloc_no = allctr->alloc_no; - - ERTS_ALC_CPOOL_ASSERT( - erts_atomic_read_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no]) >= 0 && - crr->cpool.blocks_size[alloc_no] >= 0); - - ERTS_ALC_CPOOL_ASSERT( - erts_atomic_read_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no]) >= 0 && - crr->cpool.blocks[alloc_no] >= 0); - - /* We only modify the counter for our current type since the others are - * conceptually still in the pool. */ - erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no], - ((erts_aint_t) crr->cpool.blocks_size[alloc_no])); - erts_atomic_add_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no], - ((erts_aint_t) crr->cpool.blocks[alloc_no])); + /* Add the carrier's block statistics to the pool. */ + for (ix = 0; ix < ERTS_ALC_A_COUNT; ix++) { + erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[ix], + ((erts_aint_t) crr->cpool.blocks_size[ix])); + erts_atomic_add_nob(&orig_allctr->cpool.stat.no_blocks[ix], + ((erts_aint_t) crr->cpool.blocks[ix])); } erts_atomic_add_nob(&orig_allctr->cpool.stat.carriers_size, @@ -3454,11 +3476,15 @@ cpool_delete(Allctr_t *allctr, Allctr_t *prev_allctr, Carrier_t *crr) #ifdef ERTS_ALC_CPOOL_DEBUG ErtsAlcCPoolData_t *sentinel = allctr->cpool.sentinel; #endif + Allctr_t *orig_allctr = crr->cpool.orig_allctr; + int ix; ERTS_ALC_CPOOL_ASSERT(allctr->alloc_no == ERTS_ALC_A_TEST /* testcase */ || erts_thr_progress_is_managed_thread()); ERTS_ALC_CPOOL_ASSERT(sentinel != &crr->cpool); + ERTS_ALC_CPOOL_ASSERT(orig_allctr == prev_allctr); + /* Set mod marker on next ptr of our predecessor */ val = (erts_aint_t) &crr->cpool; @@ -3531,30 +3557,31 @@ cpool_delete(Allctr_t *allctr, Allctr_t *prev_allctr, Carrier_t *crr) crr->cpool.thr_prgr = erts_thr_progress_later(NULL); - { - Allctr_t *orig_allctr = crr->cpool.orig_allctr; - int alloc_no = allctr->alloc_no; - - ERTS_ALC_CPOOL_ASSERT(orig_allctr == prev_allctr); - - ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks_size[alloc_no] <= - erts_atomic_read_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no])); - - ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks[alloc_no] <= - erts_atomic_read_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no])); + /* Subtract the carrier's block statistics from the pool. */ + for (ix = 0; ix < ERTS_ALC_A_COUNT; ix++) { +#ifdef ERTS_ALC_CPOOL_DEBUG + SWord new_blk_sz, new_blk_no; - /* We only modify the counters for our current type since the others - * were, conceptually, never taken out of the pool. */ - erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no], - -((erts_aint_t) crr->cpool.blocks_size[alloc_no])); - erts_atomic_add_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no], - -((erts_aint_t) crr->cpool.blocks[alloc_no])); + new_blk_sz = + erts_atomic_add_read_nob(&orig_allctr->cpool.stat.blocks_size[ix], + -((erts_aint_t)crr->cpool.blocks_size[ix])); + new_blk_no = + erts_atomic_add_read_nob(&orig_allctr->cpool.stat.no_blocks[ix], + -((erts_aint_t)crr->cpool.blocks[ix])); - erts_atomic_add_nob(&orig_allctr->cpool.stat.carriers_size, - -((erts_aint_t) CARRIER_SZ(crr))); - erts_atomic_dec_wb(&orig_allctr->cpool.stat.no_carriers); + ERTS_ALC_CPOOL_ASSERT(new_blk_sz >= 0); + ERTS_ALC_CPOOL_ASSERT(new_blk_no >= 0); +#else + erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[ix], + -((erts_aint_t) crr->cpool.blocks_size[ix])); + erts_atomic_add_nob(&orig_allctr->cpool.stat.no_blocks[ix], + -((erts_aint_t) crr->cpool.blocks[ix])); +#endif } + erts_atomic_add_nob(&orig_allctr->cpool.stat.carriers_size, + -((erts_aint_t) CARRIER_SZ(crr))); + erts_atomic_dec_wb(&orig_allctr->cpool.stat.no_carriers); } static Carrier_t * @@ -3937,9 +3964,12 @@ allctr_abandon_limit(Allctr_t *allctr) { UWord limit; UWord csz; + int i; - csz = allctr->mbcs.curr.norm.mseg.size; - csz += allctr->mbcs.curr.norm.sys_alloc.size; + csz = 0; + for (i = ERTS_CRR_ALLOC_MIN; i <= ERTS_CRR_ALLOC_MAX; i++) { + csz += allctr->mbcs.carriers[i].size; + } limit = csz*allctr->cpool.util_limit; if (limit > csz) @@ -3961,7 +3991,7 @@ abandon_carrier(Allctr_t *allctr, Carrier_t *crr) { erts_aint_t iallctr; - STAT_MBC_ABANDON(allctr, crr); + STAT_MBC_CPOOL_ABANDON(allctr, crr); unlink_carrier(&allctr->mbc_list, crr); allctr->remove_mbc(allctr, crr); @@ -4023,9 +4053,12 @@ static void cpool_read_stat(Allctr_t *allctr, int alloc_no, UWord *nocp, UWord *cszp, UWord *nobp, UWord *bszp) { + int block_ix; int i; UWord noc = 0, csz = 0, nob = 0, bsz = 0; + block_ix = alloc_no - ERTS_ALC_A_MIN; + /* * We try to get consistent values, but after * ERTS_ALC_CPOOL_MAX_FAILED_STAT_READS failed @@ -4041,10 +4074,10 @@ cpool_read_stat(Allctr_t *allctr, int alloc_no, ? erts_atomic_read_nob(&allctr->cpool.stat.carriers_size) : 0); tnob = (UWord) (nobp - ? erts_atomic_read_nob(&allctr->cpool.stat.no_blocks[alloc_no]) + ? erts_atomic_read_nob(&allctr->cpool.stat.no_blocks[block_ix]) : 0); tbsz = (UWord) (bszp - ? erts_atomic_read_nob(&allctr->cpool.stat.blocks_size[alloc_no]) + ? erts_atomic_read_nob(&allctr->cpool.stat.blocks_size[block_ix]) : 0); if (tnoc == noc && tcsz == csz && tnob == nob && tbsz == bsz) break; @@ -4192,12 +4225,12 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags) if (erts_mseg_no(&allctr->mseg_opt) >= max_mseg_carriers) goto try_sys_alloc; if (flags & CFLG_SBC) { - if (allctr->sbcs.curr.norm.mseg.no >= allctr->max_mseg_sbcs) + if (allctr->sbcs.carriers[ERTS_CRR_ALLOC_MSEG].no >= allctr->max_mseg_sbcs) goto try_sys_alloc; } #if !ERTS_SUPER_ALIGNED_MSEG_ONLY else { - if (allctr->mbcs.curr.norm.mseg.no >= allctr->max_mseg_mbcs) + if (allctr->mbcs.carriers[ERTS_CRR_ALLOC_MSEG].no >= allctr->max_mseg_mbcs) goto try_sys_alloc; } #endif @@ -4638,10 +4671,10 @@ static struct { Eterm mseg_alloc_carriers; #endif Eterm carriers; - Eterm blocks_size; - Eterm blocks; - Eterm foreign_blocks; + Eterm blocks; + Eterm count; + Eterm size; Eterm calls; Eterm sys_alloc; @@ -4658,6 +4691,7 @@ static struct { } am; static Eterm alloc_type_atoms[ERTS_ALC_N_MAX + 1]; +static Eterm alloc_num_atoms[ERTS_ALC_A_MAX + 1]; static ERTS_INLINE void atom_init(Eterm *atom, char *name) { @@ -4741,9 +4775,9 @@ init_atoms(Allctr_t *allctr) AM_INIT(mseg_alloc_carriers); #endif AM_INIT(carriers); - AM_INIT(blocks_size); AM_INIT(blocks); - AM_INIT(foreign_blocks); + AM_INIT(count); + AM_INIT(size); AM_INIT(calls); AM_INIT(sys_alloc); @@ -4767,6 +4801,13 @@ init_atoms(Allctr_t *allctr) alloc_type_atoms[ix] = am_atom_put(name, len); } + + for (ix = ERTS_ALC_A_MIN; ix <= ERTS_ALC_A_MAX; ix++) { + const char *name = ERTS_ALC_A2AD(ix); + size_t len = sys_strlen(name); + + alloc_num_atoms[ix] = am_atom_put(name, len); + } } if (allctr && !allctr->atoms_initialized) { @@ -4939,39 +4980,81 @@ sz_info_carriers(Allctr_t *allctr, Uint *szp) { Eterm res = THE_NON_VALUE; - UWord curr_size = cs->curr.norm.mseg.size + cs->curr.norm.sys_alloc.size; + UWord curr_size; + int i; + + curr_size = 0; + for (i = ERTS_CRR_ALLOC_MIN; i <= ERTS_CRR_ALLOC_MAX; i++) { + curr_size += cs->carriers[i].size; + } if (print_to_p) { - fmtfn_t to = *print_to_p; - void *arg = print_to_arg; - erts_print(to, - arg, - "%sblocks size: %bpu %bpu %bpu\n", - prefix, - cs->blocks.curr.size, - cs->blocks.max.size, - cs->blocks.max_ever.size); - erts_print(to, - arg, - "%scarriers size: %bpu %bpu %bpu\n", - prefix, - curr_size, - cs->max.size, - cs->max_ever.size); + fmtfn_t to = *print_to_p; + void *arg = print_to_arg; + int alloc_no; + + for (alloc_no = ERTS_ALC_A_MIN; + alloc_no <= ERTS_ALC_A_MAX; + alloc_no++) { + int ix = alloc_no - ERTS_ALC_A_MIN; + + erts_print(to, + arg, + "%sblocks[%s] size: %bpu %bpu %bpu\n", + prefix, + erts_alc_a2ad[alloc_no], + cs->blocks[ix].curr.size, + cs->blocks[ix].max.size, + cs->blocks[ix].max_ever.size); + } + + erts_print(to, + arg, + "%scarriers size: %bpu %bpu %bpu\n", + prefix, + curr_size, + cs->max.size, + cs->max_ever.size); } if (hpp || szp) { - res = NIL; - add_4tup(hpp, szp, &res, - am.carriers_size, - bld_unstable_uint(hpp, szp, curr_size), - bld_unstable_uint(hpp, szp, cs->max.size), - bld_unstable_uint(hpp, szp, cs->max_ever.size)); - add_4tup(hpp, szp, &res, - am.blocks_size, - bld_unstable_uint(hpp, szp, cs->blocks.curr.size), - bld_unstable_uint(hpp, szp, cs->blocks.max.size), - bld_unstable_uint(hpp, szp, cs->blocks.max_ever.size)); + Eterm blocks; + int alloc_no; + + res = NIL; + + add_4tup(hpp, szp, &res, + am.carriers_size, + bld_unstable_uint(hpp, szp, curr_size), + bld_unstable_uint(hpp, szp, cs->max.size), + bld_unstable_uint(hpp, szp, cs->max_ever.size)); + + blocks = NIL; + for (alloc_no = ERTS_ALC_A_MIN; + alloc_no <= ERTS_ALC_A_MAX; + alloc_no++) { + int ix = alloc_no - ERTS_ALC_A_MIN; + UWord curr, max, max_ever; + Eterm info = NIL; + + curr = cs->blocks[ix].curr.size; + max = cs->blocks[ix].max.size; + max_ever = cs->blocks[ix].max_ever.size; + + if (curr == 0 && max == 0 && max_ever == 0) { + continue; + } + + add_4tup(hpp, szp, &info, + am.size, + bld_unstable_uint(hpp, szp, curr), + bld_unstable_uint(hpp, szp, max), + bld_unstable_uint(hpp, szp, max_ever)); + + add_2tup(hpp, szp, &blocks, alloc_num_atoms[alloc_no], info); + } + + add_2tup(hpp, szp, &res, am.blocks, blocks); } return res; @@ -4988,33 +5071,43 @@ info_cpool(Allctr_t *allctr, Uint *szp) { Eterm res = THE_NON_VALUE; - UWord noc, csz, nob, bsz; + UWord noc, csz; - noc = csz = nob = bsz = ~0; + noc = csz = ~0; if (print_to_p || hpp) { - if (sz_only) - cpool_read_stat(allctr, allctr->alloc_no, NULL, &csz, NULL, &bsz); - else - cpool_read_stat(allctr, allctr->alloc_no, &noc, &csz, &nob, &bsz); + cpool_read_stat(allctr, allctr->alloc_no, &noc, &csz, NULL, NULL); } if (print_to_p) { - fmtfn_t to = *print_to_p; - void *arg = print_to_arg; - if (!sz_only) - erts_print(to, arg, "%sblocks: %bpu\n", prefix, nob); - erts_print(to, arg, "%sblocks size: %bpu\n", prefix, bsz); - if (!sz_only) - erts_print(to, arg, "%scarriers: %bpu\n", prefix, noc); - erts_print(to, arg, "%scarriers size: %bpu\n", prefix, csz); + fmtfn_t to = *print_to_p; + void *arg = print_to_arg; + int alloc_no; + + for (alloc_no = ERTS_ALC_A_MIN; + alloc_no <= ERTS_ALC_A_MAX; + alloc_no++) { + UWord nob, bsz; + + nob = bsz = ~0; + cpool_read_stat(allctr, alloc_no, NULL, NULL, &nob, &bsz); + + if (!sz_only) + erts_print(to, arg, "%sblocks[%s] count: %bpu\n", + prefix, erts_alc_a2ad[alloc_no], nob); + erts_print(to, arg, "%sblocks[%s] size: %bpu\n", + prefix, erts_alc_a2ad[alloc_no], bsz); + } + + if (!sz_only) + erts_print(to, arg, "%scarriers: %bpu\n", prefix, noc); + erts_print(to, arg, "%scarriers size: %bpu\n", prefix, csz); } if (hpp || szp) { - Eterm foreign_blocks; - int i; + Eterm blocks; + int alloc_no; - foreign_blocks = NIL; - res = NIL; + res = NIL; if (!sz_only) { add_3tup(hpp, szp, &res, am.fail_pooled, @@ -5072,49 +5165,36 @@ info_cpool(Allctr_t *allctr, bld_unstable_uint(hpp, szp, noc)); } - add_2tup(hpp, szp, &res, - am.blocks_size, - bld_unstable_uint(hpp, szp, bsz)); - - if (!sz_only) { - add_2tup(hpp, szp, &res, - am.blocks, - bld_unstable_uint(hpp, szp, nob)); - } - - for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { - const char *name_str; - Eterm name, info; - - if (i == allctr->alloc_no) { - continue; - } + blocks = NIL; + for (alloc_no = ERTS_ALC_A_MIN; + alloc_no <= ERTS_ALC_A_MAX; + alloc_no++) { + UWord nob, bsz; + Eterm info; - cpool_read_stat(allctr, i, NULL, NULL, &nob, &bsz); + nob = bsz = ~0; + cpool_read_stat(allctr, alloc_no, NULL, NULL, &nob, &bsz); if (bsz == 0 && (nob == 0 || sz_only)) { continue; } - name_str = ERTS_ALC_A2AD(i); info = NIL; add_2tup(hpp, szp, &info, - am.blocks_size, + am.size, bld_unstable_uint(hpp, szp, bsz)); if (!sz_only) { add_2tup(hpp, szp, &info, - am.blocks, + am.count, bld_unstable_uint(hpp, szp, nob)); } - name = am_atom_put(name_str, sys_strlen(name_str)); - - add_2tup(hpp, szp, &foreign_blocks, name, info); + add_2tup(hpp, szp, &blocks, alloc_num_atoms[alloc_no], info); } - add_2tup(hpp, szp, &res, am.foreign_blocks, foreign_blocks); + add_2tup(hpp, szp, &res, am.blocks, blocks); } return res; @@ -5132,27 +5212,41 @@ info_carriers(Allctr_t *allctr, { Eterm res = THE_NON_VALUE; UWord curr_no, curr_size; - - curr_no = cs->curr.norm.mseg.no + cs->curr.norm.sys_alloc.no; - curr_size = cs->curr.norm.mseg.size + cs->curr.norm.sys_alloc.size; + int i; + + curr_no = curr_size = 0; + for (i = ERTS_CRR_ALLOC_MIN; i <= ERTS_CRR_ALLOC_MAX; i++) { + curr_no += cs->carriers[i].no; + curr_size += cs->carriers[i].size; + } if (print_to_p) { - fmtfn_t to = *print_to_p; - void *arg = print_to_arg; - erts_print(to, - arg, - "%sblocks: %bpu %bpu %bpu\n", - prefix, - cs->blocks.curr.no, - cs->blocks.max.no, - cs->blocks.max_ever.no); - erts_print(to, - arg, - "%sblocks size: %bpu %bpu %bpu\n", - prefix, - cs->blocks.curr.size, - cs->blocks.max.size, - cs->blocks.max_ever.size); + fmtfn_t to = *print_to_p; + void *arg = print_to_arg; + int alloc_no; + + for (alloc_no = ERTS_ALC_A_MIN; + alloc_no <= ERTS_ALC_A_MAX; + alloc_no++) { + int ix = alloc_no - ERTS_ALC_A_MIN; + erts_print(to, + arg, + "%sblocks[%s] count: %bpu %bpu %bpu\n", + prefix, + erts_alc_a2ad[alloc_no], + cs->blocks[ix].curr.no, + cs->blocks[ix].max.no, + cs->blocks[ix].max_ever.no); + erts_print(to, + arg, + "%sblocks[%s] size: %bpu %bpu %bpu\n", + prefix, + erts_alc_a2ad[alloc_no], + cs->blocks[ix].curr.size, + cs->blocks[ix].max.size, + cs->blocks[ix].max_ever.size); + } + erts_print(to, arg, "%scarriers: %bpu %bpu %bpu\n", @@ -5165,13 +5259,13 @@ info_carriers(Allctr_t *allctr, arg, "%smseg carriers: %bpu\n", prefix, - cs->curr.norm.mseg.no); + cs->carriers[ERTS_CRR_ALLOC_MSEG].no); #endif erts_print(to, arg, "%ssys_alloc carriers: %bpu\n", prefix, - cs->curr.norm.sys_alloc.no); + cs->carriers[ERTS_CRR_ALLOC_SYS].no); erts_print(to, arg, "%scarriers size: %bpu %bpu %bpu\n", @@ -5184,24 +5278,27 @@ info_carriers(Allctr_t *allctr, arg, "%smseg carriers size: %bpu\n", prefix, - cs->curr.norm.mseg.size); + cs->carriers[ERTS_CRR_ALLOC_MSEG].size); #endif erts_print(to, arg, "%ssys_alloc carriers size: %bpu\n", prefix, - cs->curr.norm.sys_alloc.size); + cs->carriers[ERTS_CRR_ALLOC_SYS].size); } if (hpp || szp) { + Eterm blocks; + int alloc_no; + res = NIL; add_2tup(hpp, szp, &res, am.sys_alloc_carriers_size, - bld_unstable_uint(hpp, szp, cs->curr.norm.sys_alloc.size)); + bld_unstable_uint(hpp, szp, cs->carriers[ERTS_CRR_ALLOC_SYS].size)); #if HAVE_ERTS_MSEG add_2tup(hpp, szp, &res, am.mseg_alloc_carriers_size, - bld_unstable_uint(hpp, szp, cs->curr.norm.mseg.size)); + bld_unstable_uint(hpp, szp, cs->carriers[ERTS_CRR_ALLOC_MSEG].size)); #endif add_4tup(hpp, szp, &res, am.carriers_size, @@ -5210,27 +5307,57 @@ info_carriers(Allctr_t *allctr, bld_unstable_uint(hpp, szp, cs->max_ever.size)); add_2tup(hpp, szp, &res, am.sys_alloc_carriers, - bld_unstable_uint(hpp, szp, cs->curr.norm.sys_alloc.no)); + bld_unstable_uint(hpp, szp, cs->carriers[ERTS_CRR_ALLOC_SYS].no)); #if HAVE_ERTS_MSEG add_2tup(hpp, szp, &res, am.mseg_alloc_carriers, - bld_unstable_uint(hpp, szp, cs->curr.norm.mseg.no)); + bld_unstable_uint(hpp, szp, cs->carriers[ERTS_CRR_ALLOC_MSEG].no)); #endif add_4tup(hpp, szp, &res, am.carriers, bld_unstable_uint(hpp, szp, curr_no), bld_unstable_uint(hpp, szp, cs->max.no), bld_unstable_uint(hpp, szp, cs->max_ever.no)); - add_4tup(hpp, szp, &res, - am.blocks_size, - bld_unstable_uint(hpp, szp, cs->blocks.curr.size), - bld_unstable_uint(hpp, szp, cs->blocks.max.size), - bld_unstable_uint(hpp, szp, cs->blocks.max_ever.size)); - add_4tup(hpp, szp, &res, - am.blocks, - bld_unstable_uint(hpp, szp, cs->blocks.curr.no), - bld_unstable_uint(hpp, szp, cs->blocks.max.no), - bld_unstable_uint(hpp, szp, cs->blocks.max_ever.no)); + + blocks = NIL; + for (alloc_no = ERTS_ALC_A_MIN; + alloc_no <= ERTS_ALC_A_MAX; + alloc_no++) { + int ix = alloc_no - ERTS_ALC_A_MIN; + UWord curr_size, max_size, max_ever_size; + UWord curr_no, max_no, max_ever_no; + Eterm info; + + curr_size = cs->blocks[ix].curr.size; + max_size = cs->blocks[ix].max.size; + max_ever_size = cs->blocks[ix].max_ever.size; + + curr_no = cs->blocks[ix].curr.no; + max_no = cs->blocks[ix].max.no; + max_ever_no = cs->blocks[ix].max_ever.no; + + if (max_ever_no == 0) { + continue; + } + + info = NIL; + + add_4tup(hpp, szp, &info, + am.size, + bld_unstable_uint(hpp, szp, curr_size), + bld_unstable_uint(hpp, szp, max_size), + bld_unstable_uint(hpp, szp, max_ever_size)); + + add_4tup(hpp, szp, &info, + am.count, + bld_unstable_uint(hpp, szp, curr_no), + bld_unstable_uint(hpp, szp, max_no), + bld_unstable_uint(hpp, szp, max_ever_no)); + + add_2tup(hpp, szp, &blocks, alloc_num_atoms[alloc_no], info); + } + + add_2tup(hpp, szp, &res, am.blocks, blocks); } return res; @@ -5490,23 +5617,50 @@ info_options(Allctr_t *allctr, static ERTS_INLINE void update_max_ever_values(CarriersStats_t *cs) { - if (cs->max_ever.no < cs->max.no) - cs->max_ever.no = cs->max.no; - if (cs->max_ever.size < cs->max.size) - cs->max_ever.size = cs->max.size; - if (cs->blocks.max_ever.no < cs->blocks.max.no) - cs->blocks.max_ever.no = cs->blocks.max.no; - if (cs->blocks.max_ever.size < cs->blocks.max.size) - cs->blocks.max_ever.size = cs->blocks.max.size; + int ix; + + for (ix = 0; ix < ERTS_ALC_A_COUNT; ix++) { + BlockStats_t *bstats = &cs->blocks[ix]; + + if (bstats->max_ever.no < bstats->max.no) { + bstats->max_ever.no = bstats->max.no; + } + + if (bstats->max_ever.size < bstats->max.size) { + bstats->max_ever.size = bstats->max.size; + } + } + + if (cs->max_ever.no < cs->max.no) { + cs->max_ever.no = cs->max.no; + } + + if (cs->max_ever.size < cs->max.size) { + cs->max_ever.size = cs->max.size; + } } static ERTS_INLINE void reset_max_values(CarriersStats_t *cs) { - cs->max.no = cs->curr.norm.mseg.no + cs->curr.norm.sys_alloc.no; - cs->max.size = cs->curr.norm.mseg.size + cs->curr.norm.sys_alloc.size; - cs->blocks.max.no = cs->blocks.curr.no; - cs->blocks.max.size = cs->blocks.curr.size; + UWord curr_no, curr_size; + int ix; + + for (ix = 0; ix < ERTS_ALC_A_COUNT; ix++) { + BlockStats_t *bstats = &cs->blocks[ix]; + + bstats->max.no = bstats->curr.no; + bstats->max.size = bstats->curr.size; + } + + curr_no = curr_size = 0; + for (ix = ERTS_CRR_ALLOC_MIN; ix <= ERTS_CRR_ALLOC_MAX; ix++) { + curr_no += cs->carriers[ix].no; + curr_size += cs->carriers[ix].size; + } + + cs->max.no = curr_no; + cs->max.size = curr_size; } @@ -5614,11 +5768,6 @@ erts_alcu_sz_info(Allctr_t *allctr, ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr); - /* Update sbc values not continuously updated */ - allctr->sbcs.blocks.curr.no - = allctr->sbcs.curr.norm.mseg.no + allctr->sbcs.curr.norm.sys_alloc.no; - allctr->sbcs.blocks.max.no = allctr->sbcs.max.no; - update_max_ever_values(&allctr->mbcs); update_max_ever_values(&allctr->sbcs); @@ -5690,11 +5839,6 @@ erts_alcu_info(Allctr_t *allctr, ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr); - /* Update sbc values not continuously updated */ - allctr->sbcs.blocks.curr.no - = allctr->sbcs.curr.norm.mseg.no + allctr->sbcs.curr.norm.sys_alloc.no; - allctr->sbcs.blocks.max.no = allctr->sbcs.max.no; - update_max_ever_values(&allctr->mbcs); update_max_ever_values(&allctr->sbcs); @@ -5753,61 +5897,66 @@ erts_alcu_info(Allctr_t *allctr, void erts_alcu_foreign_size(Allctr_t *allctr, ErtsAlcType_t alloc_no, AllctrSize_t *size) { + int ix; + + sys_memset(size, 0, sizeof(*size)); + + if (allctr->thread_safe) + erts_mtx_lock(&allctr->mutex); + + for (ix = ERTS_CRR_ALLOC_MIN; ix <= ERTS_CRR_ALLOC_MAX; ix++) { + size->carriers += allctr->mbcs.carriers[ix].size; + size->carriers += allctr->sbcs.carriers[ix].size; + } + + ix = alloc_no - ERTS_ALC_A_MIN; + size->blocks += allctr->mbcs.blocks[ix].curr.size; + size->blocks += allctr->sbcs.blocks[ix].curr.size; + if (ERTS_ALC_IS_CPOOL_ENABLED(allctr)) { UWord csz, bsz; + + csz = bsz = 0; cpool_read_stat(allctr, alloc_no, NULL, &csz, NULL, &bsz); - size->carriers = csz; - size->blocks = bsz; - } else { - size->carriers = 0; - size->blocks = 0; + + size->carriers += csz; + size->blocks += bsz; } + + if (allctr->thread_safe) + erts_mtx_unlock(&allctr->mutex); } void erts_alcu_current_size(Allctr_t *allctr, AllctrSize_t *size, ErtsAlcUFixInfo_t *fi, int fisz) { - - if (allctr->thread_safe) - erts_mtx_lock(&allctr->mutex); - - size->carriers = allctr->mbcs.curr.norm.mseg.size; - size->carriers += allctr->mbcs.curr.norm.sys_alloc.size; - size->carriers += allctr->sbcs.curr.norm.mseg.size; - size->carriers += allctr->sbcs.curr.norm.sys_alloc.size; - - size->blocks = allctr->mbcs.blocks.curr.size; - size->blocks += allctr->sbcs.blocks.curr.size; - - if (ERTS_ALC_IS_CPOOL_ENABLED(allctr)) { - UWord csz, bsz; - cpool_read_stat(allctr, allctr->alloc_no, NULL, &csz, NULL, &bsz); - size->blocks += bsz; - size->carriers += csz; - } + erts_alcu_foreign_size(allctr, allctr->alloc_no, size); if (fi) { - int ix; - for (ix = 0; ix < fisz; ix++) { - if (allctr->fix) { - if (ERTS_ALC_IS_CPOOL_ENABLED(allctr)) { - fi[ix].allocated += (allctr->fix[ix].type_size - * allctr->fix[ix].u.cpool.allocated); - fi[ix].used += (allctr->fix[ix].type_size - * allctr->fix[ix].u.cpool.used); - } - else { - fi[ix].allocated += (allctr->fix[ix].type_size - * allctr->fix[ix].u.nocpool.allocated); - fi[ix].used += (allctr->fix[ix].type_size - * allctr->fix[ix].u.nocpool.used); - } - } - } - } + int ix; + + if (allctr->thread_safe) + erts_mtx_lock(&allctr->mutex); + + for (ix = 0; ix < fisz; ix++) { + if (allctr->fix) { + if (ERTS_ALC_IS_CPOOL_ENABLED(allctr)) { + fi[ix].allocated += (allctr->fix[ix].type_size + * allctr->fix[ix].u.cpool.allocated); + fi[ix].used += (allctr->fix[ix].type_size + * allctr->fix[ix].u.cpool.used); + } else { + fi[ix].allocated += (allctr->fix[ix].type_size + * allctr->fix[ix].u.nocpool.allocated); + fi[ix].used += (allctr->fix[ix].type_size + * allctr->fix[ix].u.nocpool.used); + } + } + } - if (allctr->thread_safe) - erts_mtx_unlock(&allctr->mutex); + if (allctr->thread_safe) + erts_mtx_unlock(&allctr->mutex); + } } /* ----------------------------------------------------------------------- */ @@ -6660,10 +6809,12 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) allctr->cpool.dc_list.last = NULL; allctr->cpool.abandon_limit = 0; allctr->cpool.disable_abandon = 0; - for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { + + for (i = 0; i < ERTS_ALC_A_COUNT; i++) { erts_atomic_init_nob(&allctr->cpool.stat.blocks_size[i], 0); erts_atomic_init_nob(&allctr->cpool.stat.no_blocks[i], 0); } + erts_atomic_init_nob(&allctr->cpool.stat.carriers_size, 0); erts_atomic_init_nob(&allctr->cpool.stat.no_carriers, 0); if (!init->ts && init->acul && init->acnl) { @@ -7696,14 +7847,15 @@ typedef struct chist_node__ { UWord carrier_size; UWord unscanned_size; - UWord allocated_size; - /* BLOCKSCAN_BAILOUT_THRESHOLD guarantees we won't overflow this or the - * counters in the free block histogram. */ - int allocated_count; int flags; - int histogram[1]; + /* A mirror of the block counters in the carrier's ErtsAlcCPoolData_t. */ + UWord alloc_count[ERTS_ALC_A_COUNT]; + UWord alloc_size[ERTS_ALC_A_COUNT]; + + /* BLOCKSCAN_BAILOUT_THRESHOLD guarantees we won't overflow. */ + int free_histogram[1]; } chist_node_t; typedef struct { @@ -7712,7 +7864,7 @@ typedef struct { ErtsIRefStorage iref; Process *process; - Eterm allocator_desc; + int allocator_number; chist_node_t *info_list; UWord info_count; @@ -7737,7 +7889,7 @@ static int gather_cinfo_scan(Allctr_t *allocator, state = (gather_cinfo_t*)user_data; node = calloc(1, sizeof(chist_node_t) + (state->hist_slot_count - 1) * - sizeof(node->histogram[0])); + sizeof(node->free_histogram[0])); blocks_scanned = 1; /* ERTS_CRR_ALCTR_FLG_BUSY is ignored since we've set it ourselves and it @@ -7747,16 +7899,20 @@ static int gather_cinfo_scan(Allctr_t *allocator, node->carrier_size = CARRIER_SZ(carrier); if (IS_SB_CARRIER(carrier)) { - UWord block_size; - - block = SBC2BLK(allocator, carrier); - block_size = SBC_BLK_SZ(block); + int ix = allocator->alloc_no - ERTS_ALC_A_MIN; - node->allocated_size = block_size; - node->allocated_count = 1; + node->alloc_count[ix] = 1; + node->alloc_size[ix] = node->carrier_size; } else { UWord scanned_bytes = MBC_HEADER_SIZE(allocator); + sys_memcpy(&node->alloc_count[0], + &carrier->cpool.blocks[0], + sizeof(UWord) * ERTS_ALC_A_COUNT); + sys_memcpy(&node->alloc_size[0], + &carrier->cpool.blocks_size[0], + sizeof(UWord) * ERTS_ALC_A_COUNT); + block = MBC_TO_FIRST_BLK(allocator, carrier); while (1) { @@ -7764,10 +7920,7 @@ static int gather_cinfo_scan(Allctr_t *allocator, scanned_bytes += block_size; - if (IS_ALLOCED_BLK(block)) { - node->allocated_size += block_size; - node->allocated_count++; - } else { + if (IS_FREE_BLK(block)) { UWord size_interval; int hist_slot; @@ -7776,7 +7929,7 @@ static int gather_cinfo_scan(Allctr_t *allocator, hist_slot = MIN(size_interval, state->hist_slot_count - 1); - node->histogram[hist_slot]++; + node->free_histogram[hist_slot]++; } if (blocks_scanned >= BLOCKSCAN_BAILOUT_THRESHOLD) { @@ -7801,46 +7954,89 @@ static int gather_cinfo_scan(Allctr_t *allocator, static void gather_cinfo_append_result(gather_cinfo_t *state, chist_node_t *info) { - Eterm carrier_size, unscanned_size, allocated_size; - Eterm histogram_tuple, carrier_tuple; + Eterm carrier_tuple, block_list, histogram_tuple; + Eterm carrier_size, unscanned_size; Uint term_size; Eterm *hp; int ix; ASSERT(state->building_result); + term_size = 0; + + /* Free block histogram. */ + term_size += 1 + state->hist_slot_count; + + /* Per-type block list. */ + for (ix = ERTS_ALC_A_MIN; ix <= ERTS_ALC_A_MAX; ix++) { + UWord count = info->alloc_count[ix - ERTS_ALC_A_MIN]; + UWord size = info->alloc_size[ix - ERTS_ALC_A_MIN]; + + if (count > 0) { + /* We have at least one block of this type, so we'll need a cons + * cell and a 3-tuple; {Type, Count, Size}. */ + term_size += 2 + 4; + term_size += IS_USMALL(0, count) ? 0 : BIG_UINT_HEAP_SIZE; + term_size += IS_USMALL(0, size) ? 0 : BIG_UINT_HEAP_SIZE; + } + } - term_size = 11 + state->hist_slot_count; + /* Carrier tuple and its fields. */ + term_size += 7; term_size += IS_USMALL(0, info->carrier_size) ? 0 : BIG_UINT_HEAP_SIZE; term_size += IS_USMALL(0, info->unscanned_size) ? 0 : BIG_UINT_HEAP_SIZE; - term_size += IS_USMALL(0, info->allocated_size) ? 0 : BIG_UINT_HEAP_SIZE; + /* ... and a finally a cons cell to keep the result in. */ + term_size += 2; + + /* * * */ hp = erts_produce_heap(&state->msg_factory, term_size, 0); - hp[0] = make_arityval(state->hist_slot_count); + block_list = NIL; + for (ix = ERTS_ALC_A_MIN; ix <= ERTS_ALC_A_MAX; ix++) { + UWord count = info->alloc_count[ix - ERTS_ALC_A_MIN]; + UWord size = info->alloc_size[ix - ERTS_ALC_A_MIN]; - for (ix = 0; ix < state->hist_slot_count; ix++) { - hp[1 + ix] = make_small(info->histogram[ix]); + if (count > 0) { + Eterm block_count, block_size; + Eterm alloc_tuple; + + block_count = bld_unstable_uint(&hp, NULL, count); + block_size = bld_unstable_uint(&hp, NULL, size); + + hp[0] = make_arityval(3); + hp[1] = alloc_num_atoms[ix]; + hp[2] = block_count; + hp[3] = block_size; + + alloc_tuple = make_tuple(hp); + hp += 4; + + block_list = CONS(hp, alloc_tuple, block_list); + hp += 2; + } } + hp[0] = make_arityval(state->hist_slot_count); + for (ix = 0; ix < state->hist_slot_count; ix++) { + hp[1 + ix] = make_small(info->free_histogram[ix]); + } histogram_tuple = make_tuple(hp); hp += 1 + state->hist_slot_count; carrier_size = bld_unstable_uint(&hp, NULL, info->carrier_size); unscanned_size = bld_unstable_uint(&hp, NULL, info->unscanned_size); - allocated_size = bld_unstable_uint(&hp, NULL, info->allocated_size); - hp[0] = make_arityval(7); - hp[1] = state->allocator_desc; - hp[2] = carrier_size; - hp[3] = unscanned_size; - hp[4] = allocated_size; - hp[5] = make_small(info->allocated_count); - hp[6] = (info->flags & ERTS_CRR_ALCTR_FLG_IN_POOL) ? am_true : am_false; - hp[7] = histogram_tuple; + hp[0] = make_arityval(6); + hp[1] = alloc_num_atoms[state->allocator_number]; + hp[2] = (info->flags & ERTS_CRR_ALCTR_FLG_IN_POOL) ? am_true : am_false; + hp[3] = carrier_size; + hp[4] = unscanned_size; + hp[5] = block_list; + hp[6] = histogram_tuple; carrier_tuple = make_tuple(hp); - hp += 8; + hp += 7; state->result_list = CONS(hp, carrier_tuple, state->result_list); @@ -7936,8 +8132,6 @@ int erts_alcu_gather_carrier_info(struct process *p, int allocator_num, { gather_cinfo_t *gather_state; blockscan_t *scanner; - - const char *allocator_desc; Allctr_t *allocator; ASSERT(is_internal_ref(ref)); @@ -7948,7 +8142,7 @@ int erts_alcu_gather_carrier_info(struct process *p, int allocator_num, return 0; } - allocator_desc = ERTS_ALC_A2AD(allocator_num); + ensure_atoms_initialized(allocator); /* Plain calloc is intentional. */ gather_state = (gather_cinfo_t*)calloc(1, sizeof(gather_cinfo_t)); @@ -7959,9 +8153,7 @@ int erts_alcu_gather_carrier_info(struct process *p, int allocator_num, scanner->finish = gather_cinfo_finish; scanner->user_data = gather_state; - gather_state->allocator_desc = erts_atom_put((byte *)allocator_desc, - sys_strlen(allocator_desc), - ERTS_ATOM_ENC_LATIN1, 1); + gather_state->allocator_number = allocator_num; erts_iref_storage_save(&gather_state->iref, ref); gather_state->hist_slot_start = hist_start * 2; gather_state->hist_slot_count = hist_width; @@ -8069,14 +8261,22 @@ void erts_alcu_verify_unused(Allctr_t *allctr) { UWord no; + int ix; - no = allctr->sbcs.curr.norm.mseg.no; - no += allctr->sbcs.curr.norm.sys_alloc.no; - no += allctr->mbcs.blocks.curr.no; + no = 0; + for (ix = ERTS_CRR_ALLOC_MIN; ix <= ERTS_CRR_ALLOC_MAX; ix++) { + no += allctr->sbcs.carriers[ix].no; + } + + ix = allctr->alloc_no - ERTS_ALC_A_MIN; + no += allctr->mbcs.blocks[ix].curr.no; if (no) { - UWord sz = allctr->sbcs.blocks.curr.size; - sz += allctr->mbcs.blocks.curr.size; + UWord sz = 0; + + sz += allctr->sbcs.blocks[ix].curr.size; + sz += allctr->mbcs.blocks[ix].curr.size; + erts_exit(ERTS_ABORT_EXIT, "%salloc() used when expected to be unused!\n" "Total amount of blocks allocated: %bpu\n" diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h index b46b311c59..07cbd8470e 100644 --- a/erts/emulator/beam/erl_alloc_util.h +++ b/erts/emulator/beam/erl_alloc_util.h @@ -456,8 +456,8 @@ typedef struct { ErtsThrPrgrVal thr_prgr; erts_atomic_t max_size; UWord abandon_limit; - UWord blocks[ERTS_ALC_A_MAX + 1]; - UWord blocks_size[ERTS_ALC_A_MAX + 1]; + UWord blocks[ERTS_ALC_A_COUNT]; + UWord blocks_size[ERTS_ALC_A_COUNT]; UWord total_blocks_size; enum { ERTS_MBC_IS_HOME, @@ -492,19 +492,28 @@ typedef struct { } StatValues_t; typedef struct { - union { - struct { - StatValues_t mseg; - StatValues_t sys_alloc; - } norm; - } curr; - StatValues_t max; - StatValues_t max_ever; - struct { - StatValues_t curr; - StatValues_t max; - StatValues_t max_ever; - } blocks; + StatValues_t curr; + StatValues_t max; + StatValues_t max_ever; +} BlockStats_t; + +enum { + ERTS_CRR_ALLOC_MIN = 0, + + ERTS_CRR_ALLOC_MSEG = ERTS_CRR_ALLOC_MIN, + ERTS_CRR_ALLOC_SYS = 1, + + ERTS_CRR_ALLOC_MAX, + ERTS_CRR_ALLOC_COUNT = ERTS_CRR_ALLOC_MAX + 1 +}; + +typedef struct { + StatValues_t carriers[ERTS_CRR_ALLOC_COUNT]; + + StatValues_t max; + StatValues_t max_ever; + + BlockStats_t blocks[ERTS_ALC_A_COUNT]; } CarriersStats_t; #ifdef USE_LTTNG_VM_TRACEPOINTS @@ -654,8 +663,8 @@ struct Allctr_t_ { UWord in_pool_limit; /* acnl */ UWord fblk_min_limit; /* acmfl */ struct { - erts_atomic_t blocks_size[ERTS_ALC_A_MAX + 1]; - erts_atomic_t no_blocks[ERTS_ALC_A_MAX + 1]; + erts_atomic_t blocks_size[ERTS_ALC_A_COUNT]; + erts_atomic_t no_blocks[ERTS_ALC_A_COUNT]; erts_atomic_t carriers_size; erts_atomic_t no_carriers; CallCounter_t fail_pooled; diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index 4e0243c1cd..24677247a7 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -302,45 +302,52 @@ wait_for_memory_deallocations() -> end. print_stats(migration) -> - IFun = fun({instance,Inr,Istats}, {Bacc,Cacc,Pacc}) -> - {mbcs,MBCS} = lists:keyfind(mbcs, 1, Istats), - Btup = lists:keyfind(blocks, 1, MBCS), - Ctup = lists:keyfind(carriers, 1, MBCS), - - Ptup = case lists:keyfind(mbcs_pool, 1, Istats) of - {mbcs_pool,POOL} -> - {blocks, Bpool} = lists:keyfind(blocks, 1, POOL), - {carriers, Cpool} = lists:keyfind(carriers, 1, POOL), - {pool, Bpool, Cpool}; - false -> - {pool, 0, 0} - end, - io:format("{instance,~p,~p,~p,~p}}\n", - [Inr, Btup, Ctup, Ptup]), - {tuple_add(Bacc,Btup),tuple_add(Cacc,Ctup), - tuple_add(Pacc,Ptup)}; - (_, Acc) -> Acc + IFun = fun({instance,_,Stats}, {Regular0, Pooled0}) -> + {mbcs,MBCS} = lists:keyfind(mbcs, 1, Stats), + {sbcs,SBCS} = lists:keyfind(sbcs, 1, Stats), + + Regular = MBCS ++ SBCS ++ Regular0, + case lists:keyfind(mbcs_pool, 1, Stats) of + {mbcs_pool,Pool} -> {Regular, Pool ++ Pooled0}; + false -> {Regular, Pooled0} + end; + (_, Acc) -> + Acc end, - {Btot,Ctot,Ptot} = lists:foldl(IFun, - {{blocks,0,0,0},{carriers,0,0,0},{pool,0,0}}, - erlang:system_info({allocator,test_alloc})), - - {pool, PBtot, PCtot} = Ptot, - io:format("Number of blocks : ~p\n", [Btot]), - io:format("Number of carriers: ~p\n", [Ctot]), - io:format("Number of pooled blocks : ~p\n", [PBtot]), - io:format("Number of pooled carriers: ~p\n", [PCtot]); -print_stats(_) -> ok. - -tuple_add(T1, T2) -> - list_to_tuple(lists:zipwith(fun(E1,E2) when is_number(E1), is_number(E2) -> - E1 + E2; - (A,A) -> - A - end, - tuple_to_list(T1), tuple_to_list(T2))). + Stats = erlang:system_info({allocator,test_alloc}), + {Regular, Pooled} = lists:foldl(IFun, {[], []}, Stats), + {RegBlocks, RegCarriers} = summarize_alloc_stats(Regular, {0, 0}), + {PooledBlocks, PooledCarriers} = summarize_alloc_stats(Pooled, {0, 0}), + + io:format("Number of blocks : ~p\n", [RegBlocks]), + io:format("Number of carriers: ~p\n", [RegCarriers]), + io:format("Number of pooled blocks : ~p\n", [PooledBlocks]), + io:format("Number of pooled carriers: ~p\n", [PooledCarriers]); +print_stats(_) -> + ok. + +summarize_alloc_stats([{blocks,L} | Rest], {Blocks0, Carriers}) -> + Blocks = count_blocks([S || {_Type, S} <- L], Blocks0), + summarize_alloc_stats(Rest, {Blocks, Carriers}); +summarize_alloc_stats([{carriers, Count, _, _} | Rest], {Blocks, Carriers0}) -> + summarize_alloc_stats(Rest, {Blocks, Carriers0 + Count}); +summarize_alloc_stats([{carriers, Count} | Rest], {Blocks, Carriers0}) -> + summarize_alloc_stats(Rest, {Blocks, Carriers0 + Count}); +summarize_alloc_stats([_ | Rest], Acc) -> + summarize_alloc_stats(Rest, Acc); +summarize_alloc_stats([], Acc) -> + Acc. + +count_blocks([{count, Count, _, _} | Rest], Acc) -> + count_blocks(Rest, Acc + Count); +count_blocks([{count, Count} | Rest], Acc) -> + count_blocks(Rest, Acc + Count); +count_blocks([_ | Rest], Acc) -> + count_blocks(Rest, Acc); +count_blocks([], Acc) -> + Acc. one_shot(CaseName) -> State = CaseName:start({1, 0, erlang:system_info(build_type)}), diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index b824daea67..b3fd3f56ab 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -2467,26 +2467,7 @@ dummy_call(_) -> ok. tmpmem() -> - case erlang:system_info({allocator,temp_alloc}) of - false -> undefined; - MemInfo -> - MSBCS = lists:foldl( - fun ({instance, 0, _}, Acc) -> - Acc; % Ignore instance 0 - ({instance, _, L}, Acc) -> - {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L), - {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L), - [MBCS,SBCS | Acc] - end, - [], - MemInfo), - lists:foldl( - fun(L, {Bl0,BlSz0}) -> - {value,{_,Bl,_,_}} = lists:keysearch(blocks, 1, L), - {value,{_,BlSz,_,_}} = lists:keysearch(blocks_size, 1, L), - {Bl0+Bl,BlSz0+BlSz} - end, {0,0}, MSBCS) - end. + erts_debug:alloc_blocks_size(temp_alloc). verify_tmpmem(MemInfo) -> %%wait_for_test_procs(), diff --git a/erts/emulator/test/send_term_SUITE.erl b/erts/emulator/test/send_term_SUITE.erl index 8afe4e4ac1..6fa19c47d4 100644 --- a/erts/emulator/test/send_term_SUITE.erl +++ b/erts/emulator/test/send_term_SUITE.erl @@ -156,27 +156,11 @@ receive_any() -> end. chk_temp_alloc() -> - case erlang:system_info({allocator,temp_alloc}) of - false -> - %% Temp alloc is not enabled - ok; - TIL -> - %% Verify that we havn't got anything allocated by temp_alloc - lists:foreach( - fun ({instance, _, TI}) -> - {value, {mbcs, MBCInfo}} - = lists:keysearch(mbcs, 1, TI), - {value, {blocks, 0, _, _}} - = lists:keysearch(blocks, 1, MBCInfo), - {value, {sbcs, SBCInfo}} - = lists:keysearch(sbcs, 1, TI), - {value, {blocks, 0, _, _}} - = lists:keysearch(blocks, 1, SBCInfo) - end, - TIL), - ok + %% Verify that we haven't got any outstanding temp_alloc allocations. + case erts_debug:alloc_blocks_size(temp_alloc) of + undefined -> ok; + 0 -> ok end. - %% Start/stop drivers. start_driver(Config, Name) -> diff --git a/erts/emulator/utils/make_alloc_types b/erts/emulator/utils/make_alloc_types index 33afe139a2..ddb8713a72 100755 --- a/erts/emulator/utils/make_alloc_types +++ b/erts/emulator/utils/make_alloc_types @@ -233,6 +233,7 @@ foreach my $a (@a_order) { $a_no--; print DST "\n#define ERTS_ALC_A_MAX ($a_no)\n"; +print DST "\n#define ERTS_ALC_A_COUNT (ERTS_ALC_A_MAX - ERTS_ALC_A_MIN + 1)\n"; # Print class numbers ----------------------------------------------------- @@ -254,6 +255,7 @@ foreach my $c (sort keys(%c_tab)) { } $c_no--; print DST "\n#define ERTS_ALC_C_MAX ($c_no)\n"; +print DST "\n#define ERTS_ALC_C_COUNT (ERTS_ALC_C_MAX - ERTS_ALC_C_MIN + 1)\n"; # Print type number intervals --------------------------------------------- @@ -291,6 +293,7 @@ foreach my $a (@a_order) { } $t_no--; print DST "#define ERTS_ALC_N_MAX ($t_no)\n"; +print DST "\n#define ERTS_ALC_N_COUNT (ERTS_ALC_N_MAX - ERTS_ALC_N_MIN + 1)\n"; # Print multi thread use of allocators ------------------------------------- diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex e79d9cafad..f280b44e3f 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index ab0cbe883e..4154e3480b 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -3914,15 +3914,6 @@ get_memval(code, #memory{code = V}) -> V; get_memval(ets, #memory{ets = V}) -> V; get_memval(_, #memory{}) -> erlang:error(badarg). -get_blocks_size([{blocks_size, Sz, _, _} | Rest], Acc) -> - get_blocks_size(Rest, Acc+Sz); -get_blocks_size([{blocks_size, Sz} | Rest], Acc) -> - get_blocks_size(Rest, Acc+Sz); -get_blocks_size([_ | Rest], Acc) -> - get_blocks_size(Rest, Acc); -get_blocks_size([], Acc) -> - Acc. - get_fix_proc([{ProcType, A1, U1}| Rest], {A0, U0}) when ProcType == proc; ProcType == monitor; ProcType == link; @@ -3965,14 +3956,15 @@ au_mem_acc(#memory{ total = Tot, processes = Proc, processes_used = ProcU } = Mem, eheap_alloc, Data) -> - Sz = get_blocks_size(Data, 0), + Sz = acc_blocks_size(Data, 0), Mem#memory{ total = Tot+Sz, processes = Proc+Sz, processes_used = ProcU+Sz}; au_mem_acc(#memory{ total = Tot, system = Sys, - ets = Ets } = Mem, ets_alloc, Data) -> - Sz = get_blocks_size(Data, 0), + ets = Ets } = Mem, + ets_alloc, Data) -> + Sz = acc_blocks_size(Data, 0), Mem#memory{ total = Tot+Sz, system = Sys+Sz, ets = Ets+Sz }; @@ -3980,31 +3972,45 @@ au_mem_acc(#memory{total = Tot, system = Sys, binary = Bin } = Mem, binary_alloc, Data) -> - Sz = get_blocks_size(Data, 0), + Sz = acc_blocks_size(Data, 0), Mem#memory{ total = Tot+Sz, system = Sys+Sz, binary = Bin+Sz}; au_mem_acc(#memory{ total = Tot, system = Sys } = Mem, _Type, Data) -> - Sz = get_blocks_size(Data, 0), + Sz = acc_blocks_size(Data, 0), Mem#memory{ total = Tot+Sz, system = Sys+Sz }. -au_mem_foreign(Mem, [{Type, SizeList} | Rest]) -> - au_mem_foreign(au_mem_acc(Mem, Type, SizeList), Rest); -au_mem_foreign(Mem, []) -> +acc_blocks_size([{size, Sz, _, _} | Rest], Acc) -> + acc_blocks_size(Rest, Acc+Sz); +acc_blocks_size([{size, Sz} | Rest], Acc) -> + acc_blocks_size(Rest, Acc+Sz); +acc_blocks_size([_ | Rest], Acc) -> + acc_blocks_size(Rest, Acc); +acc_blocks_size([], Acc) -> + Acc. + +au_mem_blocks([{blocks, L} | Rest], Mem0) -> + Mem = au_mem_blocks_1(L, Mem0), + au_mem_blocks(Rest, Mem); +au_mem_blocks([_ | Rest], Mem) -> + au_mem_blocks(Rest, Mem); +au_mem_blocks([], Mem) -> + Mem. + +au_mem_blocks_1([{Type, SizeList} | Rest], Mem) -> + au_mem_blocks_1(Rest, au_mem_acc(Mem, Type, SizeList)); +au_mem_blocks_1([], Mem) -> Mem. -au_mem_current(Mem0, Type, [{mbcs_pool, MBCS} | Rest]) -> - [Foreign] = [Foreign || {foreign_blocks, Foreign} <- MBCS], - SizeList = MBCS -- [Foreign], - Mem = au_mem_foreign(Mem0, Foreign), - au_mem_current(au_mem_acc(Mem, Type, SizeList), Type, Rest); -au_mem_current(Mem, Type, [{mbcs, SizeList} | Rest]) -> - au_mem_current(au_mem_acc(Mem, Type, SizeList), Type, Rest); -au_mem_current(Mem, Type, [{sbcs, SizeList} | Rest]) -> - au_mem_current(au_mem_acc(Mem, Type, SizeList), Type, Rest); +au_mem_current(Mem, Type, [{mbcs_pool, Stats} | Rest]) -> + au_mem_current(au_mem_blocks(Stats, Mem), Type, Rest); +au_mem_current(Mem, Type, [{mbcs, Stats} | Rest]) -> + au_mem_current(au_mem_blocks(Stats, Mem), Type, Rest); +au_mem_current(Mem, Type, [{sbcs, Stats} | Rest]) -> + au_mem_current(au_mem_blocks(Stats, Mem), Type, Rest); au_mem_current(Mem, Type, [_ | Rest]) -> au_mem_current(Mem, Type, Rest); au_mem_current(Mem, _Type, []) -> diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl index 7b9067d079..da86679532 100644 --- a/lib/kernel/src/erts_debug.erl +++ b/lib/kernel/src/erts_debug.erl @@ -526,43 +526,38 @@ alloc_blocks_size_1([], _Type, 0) -> undefined; alloc_blocks_size_1([{_Type, false} | Rest], Type, Acc) -> alloc_blocks_size_1(Rest, Type, Acc); -alloc_blocks_size_1([{Type, Instances} | Rest], Type, Acc0) -> - F = fun ({instance, _, L}, Acc) -> +alloc_blocks_size_1([{_Type, Instances} | Rest], Type, Acc) -> + F = fun ({instance, _, L}, Acc0) -> MBCSPool = case lists:keyfind(mbcs_pool, 1, L) of {_, Pool} -> Pool; false -> [] end, {_,MBCS} = lists:keyfind(mbcs, 1, L), {_,SBCS} = lists:keyfind(sbcs, 1, L), - Acc + - sum_block_sizes(MBCSPool) + - sum_block_sizes(MBCS) + - sum_block_sizes(SBCS) + Acc1 = sum_block_sizes(MBCSPool, Type, Acc0), + Acc2 = sum_block_sizes(MBCS, Type, Acc1), + sum_block_sizes(SBCS, Type, Acc2) end, - alloc_blocks_size_1(Rest, Type, lists:foldl(F, Acc0, Instances)); -alloc_blocks_size_1([{_Type, Instances} | Rest], Type, Acc0) -> - F = fun ({instance, _, L}, Acc) -> - Acc + sum_foreign_sizes(Type, L) - end, - alloc_blocks_size_1(Rest, Type, lists:foldl(F, Acc0, Instances)); + alloc_blocks_size_1(Rest, Type, lists:foldl(F, Acc, Instances)); alloc_blocks_size_1([], _Type, Acc) -> Acc. -sum_foreign_sizes(Type, L) -> - case lists:keyfind(mbcs_pool, 1, L) of - {_,Pool} -> - {_,ForeignBlocks} = lists:keyfind(foreign_blocks, 1, Pool), - case lists:keyfind(Type, 1, ForeignBlocks) of - {_,TypeSizes} -> sum_block_sizes(TypeSizes); - false -> 0 - end; - _ -> - 0 - end. +sum_block_sizes([{blocks, List} | Rest], Type, Acc) -> + sum_block_sizes(Rest, Type, sum_block_sizes_1(List, Type, Acc)); +sum_block_sizes([_ | Rest], Type, Acc) -> + sum_block_sizes(Rest, Type, Acc); +sum_block_sizes([], _Type, Acc) -> + Acc. + +sum_block_sizes_1([{Type, L} | Rest], Type, Acc0) -> + Acc = lists:foldl(fun({size, Sz,_,_}, Sz0) -> Sz0+Sz; + ({size, Sz}, Sz0) -> Sz0+Sz; + (_, Sz) -> Sz + end, Acc0, L), + sum_block_sizes_1(Rest, Type, Acc); +sum_block_sizes_1([_ | Rest], Type, Acc) -> + sum_block_sizes_1(Rest, Type, Acc); +sum_block_sizes_1([], _Type, Acc) -> + Acc. + -sum_block_sizes(Blocks) -> - lists:foldl( - fun({blocks_size, Sz,_,_}, Sz0) -> Sz0+Sz; - ({blocks_size, Sz}, Sz0) -> Sz0+Sz; - (_, Sz) -> Sz - end, 0, Blocks). diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl index da47a30fb1..1b144e05dc 100644 --- a/lib/observer/src/observer_alloc_wx.erl +++ b/lib/observer/src/observer_alloc_wx.erl @@ -261,20 +261,31 @@ sum_alloc_instances([{_,_,Data}|Instances],BS,CS,TotalBS,TotalCS) -> sum_alloc_instances([],BS,CS,TotalBS,TotalCS) -> {BS,CS,TotalBS,TotalCS,true}. -sum_alloc_one_instance([{sbmbcs,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}| - Rest],OldBS,OldCS,TotalBS,TotalCS) -> - sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS,TotalCS); -sum_alloc_one_instance([{_,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}| +sum_alloc_one_instance([{_,[{blocks,TypedBlocks},{carriers_size,CS,_,_}]}| Rest],OldBS,OldCS,TotalBS,TotalCS) -> + %% OTP 23 and later. + BS = sum_alloc_block_list(TypedBlocks, 0), sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS+BS,TotalCS+CS); -sum_alloc_one_instance([{_,[{blocks_size,BS},{carriers_size,CS}]}| +sum_alloc_one_instance([{_,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}| Rest],OldBS,OldCS,TotalBS,TotalCS) -> + %% OTP 22 and earlier. sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS+BS,TotalCS+CS); sum_alloc_one_instance([_|Rest],BS,CS,TotalBS,TotalCS) -> sum_alloc_one_instance(Rest,BS,CS,TotalBS,TotalCS); sum_alloc_one_instance([],BS,CS,TotalBS,TotalCS) -> {BS,CS,TotalBS,TotalCS}. +sum_alloc_block_list([{_Type, [{size, Current, _, _}]} | Rest], Acc) -> + %% We ignore the type since we're returning a summary of all blocks in the + %% carriers employed by a certain instance. + sum_alloc_block_list(Rest, Current + Acc); +sum_alloc_block_list([{_Type, [{size, Current}]} | Rest], Acc) -> + sum_alloc_block_list(Rest, Current + Acc); +sum_alloc_block_list([_ | Rest], Acc) -> + sum_alloc_block_list(Rest, Acc); +sum_alloc_block_list([], Acc) -> + Acc. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% create_mem_info(Parent) -> diff --git a/lib/runtime_tools/src/erts_alloc_config.erl b/lib/runtime_tools/src/erts_alloc_config.erl index 845efaf9ef..d8133ee14f 100644 --- a/lib/runtime_tools/src/erts_alloc_config.erl +++ b/lib/runtime_tools/src/erts_alloc_config.erl @@ -356,14 +356,23 @@ save_scenario(AlcList) -> process_flag(priority, OP), Res. -save_ai2(Alc, AI) -> - Alc1 = chk_sbct(Alc, AI), - case ai_value(mbcs, blocks_size, AI) of - {blocks_size, MinBS, _, MaxBS} -> - set_alloc_util(chk_mbcs_blocks_size(Alc1, MinBS, MaxBS), true); - _ -> - set_alloc_util(Alc, false) - end. +save_ai2(#alloc{name=Name}=Alc0, AI) -> + Alc1 = chk_sbct(Alc0, AI), + + {Alc, IsAUtil} = + case ai_value(mbcs, blocks, AI) of + {blocks, Bs} -> + case ai_value(Name, size, Bs) of + {size, MinBS, _, MaxBS} -> + {chk_mbcs_blocks_size(Alc1, MinBS, MaxBS), true}; + _ -> + {Alc1, false} + end; + _ -> + {Alc1, false} + end, + + set_alloc_util(Alc, IsAUtil). save_ai(Alc, [{instance, 0, AI}]) -> save_ai2(Alc, AI); diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src index 9220d5672e..b55d50d040 100644 --- a/lib/runtime_tools/src/runtime_tools.app.src +++ b/lib/runtime_tools/src/runtime_tools.app.src @@ -30,4 +30,4 @@ {env, []}, {mod, {runtime_tools, []}}, {runtime_dependencies, ["stdlib-@OTP-15251@","mnesia-4.12","kernel-@OTP-15251@", - "erts-@OTP-15251@"]}]}. + "erts-@OTP-15251:OTP-16327@"]}]}. diff --git a/lib/tools/doc/src/instrument.xml b/lib/tools/doc/src/instrument.xml index 7e9cbaebb0..7286e5c1cc 100644 --- a/lib/tools/doc/src/instrument.xml +++ b/lib/tools/doc/src/instrument.xml @@ -73,14 +73,12 @@ <desc> <p><c><anno>AllocatorType</anno></c> is the type of the allocator that employs this carrier.</p> - <p><c><anno>TotalSize</anno></c> is the total size of the carrier, - including its header.</p> - <p><c><anno>AllocatedSize</anno></c> is the combined size of the - carrier's allocated blocks, including their headers.</p> - <p><c><anno>AllocatedCount</anno></c> is the number of allocated - blocks in the carrier.</p> <p><c><anno>InPool</anno></c> is whether the carrier is in the migration pool.</p> + <p><c><anno>TotalSize</anno></c> is the total size of the carrier, + including its header.</p> + <p><c><anno>Allocations</anno></c> is a summary of the allocated blocks + in the carrier.</p> <p><c><anno>FreeBlocks</anno></c> is a histogram of the free block sizes in the carrier.</p> <p>If the carrier could not be scanned in full without harming the diff --git a/lib/tools/src/instrument.erl b/lib/tools/src/instrument.erl index 0203fefe13..1d1edcbbea 100644 --- a/lib/tools/src/instrument.erl +++ b/lib/tools/src/instrument.erl @@ -94,11 +94,12 @@ alloc_hist_merge_hist(Index, A, B) -> -type carrier_info_list() :: {HistogramStart :: non_neg_integer(), Carriers :: [{AllocatorType :: atom(), + InPool :: boolean(), TotalSize :: non_neg_integer(), UnscannedSize :: non_neg_integer(), - AllocatedSize :: non_neg_integer(), - AllocatedCount :: non_neg_integer(), - InPool :: boolean(), + Allocations :: {Type :: atom(), + Count :: non_neg_integer(), + Size :: non_neg_integer()}, FreeBlocks :: block_histogram()}]}. -spec carriers() -> {ok, Result} | {error, Reason} when diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src index f0e0fc4bec..f812c0a391 100644 --- a/lib/tools/src/tools.app.src +++ b/lib/tools/src/tools.app.src @@ -43,6 +43,6 @@ ] }, {runtime_dependencies, ["stdlib-3.4","runtime_tools-1.8.14", - "kernel-5.4","erts-9.1","compiler-5.0"]} + "kernel-5.4","erts-9.1","compiler-5.0", "erts-@OTP-16327@"]} ] }. diff --git a/lib/tools/test/instrument_SUITE.erl b/lib/tools/test/instrument_SUITE.erl index f474669836..c1a5921e04 100644 --- a/lib/tools/test/instrument_SUITE.erl +++ b/lib/tools/test/instrument_SUITE.erl @@ -194,23 +194,19 @@ verify_carriers_output(#{ histogram_start := HistStart, %% Do the carriers look alright? CarrierSet = ordsets:from_list(AllCarriers), Verified = [C || {AllocType, + InPool, TotalSize, UnscannedSize, - AllocatedSize, - AllocatedCount, - InPool, + Allocations, FreeBlockHist} = C <- CarrierSet, is_atom(AllocType), + is_boolean(InPool), is_integer(TotalSize), TotalSize >= 1, is_integer(UnscannedSize), UnscannedSize < TotalSize, UnscannedSize >= 0, - is_integer(AllocatedSize), AllocatedSize < TotalSize, - AllocatedSize >= 0, - is_integer(AllocatedCount), AllocatedCount =< AllocatedSize, - AllocatedCount >= 0, - is_boolean(InPool), + is_list(Allocations), tuple_size(FreeBlockHist) =:= HistWidth, - carrier_block_check(AllocatedCount, FreeBlockHist)], + carrier_block_check(Allocations, FreeBlockHist)], [] = ordsets:subtract(CarrierSet, Verified), %% Do we have at least as many carriers as we've generated? @@ -229,8 +225,12 @@ verify_carriers_output(#{ histogram_start := HistStart, verify_carriers_output(#{}, {error, not_enabled}) -> ok. -carrier_block_check(AllocCount, FreeHist) -> - %% A carrier must contain at least one block, and th. number of free blocks +carrier_block_check(Allocations, FreeHist) -> + AllocCount = lists:foldl(fun({_Type, Count, _Size}, Acc) -> + Count + Acc + end, 0, Allocations), + + %% A carrier must contain at least one block, and the number of free blocks %% must not exceed the number of allocated blocks + 1. FreeCount = hist_sum(FreeHist), |