Slide 1

Slide 1 text

Inner Workings of Safepoints Johannes Bechberger mostlynerdless.de

Slide 2

Slide 2 text

Kinds of Safepoints Local Safepoint/Handshake since 2017

Slide 3

Slide 3 text

Kinds of Safepoints Global Safepoint/Handshake

Slide 4

Slide 4 text

And they get ever more important

Slide 5

Slide 5 text

int mul(int a, int b) { int res = 0; while (b > 0) { res += a; b--; } return res; } Beware of inlining

Slide 6

Slide 6 text

int mul(int a, int b) { int res = 0; for (int i = 0; i < b; i++) { res += a; } return res; }

Slide 7

Slide 7 text

int mul(int a, int b) { int res = 0; for (int j = 0; j < b; j += 1000) { for (int i = j; i < j + 1000; i++) { res += i; } } return res; } Loop Strip Mining

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Safepoint biased profilers are: • Tricksy • Sneaksy • Filthy • All of the above — Nitsan Wakart “

Slide 11

Slide 11 text

Implementation

Slide 12

Slide 12 text

We could just... if (thread->at_safepoint()) { SafepointMechanism::process(); } else { // do nothing } Slow, only in interpreted mode

Slide 13

Slide 13 text

Emit in MacroAssembler testb(Address(thread_reg, JavaThread::polling_word_offset()), SafepointMechanism::poll_bit()); // handshake bit set implies poll jcc(Assembler::notZero, slow_path); https://github.com/openjdk/jdk/blob/a18b03b86fdd0eef773badbced46607a8e5a068a/src/hotspot/cpu/x8 6/macroAssembler_x86.cpp#L3073

Slide 14

Slide 14 text

We could just... if (thread->at_safepoint()) { SafepointMechanism::process(); } else { // do nothing } rare often

Slide 15

Slide 15 text

We could just... if (thread->at_safepoint()) { SafepointMechanism::process(); } else { // do nothing } slow path fast path

Slide 16

Slide 16 text

Read from pointer data Segmentation fault or

Slide 17

Slide 17 text

void method() { ... // check } name ... polling_page ... good page bad page Current Thread Safepoint disabled enabled ↯ Segfault Safepoint

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Initialize per thread char* bad_page = polling_page; char* good_page = polling_page + page_size; os::protect_memory(bad_page, page_size, os::MEM_PROT_NONE); os::protect_memory(good_page, page_size, os::MEM_PROT_READ); //... _poll_page_armed_value = reinterpret_cast(bad_page); _poll_page_disarmed_value = reinterpret_cast(good_page); https://github.com/openjdk/jdk/blob/70e7cdcb9ecedd455cf701b5c7ad05286ac0067d/src/hotspot/share/r untime/safepointMechanism.cpp#L65

Slide 20

Slide 20 text

Emit e.g. in C1 int LIR_Assembler::safepoint_poll( LIR_Opr tmp, CodeEmitInfo* info) { int offset = __ offset(); const Register poll_addr = rscratch1; __ movptr(poll_addr, Address(r15_thread, JavaThread::polling_page_offset())); // ... } https://github.com/openjdk/jdk/blob/70e7cdcb9ecedd455cf701b5c7ad05286ac0067d/src/hotspot/cpu/x8 6/c1_LIRAssembler_x86.cpp#L543

Slide 21

Slide 21 text

Arming local safepoints void SafepointMechanism::arm_local_poll( JavaThread* thread) { thread->poll_data() ->set_polling_word(_poll_word_armed_value); thread->poll_data() ->set_polling_page(_poll_page_armed_value); }

Slide 22

Slide 22 text

Arming global safepoints _state = _synchronizing; for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next();) { SafepointMechanism::arm_local_poll(cur); }

Slide 23

Slide 23 text

Tracking Safepoints

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

-Xlog:safepoint

Slide 26

Slide 26 text

G1PauseRemar k 15% G1TryInitiateConcMark 15% G1CollectFull 2% ICBufferFull 1% G1PauseCleanup 15% G1CollectForAllocation 49% Cleanup 3%

Slide 27

Slide 27 text

@parttimen3rd on Twitter parttimenerd on GitHub mostlynerdless.de @SweetSapMachine sapmachine.io