1+ #include " arch_dd.h"
2+ #include " lockFree.h"
13#include " thread.h"
24#include " os_dd.h"
35#include " profiler.h"
1113// TLS priming signal number
1214static int g_tls_prime_signal = -1 ;
1315
16+ // Define ProfiledThread static members for Java thread tracking
17+ PaddedAtomic<uint64_t > ProfiledThread::_java_thread_bitset[ProfiledThread::JAVA_THREAD_BITSET_WORDS];
18+
19+ void ProfiledThread::initJavaThreadBitset () {
20+ for (size_t i = 0 ; i < JAVA_THREAD_BITSET_WORDS; i++) {
21+ _java_thread_bitset[i].value .store (0 , std::memory_order_relaxed);
22+ }
23+ }
24+
1425pthread_key_t ProfiledThread::_tls_key;
1526int ProfiledThread::_buffer_size = 0 ;
1627volatile int ProfiledThread::_running_buffer_pos = 0 ;
@@ -35,7 +46,8 @@ inline void ProfiledThread::freeKey(void *key) {
3546 // Buffer-allocated: reset and return to buffer for reuse
3647 tls_ref->releaseFromBuffer ();
3748 } else {
38- // Non-buffer (JVMTI-allocated): delete the instance
49+ // Non-buffer (JVMTI-allocated): unregister Java thread and delete the instance
50+ ProfiledThread::unregisterJavaThread (tls_ref->_tid );
3951 delete tls_ref;
4052 }
4153 }
@@ -54,6 +66,9 @@ void ProfiledThread::initCurrentThread() {
5466 int tid = OS::threadId ();
5567 ProfiledThread *tls = ProfiledThread::forTid (tid);
5668 pthread_setspecific (_tls_key, (const void *)tls);
69+
70+ // Register this thread as a Java thread for TLS priming optimization
71+ ProfiledThread::registerJavaThread (tid);
5772}
5873
5974void ProfiledThread::initExistingThreads () {
@@ -131,6 +146,9 @@ void ProfiledThread::doInitExistingThreads() {
131146 return ; // Avoid double initialization
132147 }
133148
149+ // Initialize Java thread bitset
150+ initJavaThreadBitset ();
151+
134152 // Register fork handler to prevent issues in forked child processes
135153 ensureTlsForkHandlerRegistered ();
136154
@@ -152,17 +170,17 @@ void ProfiledThread::doInitExistingThreads() {
152170 // Set DD_PROFILER_TLS_WATCHER=1 to enable for native thread priming
153171 // Supports both environment variable and system property (for JMH forked JVMs)
154172 const char * watcher_env = std::getenv (" DD_PROFILER_TLS_WATCHER" );
155- bool watcher_enabled = (watcher_env != nullptr && std::strcmp (watcher_env, " 1" ) == 0 );
156-
157- // If not set via environment variable, check system property (for JMH compatibility)
158- if (! watcher_enabled) {
159- char * watcher_prop = nullptr ;
160- jvmtiEnv *jvmti = VM::jvmti ();
161- if (jvmti != nullptr && jvmti->GetSystemProperty (" DD_PROFILER_TLS_WATCHER" , &watcher_prop) == 0 && watcher_prop != nullptr ) {
162- watcher_enabled = (std::strcmp (watcher_prop, " 1" ) = = 0 );
163- jvmti->Deallocate ((unsigned char *)watcher_prop);
164- }
165- }
173+ bool watcher_enabled = false ; // (watcher_env == nullptr || std::strcmp(watcher_env, "1") == 0);
174+
175+ // // If not set via environment variable, check system property (for JMH compatibility)
176+ // if (watcher_enabled) {
177+ // char* watcher_prop = nullptr;
178+ // jvmtiEnv *jvmti = VM::jvmti();
179+ // if (jvmti != nullptr && jvmti->GetSystemProperty("DD_PROFILER_TLS_WATCHER", &watcher_prop) == 0 && watcher_prop != nullptr) {
180+ // watcher_enabled = (std::strcmp(watcher_prop, "1") ! = 0);
181+ // jvmti->Deallocate((unsigned char*)watcher_prop);
182+ // }
183+ // }
166184
167185 if (watcher_enabled) {
168186 // Start thread directory watcher to prime new threads (no mass-priming of existing threads)
@@ -390,3 +408,31 @@ void ProfiledThread::simpleTlsSignalHandler(int signo) {
390408 initCurrentThreadWithBuffer ();
391409 }
392410}
411+
412+ void ProfiledThread::registerJavaThread (int tid) {
413+ // Apply Knuth multiplicative hash for better distribution
414+ size_t hash = static_cast <size_t >(tid) * KNUTH_MULTIPLICATIVE_CONSTANT;
415+ size_t bit_index = hash % JAVA_THREAD_BITSET_SIZE;
416+ size_t word_index = bit_index / 64 ;
417+ uint64_t bit_mask = 1ULL << (bit_index % 64 );
418+ _java_thread_bitset[word_index].value .fetch_or (bit_mask, std::memory_order_release);
419+ }
420+
421+ bool ProfiledThread::isLikelyJavaThread (int tid) {
422+ // Apply Knuth multiplicative hash for better distribution
423+ size_t hash = static_cast <size_t >(tid) * KNUTH_MULTIPLICATIVE_CONSTANT;
424+ size_t bit_index = hash % JAVA_THREAD_BITSET_SIZE;
425+ size_t word_index = bit_index / 64 ;
426+ uint64_t bit_mask = 1ULL << (bit_index % 64 );
427+ uint64_t word = _java_thread_bitset[word_index].value .load (std::memory_order_acquire);
428+ return (word & bit_mask) != 0 ;
429+ }
430+
431+ void ProfiledThread::unregisterJavaThread (int tid) {
432+ // Apply Knuth multiplicative hash for better distribution
433+ size_t hash = static_cast <size_t >(tid) * KNUTH_MULTIPLICATIVE_CONSTANT;
434+ size_t bit_index = hash % JAVA_THREAD_BITSET_SIZE;
435+ size_t word_index = bit_index / 64 ;
436+ uint64_t bit_mask = 1ULL << (bit_index % 64 );
437+ _java_thread_bitset[word_index].value .fetch_and (~bit_mask, std::memory_order_release);
438+ }
0 commit comments