Repository: valkey-io/valkey
File: src/allocator_defrag.c (C)

Code before:
        /* Number of current slabs in the bin */
        jeQueryCtlInterface(&bin_info->info_keys.curr_slabs, &bin_usage->curr_slabs);
        /* Number of non full slabs in the bin */
        jeQueryCtlInterface(&bin_info->info_keys.nonfull_slabs, &bin_usage->curr_nonfull_slabs);

        /* Calculate the fragmentation bytes for the current bin and add it to the total. */
        frag += ((bin_info->nregs * bin_usage->curr_slabs) - bin_usage->curr_regs) * bin_info->reg_size;
    }
    return frag;
}

/* Determines whether defragmentation should be performed on a pointer based on jemalloc information.
 *
 * bin_info Pointer to the bin information structure.
 * bin_usage Pointer to the bin usage structure.
 * nalloced Number of allocated regions in the bin.
 *
 * return 1 if defragmentation should be performed, 0 otherwise.
 *
 * This function checks the following conditions to determine if defragmentation should be performed:
 * 1. If the number of allocated regions (nalloced) is equal to the total number of regions (bin_info->nregs),
 *    defragmentation is not necessary as moving regions is guaranteed not to change the fragmentation ratio.
 * 2. If the number of non-full slabs (bin_usage->curr_nonfull_slabs) is less than 2, defragmentation is not performed
 *    because there is no other slab to move regions to.
 * 3. Defrag if the slab is less than 1/8 full to ensure no low-utilization slabs left without defragged, and stabilize the defrag behavior.
 *    1/8 threshold (12.5%) chosen to align with existing utilization threshold factor.
 * 4. If slab utilization < 'avg utilization'*1.125 [code 1.125 == (1000+UTILIZATION_THRESHOLD_FACTOR_MILLI)/1000]
 *    than we should defrag. This is aligned with previous je_defrag_hint implementation.
 */
static inline int makeDefragDecision(jeBinInfo *bin_info, jemallocBinUsageData *bin_usage, unsigned long nalloced) {
    unsigned long curr_full_slabs = bin_usage->curr_slabs - bin_usage->curr_nonfull_slabs;
    size_t allocated_nonfull = bin_usage->curr_regs - curr_full_slabs * bin_info->nregs;

    /* Don't defrag if the slab is full or if there's only 1 nonfull slab */
    if (bin_info->nregs == nalloced || bin_usage->curr_nonfull_slabs < 2) return 0;

    /* Defrag if the slab is less than 1/8 full */
    if (nalloced * 8 < bin_info->nregs) return 1;

    /* Don't defrag if the slab usage is greater than the average usage (+ 12.5%) */
    if (1000 * nalloced * bin_usage->curr_nonfull_slabs > (1000 + UTILIZATION_THRESHOLD_FACTOR_MILLI) * allocated_nonfull) return 0;

    /* Otherwise, defrag! */
    return 1;
}

/*
 * Performs defragmentation analysis for a given ptr.
 *
 * ptr - ptr to memory region to be analyzed.
 *

Review comment (suggestion):
```suggestion
 * 3. Defrag if the slab is less than 1/8 full to ensure small slabs get defragmented even when average utilization is low.
 *    This also handles the case when there are items that aren't defragmented skewing the average utilization. The 1/8
 *    threshold (12.5%) was chosen to align with existing utilization threshold factor.
```

Code after:
        /* Number of current slabs in the bin */
        jeQueryCtlInterface(&bin_info->info_keys.curr_slabs, &bin_usage->curr_slabs);
        /* Number of non full slabs in the bin */
        jeQueryCtlInterface(&bin_info->info_keys.nonfull_slabs, &bin_usage->curr_nonfull_slabs);

        /* Calculate the fragmentation bytes for the current bin and add it to the total. */
        frag += ((bin_info->nregs * bin_usage->curr_slabs) - bin_usage->curr_regs) * bin_info->reg_size;
    }
    return frag;
}

/* Determines whether defragmentation should be performed on a pointer based on jemalloc information.
 *
 * bin_info Pointer to the bin information structure.
 * bin_usage Pointer to the bin usage structure.
 * nalloced Number of allocated regions in the bin.
 *
 * return 1 if defragmentation should be performed, 0 otherwise.
 *
 * This function checks the following conditions to determine if defragmentation should be performed:
 * 1. If the number of allocated regions (nalloced) is equal to the total number of regions (bin_info->nregs),
 *    defragmentation is not necessary as moving regions is guaranteed not to change the fragmentation ratio.
 * 2. If the number of non-full slabs (bin_usage->curr_nonfull_slabs) is less than 2, defragmentation is not performed
 *    because there is no other slab to move regions to.
 * 3. Defrag if the slab is less than 1/8 full to ensure small slabs get defragmented even when average utilization is low.
 *    This also handles the case when there are items that aren't defragmented skewing the average utilization. The 1/8
 *    threshold (12.5%) was chosen to align with existing utilization threshold factor.
 * 4. If slab utilization < 'avg utilization'*1.125 [code 1.125 == (1000+UTILIZATION_THRESHOLD_FACTOR_MILLI)/1000]
 *    than we should defrag. This is aligned with previous je_defrag_hint implementation.
 */
static inline int makeDefragDecision(jeBinInfo *bin_info, jemallocBinUsageData *bin_usage, unsigned long nalloced) {
    unsigned long curr_full_slabs = bin_usage->curr_slabs - bin_usage->curr_nonfull_slabs;
    size_t allocated_nonfull = bin_usage->curr_regs - curr_full_slabs * bin_info->nregs;

    /* Don't defrag if the slab is full or if there's only 1 nonfull slab */
    if (bin_info->nregs == nalloced || bin_usage->curr_nonfull_slabs < 2) return 0;

    /* Defrag if the slab is less than 1/8 full */
    if (1000 * nalloced < bin_info->nregs * UTILIZATION_THRESHOLD_FACTOR_MILLI) return 1;

    /* Don't defrag if the slab usage is greater than the average usage (+ 12.5%) */
    if (1000 * nalloced * bin_usage->curr_nonfull_slabs > (1000 + UTILIZATION_THRESHOLD_FACTOR_MILLI) * allocated_nonfull) return 0;

    /* Otherwise, defrag! */
    return 1;
}

/*
 * Performs defragmentation analysis for a given ptr.
 *
 * ptr - ptr to memory region to be analyzed.