Skip to content

Commit ebdea3e

Browse files
authored
Merge pull request #8751 from bjorng/bjorn/erts/fix-delay-gc/OTP-12909
Fix performance regression caused by a bug fix
2 parents c83ed06 + 8f811c9 commit ebdea3e

File tree

4 files changed

+91
-36
lines changed

4 files changed

+91
-36
lines changed

erts/emulator/beam/beam_bp.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -927,8 +927,6 @@ static void restore_cp_after_trace(Process *c_p, const Eterm cp_save[2]) {
927927
}
928928

929929
static ERTS_INLINE Uint get_allocated_words(Process *c_p, Sint allocated) {
930-
if (c_p->abandoned_heap)
931-
return allocated + c_p->htop - c_p->heap + c_p->mbuf_sz;
932930
return allocated + c_p->htop - c_p->high_water + c_p->mbuf_sz;
933931
}
934932

erts/emulator/beam/erl_bif_trace.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2908,12 +2908,10 @@ new_seq_trace_token(Process* p, int ensure_new_heap)
29082908
make_small(p->seq_trace_lastcnt));
29092909
}
29102910
else if (ensure_new_heap) {
2911-
Eterm *mature = p->abandoned_heap ? p->abandoned_heap : p->heap;
2912-
Uint mature_size = p->high_water - mature;
29132911
Eterm* tpl = tuple_val(SEQ_TRACE_TOKEN(p));
29142912
ASSERT(arityval(tpl[0]) == 5);
2915-
if (ErtsInBetween(tpl, OLD_HEAP(p), OLD_HEND(p)) ||
2916-
ErtsInArea(tpl, mature, mature_size*sizeof(Eterm))) {
2913+
2914+
if (!ErtsInBetween(tpl, p->high_water, p->hend)) {
29172915
hp = HAlloc(p, 6);
29182916
sys_memcpy(hp, tpl, 6*sizeof(Eterm));
29192917
SEQ_TRACE_TOKEN(p) = make_tuple(hp);

erts/emulator/beam/erl_gc.c

Lines changed: 81 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ do { \
9090
ASSERT((p)->abandoned_heap || (P)->heap_sz == (P)->hend - (P)->heap); \
9191
ASSERT((P)->heap <= (P)->htop && (P)->htop <= (P)->hend); \
9292
ASSERT((P)->heap <= (P)->stop && (P)->stop <= (P)->hend); \
93-
ASSERT((p)->abandoned_heap || ((P)->heap <= (P)->high_water && (P)->high_water <= (P)->hend)); \
93+
ASSERT(((P)->heap <= (P)->high_water && (P)->high_water <= (P)->hend)); \
9494
OverRunCheck((P)); \
9595
} while (0)
9696
#else
@@ -525,12 +525,28 @@ delay_garbage_collection(Process *p, int need, int fcalls)
525525
ssz = orig_hend - orig_stop;
526526
hsz = ssz + need + ERTS_DELAY_GC_EXTRA_FREE + S_RESERVED;
527527

528-
hfrag = new_message_buffer(hsz);
528+
/* Allocate one extra word at the end to save the high water mark. */
529+
hfrag = new_message_buffer(hsz + 1);
529530

530531
copy_erlang_stack(p, &hfrag->mem[0], hsz);
531532

532533
p->heap = p->htop = &hfrag->mem[0];
533-
p->hend = hend = &hfrag->mem[hsz];
534+
hend = &hfrag->mem[hsz];
535+
536+
/* Save the original high water mark at the end of the current
537+
* heap to make it possible to do a minor GC later. */
538+
if (p->abandoned_heap) {
539+
*hend = (Eterm) (p->hend[0]);
540+
} else {
541+
*hend = (Eterm) p->high_water;
542+
}
543+
544+
p->hend = hend;
545+
546+
/* Keep the high water mark pointing into the current heap to ensure
547+
* that the test for the safe range in the update_record_in_place (JIT)
548+
* stays honest. */
549+
p->high_water = p->heap;
534550

535551
if (p->abandoned_heap) {
536552
/*
@@ -543,7 +559,7 @@ delay_garbage_collection(Process *p, int need, int fcalls)
543559
Uint used = orig_htop - orig_heap;
544560
hfrag->used_size = used;
545561
p->mbuf_sz += used;
546-
ASSERT(hfrag->used_size <= hfrag->alloc_size);
562+
ASSERT(hfrag->used_size <= hfrag->alloc_size-1);
547563
ASSERT(!hfrag->off_heap.first && !hfrag->off_heap.overhead);
548564
hfrag->next = p->mbuf;
549565
p->mbuf = hfrag;
@@ -559,11 +575,6 @@ delay_garbage_collection(Process *p, int need, int fcalls)
559575
}
560576
p->abandoned_heap = orig_heap;
561577
erts_adjust_memory_break(p, orig_htop - p->high_water);
562-
563-
/* Point at the end of the address range to ensure that
564-
* test for the safe range in the new heap in the
565-
* update_record_in_place instruction fails. */
566-
p->high_water = (Eterm *) (Uint) -1;
567578
}
568579

569580
#ifdef CHECK_FOR_HOLES
@@ -637,21 +648,39 @@ young_gen_usage(Process *p, Uint *ext_msg_usage)
637648
return hsz;
638649
}
639650

640-
#define ERTS_GET_ORIG_HEAP(Proc, Heap, HTop) \
641-
do { \
642-
Eterm *aheap__ = (Proc)->abandoned_heap; \
643-
if (!aheap__) { \
644-
(Heap) = (Proc)->heap; \
645-
(HTop) = (Proc)->htop; \
646-
} \
647-
else { \
648-
(Heap) = aheap__; \
649-
if ((Proc)->flags & F_ABANDONED_HEAP_USE) \
650-
(HTop) = aheap__ + aheap__[(Proc)->heap_sz-1]; \
651-
else \
652-
(HTop) = aheap__ + (Proc)->heap_sz; \
653-
} \
654-
} while (0)
651+
static Eterm*
652+
get_orig_heap(Process *p, Eterm **p_htop, Eterm **p_high_water) {
653+
Eterm *aheap = p->abandoned_heap;
654+
Eterm *htop;
655+
656+
/* See delay_garbage_collection(). */
657+
658+
ASSERT(aheap != NULL);
659+
660+
if (p->flags & F_ABANDONED_HEAP_USE) {
661+
htop = aheap + aheap[p->heap_sz-1];
662+
} else {
663+
htop = aheap + p->heap_sz;
664+
}
665+
666+
*p_htop = htop;
667+
668+
if (p_high_water) {
669+
Eterm *high_water;
670+
671+
high_water = (Eterm *)(p->hend[0]);
672+
673+
ASSERT(aheap <= high_water);
674+
ASSERT(high_water <= htop);
675+
676+
/* The high water pointer must be aligned to a word boundary. */
677+
ASSERT(((UWord) high_water) % sizeof(UWord) == 0);
678+
679+
*p_high_water = high_water;
680+
}
681+
682+
return aheap;
683+
}
655684

656685
static ERTS_INLINE void
657686
check_for_possibly_long_gc(Process *p, Uint ygen_usage)
@@ -1383,12 +1412,32 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end,
13831412
Uint ygen_usage, Uint *recl)
13841413
{
13851414
Eterm *mature = p->abandoned_heap ? p->abandoned_heap : p->heap;
1386-
Uint mature_size = p->high_water - mature;
1415+
Eterm *high_water;
1416+
Uint mature_size;
13871417
Uint size_before = ygen_usage;
13881418
#ifdef DEBUG
13891419
Uint debug_tmp = 0;
13901420
#endif
13911421

1422+
if (p->abandoned_heap) {
1423+
/* See delay_garbage_collection(). */
1424+
high_water = (Eterm *)(p->hend[0]);
1425+
} else {
1426+
high_water = p->high_water;
1427+
}
1428+
1429+
#ifdef DEBUG
1430+
if (p->abandoned_heap) {
1431+
ASSERT(p->abandoned_heap <= high_water);
1432+
ASSERT(high_water - p->abandoned_heap <= size_before);
1433+
1434+
/* The high water pointer must be aligned to a word boundary. */
1435+
ASSERT(((UWord) high_water) % sizeof(UWord) == 0);
1436+
}
1437+
#endif
1438+
1439+
mature_size = high_water - mature;
1440+
13921441
need += S_RESERVED;
13931442

13941443
/*
@@ -3659,9 +3708,11 @@ erts_process_gc_info(Process *p, Uint *sizep, Eterm **hpp,
36593708
ERTS_CT_ASSERT(sizeof(values)/sizeof(*values) == ERTS_PROCESS_GC_INFO_MAX_TERMS);
36603709

36613710
if (p->abandoned_heap) {
3662-
Eterm *htop, *heap;
3663-
ERTS_GET_ORIG_HEAP(p, heap, htop);
3664-
values[3] = HIGH_WATER(p) - heap;
3711+
Eterm *htop, *heap, *high_water;
3712+
3713+
heap = get_orig_heap(p, &htop, &high_water);
3714+
3715+
values[3] = high_water - heap;
36653716
values[6] = htop - heap;
36663717
}
36673718

@@ -3906,7 +3957,7 @@ erts_dbg_within_proc(Eterm *ptr, Process *p, Eterm *real_htop)
39063957
Eterm *htop, *heap;
39073958

39083959
if (p->abandoned_heap) {
3909-
ERTS_GET_ORIG_HEAP(p, heap, htop);
3960+
heap = get_orig_heap(p, &htop, NULL);
39103961
if (heap <= ptr && ptr < htop)
39113962
return 1;
39123963
}
@@ -4017,7 +4068,7 @@ erts_dbg_check_heap_terms(int (*check_eterm)(Eterm),
40174068
Eterm *htop, *heap;
40184069

40194070
if (p->abandoned_heap) {
4020-
ERTS_GET_ORIG_HEAP(p, heap, htop);
4071+
heap = get_orig_heap(p, &htop, NULL);
40214072
if (!check_all_heap_terms_in_range(check_eterm,
40224073
heap, htop))
40234074
return 0;

erts/emulator/beam/erl_process.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,15 @@ struct process {
10571057

10581058
Eterm* heap; /* Heap start */
10591059
Eterm* hend; /* Heap end */
1060+
1061+
/* If abandoned_heap is not a NULL pointer, it points to the heap
1062+
* that was active when delay_garbage_collection() in erl_gc.c was
1063+
* called. The high water mark that was active at that time is
1064+
* saved in p->hend[0].
1065+
*/
1066+
10601067
Eterm* abandoned_heap;
1068+
10611069
Uint heap_sz; /* Size of heap in words */
10621070
Uint min_heap_size; /* Minimum size of heap (in words). */
10631071
Uint min_vheap_size; /* Minimum size of virtual heap (in words). */

0 commit comments

Comments
 (0)