Bool mm_extension_init(size_t addr_space_size, size_t working_size, size_t extension_size, Bool use_all_mem) { size_t extended_commit_limit; Bool res; MM_LOG(( LOG_IP, "0x%08x 0x%08x 0x%08x 0x%08x %d", (unsigned)mm_arena, addr_space_size, working_size, extension_size, (int)use_all_mem )); if ( working_size + extension_size < working_size ) /* overflow? */ extended_commit_limit = (size_t)-1; else extended_commit_limit = working_size + extension_size; if ( addr_space_size < extended_commit_limit ) return FALSE; /* a configuration error in the skin */ mm_commit_base = working_size; /* Extension beyond working_size, into arena extension, to reduce partial * paints. */ /* Always init, so it all works when the extension is configured off. */ mm_arena_extension.base = mm_arena_extension.limit = working_size; mm_arena_extension.cost = mm_cost_none; if ( extension_size > 0 ) { mm_arena_extension.limit = extended_commit_limit; mm_arena_extension.delta = 256*1024; /* guess */ mm_arena_extension.cost.tier = memory_tier_partial_paint; mm_arena_extension.cost.value = 0.1f; HQASSERT(mm_cost_less_than(mm_arena_extension.cost, mm_cost_normal), "Default cost doesn't include arena extension."); HQASSERT(mm_cost_less_than(mm_cost_below_reserves, mm_arena_extension.cost), "mm_cost_below_reserves includes arena extension."); res = low_mem_handler_register(&mm_arena_extension.handler); if ( !res ) return FALSE; } /* Extension beyond arena extension, intended to be permitted only after * a partial paint has been attempted (or is not allowed). */ /* Always init, so it all works when the extension is configured off. */ mm_use_all.base = mm_use_all.limit = mm_arena_extension.limit; mm_use_all.cost = mm_cost_none; if ( use_all_mem ) { if ( addr_space_size > mm_arena_extension.limit ) { mm_use_all.limit = addr_space_size; mm_use_all.delta = 256*1024; /* guess */ mm_use_all.cost.tier = memory_tier_trash_vm; mm_use_all.cost.value = 1.0f; HQASSERT(mm_cost_less_than(mm_use_all.cost, mm_cost_normal), "Default cost doesn't include use-all extension."); HQASSERT(mm_cost_less_than(mm_cost_below_reserves, mm_use_all.cost), "mm_cost_below_reserves includes use-all extension."); res = low_mem_handler_register(&mm_use_all.handler); if ( !res ) return FALSE; } } /* Now set the current commit limit */ mm_commit_limit = working_size; if ( mps_arena_commit_limit_set( mm_arena, mm_commit_limit ) != MPS_RES_OK ) return FALSE; /* Try to hang onto a few a spare segments. Note that we just use a small * and fairly arbitrary number here. It's small 'cos there are few pools * which exhibit the problem of repeated allocs and frees that cause * segments to be created and destroyed (examples: dl pool, and to a much * lesser extent, color pool - as it overflows onto a second segment). */ mps_arena_spare_commit_limit_set( mm_arena, (size_t)4 * 64 * 1024 ); return TRUE; }
static void test(void) { mps_pool_t poolhi, poollo; mps_thr_t thread; unsigned long com0, com1; /* create a VM arena of 30MB */ cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), (size_t) (1024*1024*40)), "create arena"); /* set the commit limit to 100MB, i.e. let the arena do the limiting */ mps_arena_commit_limit_set(arena, (size_t) (1024ul*1024ul*100ul)); cdie(mps_thread_reg(&thread, arena), "register thread"); cdie( mps_pool_create(&poolhi, arena, mps_class_mvff(), MVFF_HI_PARMS), "create high pool"); cdie( mps_pool_create(&poollo, arena, mps_class_mvff(), MVFF_LO_PARMS), "create low pool"); /* set the spare commit limit to something very big */ mps_arena_spare_commit_limit_set(arena, (size_t)-1); /* allocate a jolly big object, clamp the commit limit down, leaving 64KB space, then free it */ die(mps_alloc(&objs[0], poollo, BIGSIZE), "alloc"); com0 = mps_arena_committed(arena); mps_arena_commit_limit_set(arena, com0+(1024*64)); mps_free(poollo, objs[0], BIGSIZE); com1 = mps_arena_committed(arena); /* the free shouldn't have reduced the total amount committed */ report("reduce1", "%ld", com0-com1); /* it should be possible to reallocate the object */ die(mps_alloc(&objs[0], poollo, BIGSIZE), "alloc lo"); mps_free(poollo, objs[0], BIGSIZE); /* it should equally be possible to allocate an object in a different segment (poolhi). This ought to flush the spare. */ die(mps_alloc(&objs[0], poolhi, BIGSIZE), "alloc hi"); mps_free(poolhi, objs[0], BIGSIZE); comment("Finishing off."); mps_pool_destroy(poolhi); mps_pool_destroy(poollo); comment("Destroyed pool."); mps_thread_dereg(thread); comment("Deregistered thread."); mps_arena_destroy(arena); comment("Destroyed arena."); }
static void t_alloc(int spare, int spare_total, int commit, int obj_size) { size_t size, hisize, comsize, comlimit; size_t spsize = 0, losize = 0; /* stop warnings */ mps_res_t res, res_expected; if (obj_size == OBJ_SMALL) size = SMALL_SIZE; else size = BIG_SIZE; switch (spare_total) { case SPARE_EMPTY: spsize = 0; break; case SPARE_LESS: if (size > DIFF_SIZE) { spsize = size-DIFF_SIZE; } else { spsize = 0; } break; case SPARE_EXACT: spsize = size; break; case SPARE_MORE: spsize = size+DIFF_SIZE; break; default: error("Illegal spare.\n"); break; } switch (spare) { case SPARE_EMPTY: losize = 0; break; case SPARE_LESS: if (size > DIFF_SIZE) { losize = size-DIFF_SIZE; } else { losize = 0; } break; case SPARE_EXACT: losize = size; break; case SPARE_MORE: losize = size+DIFF_SIZE; break; } if (losize > spsize) { losize = spsize; hisize = 0; } else { hisize = spsize-losize; } /* turn off commit limit for a moment */ mps_arena_commit_limit_set(arena, HUGE); /* create low and high pools */ die( mps_pool_create(&poolhi, arena, mps_class_mvff(), MVFF_HI_PARMS), "create high pool"); die( mps_pool_create(&poollo, arena, mps_class_mvff(), MVFF_LO_PARMS), "create low pool"); /* flush hysteresis fund, then set limit */ mps_arena_spare_commit_limit_set(arena, SPARE_ZERO); mps_arena_spare_commit_limit_set(arena, SPARE_LIMIT); /* allocate something in each pool (to reduce risk of subsidiary allocation being neede later */ die(mps_alloc(&objlo, poollo, EXTEND), "low alloc"); die(mps_alloc(&objhi, poolhi, EXTEND), "high alloc"); /* set up spare committed the way we want it */ if (losize>0) { die(mps_alloc(&objlo, poollo, losize), "low setup"); mps_free(poollo, objlo, losize); } if (hisize>0) { die(mps_alloc(&objhi, poolhi, hisize), "high setup"); mps_free(poolhi, objhi, hisize); } /* spare is now set up correctly */ /* now we need to set the commit limit correctly */ comsize = arena_committed_and_used(arena); /* allow for 1/16th memory overhead in setting commit limit */ if (commit == COMMIT_EXACT) { comlimit = comsize+size+(size/16); } else if (commit == COMMIT_NOCHANGE) { comlimit = mps_arena_committed(arena); } else if (commit == COMMIT_PLENTY) { comlimit = HUGE; } else /* commit == COMMIT_LITTLE */ { if (size > DIFF_SIZE) { comlimit = comsize+size+(size/16)+DIFF_SIZE; } else { comlimit = comsize+size+(size/16); } } die(mps_arena_commit_limit_set(arena, comlimit), "commit limit set"); res = mps_alloc(&objlo, poollo, size); asserts(comlimit >= comsize, "comlimit was less than comsize!"); if (size <= (comlimit-comsize)) { res_expected = MPS_RES_OK; } else { res_expected = MPS_RES_COMMIT_LIMIT; } if (res != res_expected) { comment("Spare useful/total %i/%i. Limit %i. Size %i. Expected %s. Got %s", spare, spare_total, commit, obj_size, err_text(res_expected), err_text(res)); report("failed", "yes"); } mps_pool_destroy(poollo); mps_pool_destroy(poolhi); }