| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -1104,6 +1104,300 @@ Java_com_datadoghq_profiler_JavaProfiler_dumpContext(JNIEnv* env, jclass unused) | |
| TEST_LOG("===> Context: tid:%lu, spanId=%lu, rootSpanId=%lu", OS::threadId(), spanId, rootSpanId); | ||
| } | ||
|
|
||
| // LivenessTracker/ReferenceChainTracker test seams. They mutate real tracker | ||
| // state, so they are only implemented in DEBUG builds; release builds get the | ||
| // no-op stubs below. | ||
| #ifdef DEBUG | ||
| #include "livenessTracker.h" | ||
| #include "referenceChains.h" | ||
| #include <vector> | ||
|
|
||
| extern "C" DLLEXPORT jboolean JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_setGcGenerationsEnabled0( | ||
| JNIEnv *env, jclass unused, jboolean enabled) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| LivenessTracker::instance()->setGcGenerationsForTest(enabled); | ||
| return JNI_TRUE; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_seedKlassPopulationSample0( | ||
| JNIEnv *env, jclass unused, jint klassId, jint count, jlong epoch) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| int slot; | ||
| bool created; | ||
| LivenessTracker::instance()->klassPopulationRecordForTest( | ||
| (u32)klassId, (u16)count, (u64)epoch, &slot, &created); | ||
|
Comment thread
Copy link
Copy Markdown
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityBesides the (u16) truncation (the callee takes u32, so the cast isn't needed), this passes out_evicted = nullptr. When the population table is full, recordKlassPopulationSampleLocked() evicts the LRU entry and memsets its representatives[], so those weak global refs leak. tidTrendRecordForTest()'s create path has the same issue. It's debug-only, but it's easy to collect the evicted refs and DeleteWeakGlobalRef them here like foldKlassCountsLocked() does.
Sorry, something went wrong.
All reactions
|
||
| } | ||
|
|
||
| // See tidTrendRecordForTest() (livenessTracker.h) for the tid requirements. | ||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_seedTidTrendSample0( | ||
| JNIEnv *env, jclass unused, jint klassId, jint tid, jint count, | ||
| jlong epoch) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| LivenessTracker::instance()->tidTrendRecordForTest( | ||
| (u32)klassId, (jint)tid, (u32)count, (u64)epoch); | ||
| } | ||
|
|
||
| // Makes `representative` klassId's leak-candidate representative, so a seeded | ||
| // population sample and a tagged root can drive pollWatchedTargets() without | ||
| // the real sampler or walk. The tracker owns the weak global ref created here. | ||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_setKlassPopulationRepresentativeForTest0( | ||
| JNIEnv *env, jclass unused, jint klassId, jobject representative) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| jweak rep = env->NewWeakGlobalRef(representative); | ||
| LivenessTracker::instance()->klassPopulationSetRepresentativeForTest( | ||
| env, (u32)klassId, rep); | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_resetKlassPopulationForTest0( | ||
| JNIEnv *env, jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| LivenessTracker::instance()->klassPopulationResetForTest(); | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jintArray JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_selectLeakCandidateKlassIds0( | ||
| JNIEnv *env, jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| KlassCandidate candidates[5]; | ||
| int n = LivenessTracker::instance()->selectLeakCandidates(candidates, 5); | ||
| jintArray result = env->NewIntArray(n); | ||
| if (result == nullptr || n == 0) { | ||
| return result; | ||
| } | ||
| jint ids[5]; | ||
| for (int i = 0; i < n; i++) { | ||
| ids[i] = (jint)candidates[i].klass_id; | ||
| } | ||
| env->SetIntArrayRegion(result, 0, n, ids); | ||
| return result; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jlong JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_tagAsReferenceChainRoot0( | ||
| JNIEnv *env, jclass unused, jobject target) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| jvmtiEnv *jvmti = VM::jvmti(); | ||
| if (jvmti == nullptr) { | ||
| return 0; | ||
| } | ||
| return ReferenceChainTracker::instance()->tagAsRootForTest(jvmti, env, | ||
| target); | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jboolean JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_runReferenceChainPass0( | ||
| JNIEnv *env, jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| jvmtiEnv *jvmti = VM::jvmti(); | ||
| if (jvmti == nullptr) { | ||
| return JNI_FALSE; | ||
| } | ||
| return ReferenceChainTracker::instance()->runPassSerialized(jvmti, env); | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_pollReferenceChainTargets0( | ||
| JNIEnv *env, jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| jvmtiEnv *jvmti = VM::jvmti(); | ||
| if (jvmti == nullptr) { | ||
| return; | ||
| } | ||
| ReferenceChainTracker::instance()->finishLoopIterationSerialized(jvmti, env); | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jint JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_drainReferenceChainEventCount0( | ||
| JNIEnv *env, jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| std::vector<ReferenceChainEvent> events; | ||
| ReferenceChainTracker::instance()->drainPendingChainEvents(&events); | ||
| return (jint)events.size(); | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_resetReferenceChainSearchForTest0( | ||
| JNIEnv *env, jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| jvmtiEnv *jvmti = VM::jvmti(); | ||
| if (jvmti == nullptr) { | ||
| return; | ||
| } | ||
| ReferenceChainTracker::instance()->resetSearchStateForTest(jvmti, env); | ||
| } | ||
|
|
||
| // Reads target's existing tag without tagging it. Return values are described | ||
| // at pendingExpandPositionForTest(). | ||
| extern "C" DLLEXPORT jlong JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_getReferenceChainPendingPositionForTest0( | ||
| JNIEnv *env, jclass unused, jobject target) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| jvmtiEnv *jvmti = VM::jvmti(); | ||
| if (jvmti == nullptr || target == nullptr) { | ||
| return -2; | ||
| } | ||
| jlong tag = 0; | ||
| jvmtiError err = jvmti->GetTag(target, &tag); | ||
| if (err != JVMTI_ERROR_NONE) { | ||
| return -2; | ||
| } | ||
| return (jlong)ReferenceChainTracker::instance()->pendingExpandPositionForTest( | ||
|
Comment thread
jbachorik marked this conversation as resolved.
|
||
| tag); | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jlong JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_getReferenceChainPendingSizeForTest0( | ||
| JNIEnv *env, jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| return (jlong)ReferenceChainTracker::instance()->pendingExpandSizeForTest(); | ||
| } | ||
|
|
||
| // Seeds one heap-floor sample for secondsToOOM() without waiting for a GC. | ||
| // Timestamps are only compared with each other, so any increasing sequence works. | ||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_heapFloorRecordForTest0( | ||
| JNIEnv *env, jclass unused, jlong usedBytes, jlong timestampNs) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| LivenessTracker::instance()->heapFloorRecordForTest((u64)usedBytes, | ||
| (u64)timestampNs); | ||
| } | ||
|
|
||
| // Overrides the max heap size secondsToOOM() projects against. | ||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_setMaxHeapBytesForTest0( | ||
| JNIEnv *env, jclass unused, jlong maxHeapBytes) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| LivenessTracker::instance()->setMaxHeapBytesForTest((jlong)maxHeapBytes); | ||
| } | ||
|
|
||
| // Stops real GCs from recording heap-floor samples while a test seeds them. | ||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_setHeapFloorRecordingForTest0( | ||
| JNIEnv *env, jclass unused, jboolean enabled) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| LivenessTracker::instance()->setHeapFloorRecordingForTest(enabled == JNI_TRUE); | ||
| } | ||
|
|
||
| // Whether the search-restart gate would currently allow a new search. | ||
| extern "C" DLLEXPORT jboolean JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_shouldRunPassForTest0(JNIEnv *env, | ||
| jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| return ReferenceChainTracker::instance()->shouldRunPassForTest( | ||
| OS::nanotime()) | ||
| ? JNI_TRUE | ||
| : JNI_FALSE; | ||
| } | ||
|
|
||
| // Lets a test wait for a pass that started after it created an object. | ||
| extern "C" DLLEXPORT jint JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_referenceChainPassesRunForTest0( | ||
| JNIEnv *env, jclass unused) { | ||
| ProfiledThread::initCurrentThreadSignalSafe(); | ||
| return (jint)ReferenceChainTracker::instance()->passesRun(); | ||
| } | ||
|
|
||
| #else // !DEBUG | ||
|
|
||
| // Release builds: no-op stubs so the Java natives still link. | ||
| extern "C" DLLEXPORT jboolean JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_setGcGenerationsEnabled0( | ||
| JNIEnv *env, jclass unused, jboolean enabled) { | ||
| return JNI_FALSE; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_seedKlassPopulationSample0( | ||
| JNIEnv *env, jclass unused, jint klassId, jint count, jlong epoch) {} | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_seedTidTrendSample0( | ||
| JNIEnv *env, jclass unused, jint klassId, jint tid, jint count, | ||
| jlong epoch) {} | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_setKlassPopulationRepresentativeForTest0( | ||
| JNIEnv *env, jclass unused, jint klassId, jobject representative) {} | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_resetKlassPopulationForTest0( | ||
| JNIEnv *env, jclass unused) {} | ||
|
|
||
| extern "C" DLLEXPORT jintArray JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_selectLeakCandidateKlassIds0( | ||
| JNIEnv *env, jclass unused) { | ||
| return env->NewIntArray(0); | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jlong JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_tagAsReferenceChainRoot0( | ||
| JNIEnv *env, jclass unused, jobject target) { | ||
| return 0; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jboolean JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_runReferenceChainPass0( | ||
| JNIEnv *env, jclass unused) { | ||
| return JNI_FALSE; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_pollReferenceChainTargets0( | ||
| JNIEnv *env, jclass unused) {} | ||
|
|
||
| extern "C" DLLEXPORT jint JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_drainReferenceChainEventCount0( | ||
| JNIEnv *env, jclass unused) { | ||
| return 0; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_resetReferenceChainSearchForTest0( | ||
| JNIEnv *env, jclass unused) {} | ||
|
|
||
| extern "C" DLLEXPORT jlong JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_getReferenceChainPendingPositionForTest0( | ||
| JNIEnv *env, jclass unused, jobject target) { | ||
| return -2; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jlong JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_getReferenceChainPendingSizeForTest0( | ||
| JNIEnv *env, jclass unused) { | ||
| return 0; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_heapFloorRecordForTest0( | ||
| JNIEnv *env, jclass unused, jlong usedBytes, jlong timestampNs) {} | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_setMaxHeapBytesForTest0( | ||
| JNIEnv *env, jclass unused, jlong maxHeapBytes) {} | ||
|
|
||
| extern "C" DLLEXPORT void JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_setHeapFloorRecordingForTest0( | ||
| JNIEnv *env, jclass unused, jboolean enabled) {} | ||
|
|
||
| extern "C" DLLEXPORT jboolean JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_shouldRunPassForTest0(JNIEnv *env, | ||
| jclass unused) { | ||
| return JNI_FALSE; | ||
| } | ||
|
|
||
| extern "C" DLLEXPORT jint JNICALL | ||
| Java_com_datadoghq_profiler_JavaProfiler_referenceChainPassesRunForTest0( | ||
| JNIEnv *env, jclass unused) { | ||
| return 0; | ||
| } | ||
|
|
||
| #endif // DEBUG | ||
|
|
||
| // ---- Test-only reads of the current thread's OTEP record ----------------------------------- | ||
| // Each reads the current carrier's record directly via ProfiledThread::current(), with no | ||
| // detach/attach (diagnostic-only, not on any signal-handler or hot write path). | ||
| Expand Down | ||
| Back | FazBrowse Home | New Git URL |
Uh oh!
There was an error while loading. Please reload this page.