diff --git a/Makefile b/Makefile index 3675d9b13..dea2f061c 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ JATTACH=jattach CC=gcc CFLAGS=-O2 CPP=g++ -CPPFLAGS=-O2 -INCLUDES=-I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux +CPPFLAGS=-O2 -D_XOPEN_SOURCE +INCLUDES=-I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I$(JAVA_HOME)/include/darwin .PHONY: test diff --git a/profiler.sh b/profiler.sh index 435b60e78..5223d47f3 100755 --- a/profiler.sh +++ b/profiler.sh @@ -35,8 +35,14 @@ show_agent_output() { OPTIND=1 SCRIPT_DIR=$(dirname $0) JATTACH=$SCRIPT_DIR/build/jattach -# realpath is not present on all distros, notably on the Travis CI image -PROFILER=$(readlink -f $SCRIPT_DIR/build/libasyncProfiler.so) +UNAME_S=$(uname -s) +if [ "$UNAME_S" == "Darwin" ]; then + PROFILER=$SCRIPT_DIR/build/libasyncProfiler.so + PROFILER=$(perl -MCwd -e 'print Cwd::abs_path shift' $PROFILER) +else + PROFILER=$(readlink -f $SCRIPT_DIR/build/libasyncProfiler.so) +fi + ACTION="collect" MODE="cpu" DURATION="60" @@ -94,7 +100,7 @@ done # if no -f argument is given, use temporary file to transfer output to caller terminal if [[ $USE_TMP ]]; then - FILE=$(mktemp --tmpdir async-profiler.XXXXXXXX) + FILE=$(mktemp /tmp/async-profiler.XXXXXXXX) fi case $ACTION in diff --git a/src/allocTracer.cpp b/src/allocTracer.cpp index fbcf3931a..12d8239ae 100755 --- a/src/allocTracer.cpp +++ b/src/allocTracer.cpp @@ -30,8 +30,8 @@ Trap AllocTracer::_outside_tlab("_ZN11AllocTracer34send_allocation_outside_tlab_ // Make the entry point writeable and insert breakpoint at the very first instruction void Trap::install() { - uintptr_t page_start = (uintptr_t)_entry & ~0xfffULL; - mprotect((void*)page_start, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); + uintptr_t page_start = (uintptr_t)_entry & ~PAGE_MASK; + mprotect((void*)page_start, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); _saved_insn = *_entry; *_entry = BREAKPOINT; diff --git a/src/arch.h b/src/arch.h index 63b7066ca..0bb3403f5 100755 --- a/src/arch.h +++ b/src/arch.h @@ -18,6 +18,12 @@ #define _ARCH_H +typedef unsigned long long u64; + +const unsigned long PAGE_SIZE = 4096; +const unsigned long PAGE_MASK = PAGE_SIZE - 1; + + #if defined(__x86_64__) || defined(__i386__) typedef unsigned char instruction_t; diff --git a/src/jattach.c b/src/jattach.c old mode 100644 new mode 100755 index be22c13d5..67fc2c93d --- a/src/jattach.c +++ b/src/jattach.c @@ -14,11 +14,6 @@ * limitations under the License. */ -#ifdef __linux__ -#define _GNU_SOURCE -#include -#endif - #include #include #include @@ -32,6 +27,11 @@ #include #include +#ifdef __linux__ +#define _GNU_SOURCE +#include +#endif + #define PATH_MAX 1024 // See hotspot/src/os/bsd/vm/os_bsd.cpp @@ -197,7 +197,7 @@ static int enter_mount_ns(int pid) { return 1; } - return setns(newns, CLONE_NEWNS) < 0 ? 0 : 1; + return setns(newns, 0) < 0 ? 0 : 1; #else return 1; #endif diff --git a/src/perfEvent.h b/src/perfEvents.h similarity index 63% rename from src/perfEvent.h rename to src/perfEvents.h index 1edeeef6c..7bad4a918 100755 --- a/src/perfEvent.h +++ b/src/perfEvents.h @@ -14,49 +14,14 @@ * limitations under the License. */ -#ifndef _PERFEVENT_H -#define _PERFEVENT_H +#ifndef _PERFEVENTS_H +#define _PERFEVENTS_H #include #include -#include -#include "spinLock.h" -typedef unsigned long long u64; -typedef unsigned int u32; -typedef unsigned short u16; -const size_t PAGE_SIZE = 4096; - - -class RingBuffer { - private: - const char* _start; - u32 _offset; - - public: - RingBuffer(struct perf_event_mmap_page* page) { - _start = (const char*)page + PAGE_SIZE; - } - - struct perf_event_header* seek(u64 offset) { - _offset = (u32)(offset & 0xfff); - return (struct perf_event_header*)(_start + _offset); - } - - u64 next() { - _offset = (_offset + sizeof(u64)) & 0xfff; - return *(u64*)(_start + _offset); - } -}; - -class PerfEvent : public SpinLock { - private: - int _fd; - struct perf_event_mmap_page* _page; - - friend class PerfEvents; -}; +class PerfEvent; class PerfEvents { private: @@ -65,7 +30,6 @@ class PerfEvents { static int _interval; static int tid(); - static int getMaxPid(); static void createForThread(int tid); static void createForAllThreads(); static void destroyForThread(int tid); @@ -88,4 +52,4 @@ class PerfEvents { } }; -#endif // _PERFEVENT_H +#endif // _PERFEVENTS_H diff --git a/src/perfEvent.cpp b/src/perfEvents_linux.cpp similarity index 86% rename from src/perfEvent.cpp rename to src/perfEvents_linux.cpp index 0a508e9c1..aab7b9740 100755 --- a/src/perfEvent.cpp +++ b/src/perfEvents_linux.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#ifdef __linux__ + #include #include #include @@ -22,9 +24,11 @@ #include #include #include +#include #include "arch.h" -#include "perfEvent.h" +#include "perfEvents.h" #include "profiler.h" +#include "spinLock.h" // Ancient fcntl.h does not define F_SETOWN_EX constants and structures @@ -39,23 +43,38 @@ struct f_owner_ex { #endif // F_SETOWN_EX -const int PROF_SIGNAL = SIGPROF; +class RingBuffer { + private: + const char* _start; + unsigned long _offset; -int PerfEvents::_max_events = 0; -PerfEvent* PerfEvents::_events = NULL; -int PerfEvents::_interval; + public: + RingBuffer(struct perf_event_mmap_page* page) { + _start = (const char*)page + PAGE_SIZE; + } + struct perf_event_header* seek(u64 offset) { + _offset = (unsigned long)offset & PAGE_MASK; + return (struct perf_event_header*)(_start + _offset); + } -void PerfEvents::init() { - _max_events = getMaxPid(); - _events = (PerfEvent*)calloc(_max_events, sizeof(PerfEvent)); -} + u64 next() { + _offset = (_offset + sizeof(u64)) & PAGE_MASK; + return *(u64*)(_start + _offset); + } +}; -int PerfEvents::tid() { - return syscall(__NR_gettid); -} -int PerfEvents::getMaxPid() { +class PerfEvent : public SpinLock { + private: + int _fd; + struct perf_event_mmap_page* _page; + + friend class PerfEvents; +}; + + +static int getMaxPID() { char buf[16] = "65536"; int fd = open("/proc/sys/kernel/pid_max", O_RDONLY); if (fd != -1) { @@ -66,6 +85,21 @@ int PerfEvents::getMaxPid() { return atoi(buf); } + +int PerfEvents::_max_events = 0; +PerfEvent* PerfEvents::_events = NULL; +int PerfEvents::_interval; + + +void PerfEvents::init() { + _max_events = getMaxPID(); + _events = (PerfEvent*)calloc(_max_events, sizeof(PerfEvent)); +} + +int PerfEvents::tid() { + return syscall(__NR_gettid); +} + void PerfEvents::createForThread(int tid) { struct perf_event_attr attr = {0}; attr.type = PERF_TYPE_SOFTWARE; @@ -99,7 +133,7 @@ void PerfEvents::createForThread(int tid) { ex.pid = tid; fcntl(fd, F_SETFL, O_ASYNC); - fcntl(fd, F_SETSIG, PROF_SIGNAL); + fcntl(fd, F_SETSIG, SIGPROF); fcntl(fd, F_SETOWN_EX, &ex); ioctl(fd, PERF_EVENT_IOC_RESET, 0); @@ -149,7 +183,7 @@ void PerfEvents::installSignalHandler() { sa.sa_sigaction = signalHandler; sa.sa_flags = SA_RESTART | SA_SIGINFO; - sigaction(PROF_SIGNAL, &sa, NULL); + sigaction(SIGPROF, &sa, NULL); } void PerfEvents::signalHandler(int signo, siginfo_t* siginfo, void* ucontext) { @@ -216,3 +250,5 @@ int PerfEvents::getCallChain(const void** callchain, int max_depth) { event->unlock(); return depth; } + +#endif // __linux__ diff --git a/src/perfEvents_macos.cpp b/src/perfEvents_macos.cpp new file mode 100755 index 000000000..572f0c1ff --- /dev/null +++ b/src/perfEvents_macos.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2017 Andrei Pangin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __APPLE__ + +#include +#include "perfEvents.h" +#include "profiler.h" + + +int PerfEvents::_max_events; +PerfEvent* PerfEvents::_events; +int PerfEvents::_interval; + + +void PerfEvents::init() {} + +int PerfEvents::tid() { return 0; } + +void PerfEvents::createForThread(int tid) {} +void PerfEvents::createForAllThreads() {} +void PerfEvents::destroyForThread(int tid) {} +void PerfEvents::destroyForAllThreads() {} + + +void PerfEvents::installSignalHandler() { + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_handler = NULL; + sa.sa_sigaction = signalHandler; + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + sigaction(SIGPROF, &sa, NULL); +} + +void PerfEvents::signalHandler(int signo, siginfo_t* siginfo, void* ucontext) { + Profiler::_instance.recordSample(ucontext, 1, NULL); +} + +bool PerfEvents::start(int interval) { + if (interval <= 0) return false; + _interval = interval; + + installSignalHandler(); + + int sec = interval / 1000000000; + int usec = (interval % 1000000000) / 1000; + struct itimerval tv = {{sec, usec}, {sec, usec}}; + setitimer(ITIMER_PROF, &tv, NULL); + + return true; +} + +void PerfEvents::stop() { + struct itimerval tv = {{0, 0}, {0, 0}}; + setitimer(ITIMER_PROF, &tv, NULL); +} + +int PerfEvents::getCallChain(const void** callchain, int max_depth) { + return 0; +} + +#endif // __APPLE__ diff --git a/src/profiler.cpp b/src/profiler.cpp index 78f282f40..16f3c9835 100755 --- a/src/profiler.cpp +++ b/src/profiler.cpp @@ -23,7 +23,7 @@ #include #include #include "profiler.h" -#include "perfEvent.h" +#include "perfEvents.h" #include "allocTracer.h" #include "stackFrame.h" #include "symbols.h" @@ -396,7 +396,7 @@ bool Profiler::start(Mode mode, int interval, int frame_buffer_size) { _frame_buffer_overflow = false; resetSymbols(); - + VMStructs::init(jvmLibrary()); bool success; if (mode == MODE_CPU) { success = PerfEvents::start(interval); @@ -567,6 +567,8 @@ void Profiler::runInternal(Arguments& args, std::ostream& out) { if (args._dump_traces > 0) dumpTraces(out, args._dump_traces); if (args._dump_flat > 0) dumpFlat(out, args._dump_flat); break; + default: + break; } } diff --git a/src/profiler.h b/src/profiler.h index 7992b8d89..f425121c0 100755 --- a/src/profiler.h +++ b/src/profiler.h @@ -20,6 +20,7 @@ #include #include #include +#include "arch.h" #include "arguments.h" #include "spinLock.h" #include "codeCache.h" @@ -33,7 +34,6 @@ const int MAX_NATIVE_FRAMES = 128; const int MAX_NATIVE_LIBS = 4096; const int CONCURRENCY_LEVEL = 16; -typedef unsigned long long u64; static inline int cmp64(u64 a, u64 b) { return a > b ? 1 : a == b ? 0 : -1; diff --git a/src/stackFrame_x64.cpp b/src/stackFrame_x64.cpp index 7b8412aff..e984b474c 100755 --- a/src/stackFrame_x64.cpp +++ b/src/stackFrame_x64.cpp @@ -19,28 +19,35 @@ #include "stackFrame.h" +#ifdef __APPLE__ +# define REG(l, m) _ucontext->uc_mcontext->__ss.m +#else +# define REG(l, m) _ucontext->uc_mcontext.gregs[l] +#endif + + uintptr_t& StackFrame::pc() { - return (uintptr_t&)_ucontext->uc_mcontext.gregs[REG_RIP]; + return (uintptr_t&)REG(REG_RIP, __rip); } uintptr_t& StackFrame::sp() { - return (uintptr_t&)_ucontext->uc_mcontext.gregs[REG_RSP]; + return (uintptr_t&)REG(REG_RSP, __rsp); } uintptr_t& StackFrame::fp() { - return (uintptr_t&)_ucontext->uc_mcontext.gregs[REG_RBP]; + return (uintptr_t&)REG(REG_RBP, __rbp); } uintptr_t StackFrame::arg0() { - return (uintptr_t)_ucontext->uc_mcontext.gregs[REG_RDI]; + return (uintptr_t)REG(REG_RDI, __rdi); } uintptr_t StackFrame::arg1() { - return (uintptr_t)_ucontext->uc_mcontext.gregs[REG_RSI]; + return (uintptr_t)REG(REG_RSI, __rsi); } uintptr_t StackFrame::arg2() { - return (uintptr_t)_ucontext->uc_mcontext.gregs[REG_RDX]; + return (uintptr_t)REG(REG_RDX, __rdx); } void StackFrame::ret() { diff --git a/src/symbols.h b/src/symbols.h index 4f08ec390..935a5bd24 100755 --- a/src/symbols.h +++ b/src/symbols.h @@ -17,69 +17,9 @@ #ifndef _SYMBOLS_H #define _SYMBOLS_H -#include #include "codeCache.h" -#ifdef __LP64__ -const unsigned char ELFCLASS_SUPPORTED = ELFCLASS64; -typedef Elf64_Ehdr ElfHeader; -typedef Elf64_Shdr ElfSection; -typedef Elf64_Nhdr ElfNote; -typedef Elf64_Sym ElfSymbol; -#else -const unsigned char ELFCLASS_SUPPORTED = ELFCLASS32; -typedef Elf32_Ehdr ElfHeader; -typedef Elf32_Shdr ElfSection; -typedef Elf32_Nhdr ElfNote; -typedef Elf32_Sym ElfSymbol; -#endif // __LP64__ - - -class ElfParser { - private: - NativeCodeCache* _cc; - const char* _base; - const char* _file_name; - ElfHeader* _header; - const char* _sections; - - ElfParser(NativeCodeCache* cc, const char* base, const void* addr, const char* file_name = NULL) { - _cc = cc; - _base = base; - _file_name = file_name; - _header = (ElfHeader*)addr; - _sections = (const char*)addr + _header->e_shoff; - } - - bool valid_header() { - unsigned char* ident = _header->e_ident; - return ident[0] == 0x7f && ident[1] == 'E' && ident[2] == 'L' && ident[3] == 'F' - && ident[4] == ELFCLASS_SUPPORTED && ident[5] == ELFDATA2LSB && ident[6] == EV_CURRENT - && _header->e_shstrndx != SHN_UNDEF; - } - - ElfSection* section(int index) { - return (ElfSection*)(_sections + index * _header->e_shentsize); - } - - const char* at(ElfSection* section) { - return (const char*)_header + section->sh_offset; - } - - ElfSection* findSection(uint32_t type, const char* name); - - void loadSymbols(bool use_debug); - bool loadSymbolsUsingBuildId(); - bool loadSymbolsUsingDebugLink(); - void loadSymbolTable(ElfSection* symtab); - - public: - static bool parseFile(NativeCodeCache* cc, const char* base, const char* file_name, bool use_debug); - static void parseMem(NativeCodeCache* cc, const char* base, const void* addr); -}; - - class Symbols { private: static void parseKernelSymbols(NativeCodeCache* cc); diff --git a/src/symbols.cpp b/src/symbols_linux.cpp similarity index 81% rename from src/symbols.cpp rename to src/symbols_linux.cpp index a65ee6f8c..1a307d68e 100755 --- a/src/symbols.cpp +++ b/src/symbols_linux.cpp @@ -14,11 +14,14 @@ * limitations under the License. */ +#ifdef __linux__ + #include #include #include #include #include +#include #include #include #include @@ -78,6 +81,65 @@ class MemoryMapDesc { }; +#ifdef __LP64__ +const unsigned char ELFCLASS_SUPPORTED = ELFCLASS64; +typedef Elf64_Ehdr ElfHeader; +typedef Elf64_Shdr ElfSection; +typedef Elf64_Nhdr ElfNote; +typedef Elf64_Sym ElfSymbol; +#else +const unsigned char ELFCLASS_SUPPORTED = ELFCLASS32; +typedef Elf32_Ehdr ElfHeader; +typedef Elf32_Shdr ElfSection; +typedef Elf32_Nhdr ElfNote; +typedef Elf32_Sym ElfSymbol; +#endif // __LP64__ + + +class ElfParser { + private: + NativeCodeCache* _cc; + const char* _base; + const char* _file_name; + ElfHeader* _header; + const char* _sections; + + ElfParser(NativeCodeCache* cc, const char* base, const void* addr, const char* file_name = NULL) { + _cc = cc; + _base = base; + _file_name = file_name; + _header = (ElfHeader*)addr; + _sections = (const char*)addr + _header->e_shoff; + } + + bool valid_header() { + unsigned char* ident = _header->e_ident; + return ident[0] == 0x7f && ident[1] == 'E' && ident[2] == 'L' && ident[3] == 'F' + && ident[4] == ELFCLASS_SUPPORTED && ident[5] == ELFDATA2LSB && ident[6] == EV_CURRENT + && _header->e_shstrndx != SHN_UNDEF; + } + + ElfSection* section(int index) { + return (ElfSection*)(_sections + index * _header->e_shentsize); + } + + const char* at(ElfSection* section) { + return (const char*)_header + section->sh_offset; + } + + ElfSection* findSection(uint32_t type, const char* name); + + void loadSymbols(bool use_debug); + bool loadSymbolsUsingBuildId(); + bool loadSymbolsUsingDebugLink(); + void loadSymbolTable(ElfSection* symtab); + + public: + static bool parseFile(NativeCodeCache* cc, const char* base, const char* file_name, bool use_debug); + static void parseMem(NativeCodeCache* cc, const char* base, const void* addr); +}; + + ElfSection* ElfParser::findSection(uint32_t type, const char* name) { const char* strtab = at(section(_header->e_shstrndx)); @@ -271,3 +333,5 @@ int Symbols::parseMaps(NativeCodeCache** array, int size) { return count; } + +#endif // __linux__ diff --git a/src/symbols_macos.cpp b/src/symbols_macos.cpp new file mode 100755 index 000000000..703dfe24b --- /dev/null +++ b/src/symbols_macos.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2017 Andrei Pangin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __APPLE__ + +#include +#include +#include +#include "symbols.h" +#include +#include +#include + +// Workaround for newer macosx versions: since 10.12.x _dyld_get_all_image_infos exists, but is not exported +extern "C" const struct dyld_all_image_infos* _dyld_get_all_image_infos(); + +class MachOParser { + private: + NativeCodeCache* _cc; + const uintptr_t _base; + const void* _header; + + load_command* findCommand(uint32_t command) { + mach_header_64* header = (mach_header_64*)_header; + load_command* result = (load_command*)((uint64_t)header + sizeof(mach_header_64)); + + if (command == 0) { + return result; + } + + for (uint32_t i = 0; i < header->ncmds; i++) { + if (result->cmd == command) { + break; + } + + result = (load_command*)((uint64_t)result + result->cmdsize); + } + return result; + } + + + void loadSymbols() { + load_command* command = findCommand(LC_SYMTAB); + symtab_command* symtab = (symtab_command*)command; + nlist_64* symbol_table = (nlist_64*)((char*)_header + symtab->symoff); + const char* str_table = (char*)_header + symtab->stroff; + + for (uint32_t sym_n = 0; sym_n < symtab->nsyms; ++sym_n) { + nlist_64 descr = symbol_table[sym_n]; + uint32_t str_offset = descr.n_un.n_strx; + uintptr_t offset = descr.n_value; + if (offset != 0) { + const char* symbol_name = &str_table[str_offset]; + if (symbol_name != NULL && (descr.n_type)) { + _cc->add((void*)(_base + offset), sizeof(uintptr_t), symbol_name + 1); + } + } + } + + _cc->sort(); + } + + public: + MachOParser(NativeCodeCache* cc, uintptr_t base, const char* header) : _cc(cc), _base(base), _header(header) { + } + + static void parseFile(NativeCodeCache* cc, uintptr_t base, const char* file_name) { + int fd = open(file_name, O_RDONLY); + if (fd == -1) { + return; + } + + size_t length = (size_t)lseek(fd, 0, SEEK_END); + void* addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + + if (addr != NULL) { + MachOParser parser(cc, base, (char*)addr); + parser.loadSymbols(); + munmap(addr, length); + } + } +}; + +void Symbols::parseKernelSymbols(NativeCodeCache* cc) { +} + +int Symbols::parseMaps(NativeCodeCache** array, int size) { + + const dyld_all_image_infos* dyld_all_image_infos = _dyld_get_all_image_infos(); + const char* lib_path = NULL; + uintptr_t loaded_lib_addr = 0; + for (int i = 0; i < dyld_all_image_infos->infoArrayCount; i++) { + const char* path = dyld_all_image_infos->infoArray[i].imageFilePath; + size_t length = strlen(path); + if (strcmp(path + length - 12, "libjvm.dylib") == 0) { + lib_path = path; + loaded_lib_addr = (uintptr_t)dyld_all_image_infos->infoArray[i].imageLoadAddress; + } + } + + if (lib_path == NULL) { + return 0; + } + + NativeCodeCache* cc = new NativeCodeCache(lib_path); + MachOParser::parseFile(cc, loaded_lib_addr, lib_path); + array[0] = cc; + return 1; +} + +#endif // __APPLE__ diff --git a/src/vmEntry.cpp b/src/vmEntry.cpp index 74402566d..4c9f9bde9 100755 --- a/src/vmEntry.cpp +++ b/src/vmEntry.cpp @@ -19,7 +19,7 @@ #include "vmEntry.h" #include "arguments.h" #include "profiler.h" -#include "perfEvent.h" +#include "perfEvents.h" #include "vmStructs.h" @@ -64,13 +64,12 @@ bool VM::init(JavaVM* vm) { _jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL); PerfEvents::init(); - VMStructs::init(); - _asyncGetCallTrace = (AsyncGetCallTrace)dlsym(RTLD_DEFAULT, "AsyncGetCallTrace"); if (_asyncGetCallTrace == NULL) { std::cerr << "Could not find AsyncGetCallTrace function" << std::endl; return false; } + return true; } diff --git a/src/vmStructs.cpp b/src/vmStructs.cpp index 8689d8acf..0436f5c28 100755 --- a/src/vmStructs.cpp +++ b/src/vmStructs.cpp @@ -13,31 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#include -#include +#include +#include #include "vmStructs.h" +#include "codeCache.h" +#include int VMStructs::_klass_name_offset = -1; int VMStructs::_symbol_length_offset = -1; int VMStructs::_symbol_body_offset = -1; - -uintptr_t VMStructs::getGlobalVar(const char* name) { - void* addr = dlsym(RTLD_DEFAULT, name); - if (addr == NULL) { +uintptr_t dereferenceSymbol(NativeCodeCache* lib, const char* symbol_name) { + const void* symbol = lib->findSymbol(symbol_name); + if (symbol == NULL || symbol < 0) { + // Fallback to avoid jvm crash in case of missing symbols return 0; } - return *(uintptr_t*)addr; + + return *((uintptr_t*)symbol); } -void VMStructs::init() { - uintptr_t entry = getGlobalVar("gHotSpotVMStructs"); - uintptr_t stride = getGlobalVar("gHotSpotVMStructEntryArrayStride"); - uintptr_t type_offset = getGlobalVar("gHotSpotVMStructEntryTypeNameOffset"); - uintptr_t field_offset = getGlobalVar("gHotSpotVMStructEntryFieldNameOffset"); - uintptr_t offset_offset = getGlobalVar("gHotSpotVMStructEntryOffsetOffset"); +void VMStructs::init(NativeCodeCache* libjvm) { + uintptr_t entry = dereferenceSymbol(libjvm, "gHotSpotVMStructs"); + uintptr_t stride = dereferenceSymbol(libjvm, "gHotSpotVMStructEntryArrayStride"); + uintptr_t type_offset = dereferenceSymbol(libjvm, "gHotSpotVMStructEntryTypeNameOffset"); + uintptr_t field_offset = dereferenceSymbol(libjvm, "gHotSpotVMStructEntryFieldNameOffset"); + uintptr_t offset_offset = dereferenceSymbol(libjvm, "gHotSpotVMStructEntryOffsetOffset"); if (entry == 0 || stride == 0) { return; diff --git a/src/vmStructs.h b/src/vmStructs.h index 855ec921a..676022ae0 100755 --- a/src/vmStructs.h +++ b/src/vmStructs.h @@ -19,11 +19,9 @@ #include +class NativeCodeCache; class VMStructs { - private: - static uintptr_t getGlobalVar(const char* name); - protected: static int _klass_name_offset; static int _symbol_length_offset; @@ -34,7 +32,7 @@ class VMStructs { } public: - static void init(); + static void init(NativeCodeCache* libjvm); static bool available() { return _klass_name_offset >= 0 diff --git a/test/AllocatingTarget.java b/test/AllocatingTarget.java new file mode 100644 index 000000000..ab9624e67 --- /dev/null +++ b/test/AllocatingTarget.java @@ -0,0 +1,21 @@ +import java.util.concurrent.ThreadLocalRandom; + + +public class AllocatingTarget { + + public static volatile Object sink; + + public static void main(String[] args) { + while (true) { + allocate(); + } + } + + private static void allocate() { + if (ThreadLocalRandom.current().nextBoolean()) { + sink = new int[128 * 1000]; + } else { + sink = new Integer[128 * 1000]; + } + } +} diff --git a/test/Target.java b/test/Target.java index d9a88a9ef..0e3b6f517 100644 --- a/test/Target.java +++ b/test/Target.java @@ -16,7 +16,9 @@ private static void method2() { private static void method3() throws Exception { for (int i = 0; i < 1000; ++i) { - new Scanner(new File("/proc/cpuinfo")).useDelimiter("\\Z").next(); + for (String s : new File("/tmp").list()) { + value += s.hashCode(); + } } } diff --git a/test/alloc-smoke-test.sh b/test/alloc-smoke-test.sh new file mode 100755 index 000000000..baaa6f122 --- /dev/null +++ b/test/alloc-smoke-test.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set -e # exit on any failure +set -x # print all executed lines + +if [ -z "${JAVA_HOME}" ] +then + echo "JAVA_HOME is not set" +fi + +( + cd $(dirname $0) + + if [ "AllocatingTarget.class" -ot "AllocatingTarget.java" ] + then + ${JAVA_HOME}/bin/javac AllocatingTarget.java + fi + + ${JAVA_HOME}/bin/java AllocatingTarget & + + FILENAME=/tmp/java.trace + JAVAPID=$! + + sleep 1 # allow the Java runtime to initialize + ../profiler.sh -f $FILENAME -o collapsed -d 5 -m heap $JAVAPID + + kill $JAVAPID + + function assert_string() { + if ! grep -q "$1" $FILENAME; then + exit 1 + fi + } + + assert_string "AllocatingTarget.allocate;.*\[Ljava/lang/Integer" + assert_string "AllocatingTarget.allocate;.*\[I" +) diff --git a/test/smoke-test.sh b/test/smoke-test.sh index 6c0f162e2..c4f9143a0 100755 --- a/test/smoke-test.sh +++ b/test/smoke-test.sh @@ -34,5 +34,5 @@ fi assert_string "Target.main;Target.method1 " assert_string "Target.main;Target.method2 " - assert_string "Target.main;Target.method3;java/util/Scanner" + assert_string "Target.main;Target.method3;java/io/File" )