Skip to content

Commit f2ea26d

Browse files
authored
alter array alloc threshold to remove O(n^2) behavior (JuliaLang#40453)
grow faster at small n, and slower at large n, but always as a function of n, never constant
1 parent 0432ea3 commit f2ea26d

File tree

3 files changed

+25
-28
lines changed

3 files changed

+25
-28
lines changed

src/array.c

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ typedef __uint128_t wideint_t;
7070
typedef uint64_t wideint_t;
7171
#endif
7272

73-
size_t jl_arr_xtralloc_limit = 0;
74-
7573
#define MAXINTVAL (((size_t)-1)>>1)
7674

7775
static jl_array_t *_new_array_(jl_value_t *atype, uint32_t ndims, size_t *dims,
@@ -758,16 +756,23 @@ static void NOINLINE array_try_unshare(jl_array_t *a)
758756
}
759757
}
760758

761-
static size_t limit_overallocation(jl_array_t *a, size_t alen, size_t newlen, size_t inc)
759+
size_t overallocation(size_t maxsize)
762760
{
763-
// Limit overallocation to jl_arr_xtralloc_limit
764-
size_t es = a->elsize;
765-
size_t xtra_elems_mem = (newlen - a->offset - alen - inc) * es;
766-
if (xtra_elems_mem > jl_arr_xtralloc_limit) {
767-
// prune down
768-
return alen + inc + a->offset + (jl_arr_xtralloc_limit / es);
769-
}
770-
return newlen;
761+
if (maxsize < 8)
762+
return 8;
763+
// compute maxsize = maxsize + 4*maxsize^(7/8) + maxsize/8
764+
// for small n, we grow faster than O(n)
765+
// for large n, we grow at O(n/8)
766+
// and as we reach O(memory) for memory>>1MB,
767+
// this means we end by adding about 10% of memory each time
768+
int exp2 = sizeof(maxsize) * 8 -
769+
#ifdef _P64
770+
__builtin_clzll(maxsize);
771+
#else
772+
__builtin_clz(maxsize);
773+
#endif
774+
maxsize += ((size_t)1 << (exp2 * 7 / 8)) * 4 + maxsize / 8;
775+
return maxsize;
771776
}
772777

773778
STATIC_INLINE void jl_array_grow_at_beg(jl_array_t *a, size_t idx, size_t inc,
@@ -815,10 +820,12 @@ STATIC_INLINE void jl_array_grow_at_beg(jl_array_t *a, size_t idx, size_t inc,
815820
size_t nb1 = idx * elsz;
816821
if (inc > (a->maxsize - n) / 2 - (a->maxsize - n) / 20) {
817822
// not enough room for requested growth from end of array
818-
size_t newlen = a->maxsize == 0 ? inc * 2 : a->maxsize * 2;
823+
size_t newlen = inc * 2;
819824
while (n + 2 * inc > newlen - a->offset)
820825
newlen *= 2;
821-
newlen = limit_overallocation(a, n, newlen, 2 * inc);
826+
size_t newmaxsize = overallocation(a->maxsize);
827+
if (newlen < newmaxsize)
828+
newlen = newmaxsize;
822829
size_t newoffset = (newlen - newnrows) / 2;
823830
if (!array_resize_buffer(a, newlen)) {
824831
data = (char*)a->data + oldoffsnb;
@@ -903,12 +910,11 @@ STATIC_INLINE void jl_array_grow_at_end(jl_array_t *a, size_t idx,
903910
if (__unlikely(reqmaxsize > a->maxsize)) {
904911
size_t nb1 = idx * elsz;
905912
size_t nbinc = inc * elsz;
906-
// if the requested size is more than 2x current maxsize, grow exactly
907-
// otherwise double the maxsize
908-
size_t newmaxsize = reqmaxsize >= a->maxsize * 2
909-
? (reqmaxsize < 4 ? 4 : reqmaxsize)
910-
: a->maxsize * 2;
911-
newmaxsize = limit_overallocation(a, n, newmaxsize, inc);
913+
// grow either by our computed overallocation factor or exactly the requested size,
914+
// whichever is larger
915+
size_t newmaxsize = overallocation(a->maxsize);
916+
if (newmaxsize < reqmaxsize)
917+
newmaxsize = reqmaxsize;
912918
size_t oldmaxsize = a->maxsize;
913919
int newbuf = array_resize_buffer(a, newmaxsize);
914920
char *newdata = (char*)a->data + a->offset * elsz;

src/init.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -647,14 +647,6 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel)
647647
jl_init_intrinsic_properties();
648648

649649
jl_page_size = jl_getpagesize();
650-
uint64_t total_mem = uv_get_total_memory();
651-
uint64_t constrained_mem = uv_get_constrained_memory();
652-
if (constrained_mem > 0 && constrained_mem < total_mem)
653-
total_mem = constrained_mem;
654-
if (total_mem >= (size_t)-1) {
655-
total_mem = (size_t)-1;
656-
}
657-
jl_arr_xtralloc_limit = total_mem / 100; // Extra allocation limited to 1% of total RAM
658650
jl_prep_sanitizers();
659651
void *stack_lo, *stack_hi;
660652
jl_init_stack_limits(1, &stack_lo, &stack_hi);

src/julia_internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,6 @@ extern char jl_using_oprofile_jitevents;
654654
extern char jl_using_perf_jitevents;
655655
#endif
656656
extern char jl_using_gdb_jitevents;
657-
extern size_t jl_arr_xtralloc_limit;
658657

659658
// -- init.c -- //
660659

0 commit comments

Comments
 (0)