diff --git a/runtime/vm/JFRChunkWriter.cpp b/runtime/vm/JFRChunkWriter.cpp index b805c31dc49..a23724d5b27 100644 --- a/runtime/vm/JFRChunkWriter.cpp +++ b/runtime/vm/JFRChunkWriter.cpp @@ -19,13 +19,13 @@ * * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0 *******************************************************************************/ -#include "JFRUtils.hpp" #include "vm_internal.h" #if defined(J9VM_OPT_JFR) - #include "JFRChunkWriter.hpp" + #include "JFRConstantPoolTypes.hpp" +#include "JFRUtils.hpp" void VM_JFRChunkWriter::writeJFRHeader() @@ -815,4 +815,14 @@ VM_JFRChunkWriter::writeInitialSystemPropertyEvents(J9JavaVM *vm) } } + +void +VM_JFRChunkWriter::writeNativeLibraryEvents() +{ +#if defined(LINUX) + dl_iterate_phdr(dlIterateCallback, this); +#endif /* defined(LINUX) */ + +/* TODO: add implementations for other platforms */ +} #endif /* defined(J9VM_OPT_JFR) */ diff --git a/runtime/vm/JFRChunkWriter.hpp b/runtime/vm/JFRChunkWriter.hpp index b85a395009d..524209ecc76 100644 --- a/runtime/vm/JFRChunkWriter.hpp +++ b/runtime/vm/JFRChunkWriter.hpp @@ -29,6 +29,10 @@ #if defined(J9VM_OPT_JFR) +#if defined(LINUX) +#include +#endif /* defined(LINUX) */ + #include "BufferWriter.hpp" #include "JFRConstantPoolTypes.hpp" #include "JFRUtils.hpp" @@ -75,6 +79,7 @@ enum MetadataTypeID { ThreadCPULoadID = 95, PhysicalMemoryID = 107, ExecutionSampleID = 108, + NativeLibraryID = 111, ThreadID = 163, ThreadGroupID = 164, ClassID = 165, @@ -162,6 +167,7 @@ class VM_JFRChunkWriter { static constexpr int INITIAL_SYSTEM_PROPERTY_EVENT_SIZE = 6000; static constexpr int CPU_LOAD_EVENT_SIZE = (3 * sizeof(float)) + (3 * sizeof(I_64)); static constexpr int THREAD_CPU_LOAD_EVENT_SIZE = (2 * sizeof(float)) + (4 * sizeof(I_64)); + static constexpr int NATIVE_LIBRARY_EVENT_SIZE = 3000; static constexpr int METADATA_ID = 1; @@ -183,6 +189,40 @@ class VM_JFRChunkWriter { return false; } +#if defined(LINUX) + static int + dlIterateCallback(struct dl_phdr_info *info, size_t size, void *data) + { + if ((NULL == info->dlpi_name) || ('\0' == info->dlpi_name[0])) { + return 0; + } + + UDATA baseAddress = 0; + UDATA topAddress = 0; + + for (int i = 0; i < info->dlpi_phnum; i++) { + const ElfW(Phdr) *phdr = info->dlpi_phdr + i; + if (PT_LOAD == phdr->p_type) { + UDATA phdrBase = info->dlpi_addr + phdr->p_vaddr; + UDATA phdrTop = phdrBase + phdr->p_memsz; + + if ((0 == baseAddress) || (phdrBase < baseAddress)) { + baseAddress = phdrBase; + } + + if ((0 == topAddress) || (phdrTop > topAddress)) { + topAddress = phdrTop; + } + } + } + + VM_JFRChunkWriter *chunkWriter = (VM_JFRChunkWriter *)data; + chunkWriter->writeNativeLibraryEvent(baseAddress, topAddress, info->dlpi_name); + + return 0; + } +#endif /* defined(LINUX) */ + protected: public: @@ -351,6 +391,8 @@ class VM_JFRChunkWriter { writePhysicalMemoryEvent(); + writeNativeLibraryEvents(); + writeJFRHeader(); if (_bufferWriter->overflowOccurred()) { @@ -595,6 +637,25 @@ class VM_JFRChunkWriter { _bufferWriter->writeLEB128PaddedU32(dataStart, _bufferWriter->getCursor() - dataStart); } + void + writeNativeLibraryEvent(UDATA baseAddress, UDATA topAddress, const char *name) + { + /* reserve size field */ + U_8 *dataStart = _bufferWriter->getAndIncCursor(sizeof(U_32)); + + _bufferWriter->writeLEB128(NativeLibraryID); + + /* write start time */ + _bufferWriter->writeLEB128(j9time_current_time_millis()); + + writeStringLiteral(name); + + _bufferWriter->writeLEB128(baseAddress); + _bufferWriter->writeLEB128(topAddress); + /* write size */ + _bufferWriter->writeLEB128PaddedU32(dataStart, _bufferWriter->getCursor() - dataStart); + } + void writeJFRChunkToFile() { @@ -657,6 +718,8 @@ class VM_JFRChunkWriter { U_8 *writeOSInformationEvent(); + void writeNativeLibraryEvents(); + void writeInitialSystemPropertyEvents(J9JavaVM *vm); UDATA @@ -717,6 +780,8 @@ class VM_JFRChunkWriter { requiredBufferSize += _constantPoolTypes.getThreadCPULoadCount() * THREAD_CPU_LOAD_EVENT_SIZE; + requiredBufferSize += NATIVE_LIBRARY_EVENT_SIZE; + return requiredBufferSize; }