diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c new file mode 100644 index 1452e8c..9c5d85a *** a/src/backend/utils/sort/tuplesort.c --- b/src/backend/utils/sort/tuplesort.c *************** struct Tuplesortstate *** 273,278 **** --- 273,280 ---- SortTuple *memtuples; /* array of SortTuple structs */ int memtupcount; /* number of tuples currently present */ int memtupsize; /* allocated length of memtuples array */ + bool final_memtupsize; /* true if we are no longer growing memtupsize */ + /* * While building initial runs, this is the current output run number *************** tuplesort_begin_common(int workMem, bool *** 546,551 **** --- 548,554 ---- state->randomAccess = randomAccess; state->bounded = false; state->boundUsed = false; + state->final_memtupsize = false; state->allowedMem = workMem * 1024L; state->availMem = state->allowedMem; state->sortcontext = sortcontext; *************** tuplesort_end(Tuplesortstate *state) *** 937,950 **** * Grow the memtuples[] array, if possible within our memory constraint. * Return TRUE if able to enlarge the array, FALSE if not. * ! * At each increment we double the size of the array. When we are short * on memory we could consider smaller increases, but because availMem ! * moves around with tuple addition/removal, this might result in thrashing. * Small increases in the array size are likely to be pretty inefficient. */ static bool grow_memtuples(Tuplesortstate *state) { /* * We need to be sure that we do not cause LACKMEM to become true, else * the space management algorithm will go nuts. We assume here that the --- 940,957 ---- * Grow the memtuples[] array, if possible within our memory constraint. * Return TRUE if able to enlarge the array, FALSE if not. * ! * At each increment except possibly the last one we double the size of ! * the array. When we are short * on memory we could consider smaller increases, but because availMem ! * moves around with tuple addition/removal, this might result in thrashing, ! * so only allow it to happen once. * Small increases in the array size are likely to be pretty inefficient. */ static bool grow_memtuples(Tuplesortstate *state) { + int new_memtupsize; + /* * We need to be sure that we do not cause LACKMEM to become true, else * the space management algorithm will go nuts. We assume here that the *************** grow_memtuples(Tuplesortstate *state) *** 953,971 **** * minimum array size established in tuplesort_begin_common is large * enough to force palloc to treat it as a separate chunk, so this * assumption should be good. But let's check it.) */ ! if (state->availMem <= (long) (state->memtupsize * sizeof(SortTuple))) return false; /* * On a 64-bit machine, allowedMem could be high enough to get us into * trouble with MaxAllocSize, too. */ ! if ((Size) (state->memtupsize * 2) >= MaxAllocSize / sizeof(SortTuple)) return false; FREEMEM(state, GetMemoryChunkSpace(state->memtuples)); ! state->memtupsize *= 2; state->memtuples = (SortTuple *) repalloc(state->memtuples, state->memtupsize * sizeof(SortTuple)); --- 960,994 ---- * minimum array size established in tuplesort_begin_common is large * enough to force palloc to treat it as a separate chunk, so this * assumption should be good. But let's check it.) + * XXXX is the new method still follow this? The last allocation is no + * longer necessarily a power of 2, but that is not freed. + * + * Once we are approaching the final growth of memtuples, use the + * historical size of the tuples seen so far try to estimate the + * best final growth size to make most efficient use of memory. */ ! if (state->final_memtupsize) return false; + if (state->availMem < state->allowedMem/2) + { + new_memtupsize = (int) ((float)state->memtupsize * (float) state->allowedMem / (float) (state->allowedMem - state->availMem)); + state->final_memtupsize = true; + } + else + { + new_memtupsize = state->memtupsize * 2; + }; + /* * On a 64-bit machine, allowedMem could be high enough to get us into * trouble with MaxAllocSize, too. */ ! if ((Size) (new_memtupsize) >= MaxAllocSize / sizeof(SortTuple)) return false; FREEMEM(state, GetMemoryChunkSpace(state->memtuples)); ! state->memtupsize = new_memtupsize; state->memtuples = (SortTuple *) repalloc(state->memtuples, state->memtupsize * sizeof(SortTuple));