mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 22:28:22 +01:00
CostManager: introduce a free-list of ~10 intervals
and also recycle the malloc'd intervals This avoids quite some malloc/free cycles during interval managment. Change-Id: Ic2892e7c0260d0fca0e455d4728f261fb4c3800e
This commit is contained in:
parent
0481d42ad8
commit
eab39d8147
@ -611,6 +611,7 @@ typedef struct {
|
||||
// It caches the different CostCacheInterval, caches the different
|
||||
// GetLengthCost(cost_model, k) in cost_cache_ and the CostInterval's (whose
|
||||
// count_ is limited by COST_CACHE_INTERVAL_SIZE_MAX).
|
||||
#define COST_MANAGER_MAX_FREE_LIST 10
|
||||
typedef struct {
|
||||
CostInterval* head_;
|
||||
int count_; // The number of stored intervals.
|
||||
@ -619,8 +620,13 @@ typedef struct {
|
||||
double cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k).
|
||||
float* costs_;
|
||||
uint16_t* dist_array_;
|
||||
CostInterval spare_; // most of the time, we only will be using a single
|
||||
int spare_used_; // interval. => We re-use this one first if possible.
|
||||
// Most of the time, we only need few intervals -> use a free-list, to avoid
|
||||
// fragmentation with small allocs in most common cases.
|
||||
CostInterval intervals_[COST_MANAGER_MAX_FREE_LIST];
|
||||
CostInterval* free_intervals_;
|
||||
// These are regularly malloc'd remains. This list can't grow larger than than
|
||||
// size COST_CACHE_INTERVAL_SIZE_MAX - COST_MANAGER_MAX_FREE_LIST, note.
|
||||
CostInterval* recycled_intervals_;
|
||||
} CostManager;
|
||||
|
||||
static int IsCostCacheIntervalWritable(int start, int end) {
|
||||
@ -633,28 +639,52 @@ static int IsCostCacheIntervalWritable(int start, int end) {
|
||||
return (end - start + 1 < 100);
|
||||
}
|
||||
|
||||
static void CostIntervalAddToFreeList(CostManager* const manager,
|
||||
CostInterval* const interval) {
|
||||
interval->next_ = manager->free_intervals_;
|
||||
manager->free_intervals_ = interval;
|
||||
}
|
||||
|
||||
static int CostIntervalIsInFreeList(const CostManager* const manager,
|
||||
const CostInterval* const interval) {
|
||||
return (interval >= &manager->intervals_[0] &&
|
||||
interval <= &manager->intervals_[COST_MANAGER_MAX_FREE_LIST - 1]);
|
||||
}
|
||||
|
||||
static void CostManagerInitFreeList(CostManager* const manager) {
|
||||
int i;
|
||||
manager->free_intervals_ = NULL;
|
||||
for (i = 0; i < COST_MANAGER_MAX_FREE_LIST; ++i) {
|
||||
CostIntervalAddToFreeList(manager, &manager->intervals_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void DeleteIntervalList(CostManager* const manager,
|
||||
const CostInterval* interval) {
|
||||
while (interval != NULL) {
|
||||
const CostInterval* const next = interval->next_;
|
||||
if (!CostIntervalIsInFreeList(manager, interval)) {
|
||||
WebPSafeFree((void*)interval);
|
||||
} // else: do nothing
|
||||
interval = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void CostManagerClear(CostManager* const manager) {
|
||||
if (manager == NULL) return;
|
||||
|
||||
WebPSafeFree(manager->costs_);
|
||||
WebPSafeFree(manager->cache_intervals_);
|
||||
|
||||
// Clear the intervals.
|
||||
{
|
||||
CostInterval* interval = manager->head_;
|
||||
while (interval != NULL) {
|
||||
CostInterval* const next = interval->next_;
|
||||
if (manager->spare_used_ && interval == &manager->spare_) {
|
||||
manager->spare_used_ = 0;
|
||||
} else {
|
||||
WebPSafeFree(interval);
|
||||
}
|
||||
interval = next;
|
||||
}
|
||||
}
|
||||
// Clear the interval lists.
|
||||
DeleteIntervalList(manager, manager->head_);
|
||||
manager->head_ = NULL;
|
||||
DeleteIntervalList(manager, manager->recycled_intervals_);
|
||||
manager->recycled_intervals_ = NULL;
|
||||
|
||||
// Reset pointers, count_ and cache_intervals_size_.
|
||||
memset(manager, 0, sizeof(*manager));
|
||||
CostManagerInitFreeList(manager);
|
||||
}
|
||||
|
||||
static int CostManagerInit(CostManager* const manager,
|
||||
@ -667,9 +697,10 @@ static int CostManagerInit(CostManager* const manager,
|
||||
const double min_cost_diff = 0.1;
|
||||
|
||||
manager->head_ = NULL;
|
||||
manager->recycled_intervals_ = NULL;
|
||||
manager->count_ = 0;
|
||||
manager->dist_array_ = dist_array;
|
||||
manager->spare_used_ = 0;
|
||||
CostManagerInitFreeList(manager);
|
||||
|
||||
// Fill in the cost_cache_.
|
||||
manager->cache_intervals_size_ = 1;
|
||||
@ -800,10 +831,11 @@ static WEBP_INLINE void PopInterval(CostManager* const manager,
|
||||
if (interval == NULL) return;
|
||||
|
||||
ConnectIntervals(manager, interval->previous_, next);
|
||||
if (interval == &manager->spare_) {
|
||||
manager->spare_used_ = 0;
|
||||
} else {
|
||||
WebPSafeFree(interval);
|
||||
if (CostIntervalIsInFreeList(manager, interval)) {
|
||||
CostIntervalAddToFreeList(manager, interval);
|
||||
} else { // recycle regularly malloc'd intervals too
|
||||
interval->next_ = manager->recycled_intervals_;
|
||||
manager->recycled_intervals_ = interval;
|
||||
}
|
||||
--manager->count_;
|
||||
assert(manager->count_ >= 0);
|
||||
@ -867,10 +899,13 @@ static WEBP_INLINE void InsertInterval(CostManager* const manager,
|
||||
UpdateCostPerInterval(manager, start, end, index, distance_cost);
|
||||
return;
|
||||
}
|
||||
if (!manager->spare_used_) {
|
||||
interval_new = &manager->spare_;
|
||||
manager->spare_used_ = 1;
|
||||
} else {
|
||||
if (manager->free_intervals_ != NULL) {
|
||||
interval_new = manager->free_intervals_;
|
||||
manager->free_intervals_ = interval_new->next_;
|
||||
} else if (manager->recycled_intervals_ != NULL) {
|
||||
interval_new = manager->recycled_intervals_;
|
||||
manager->recycled_intervals_ = interval_new->next_;
|
||||
} else { // malloc for good
|
||||
interval_new = (CostInterval*)WebPSafeMalloc(1, sizeof(*interval_new));
|
||||
if (interval_new == NULL) {
|
||||
// Write down the interval if we cannot create it.
|
||||
|
Loading…
Reference in New Issue
Block a user