From b7c1c46796d96081317b75f172dc328523fe29e0 Mon Sep 17 00:00:00 2001 From: Andrey Pangin Date: Sun, 8 Oct 2017 22:29:40 +0300 Subject: [PATCH] Coding style. Minor bugfixes. --- Makefile | 1 + profiler.sh | 18 ++++---- src/allocTracer.cpp | 29 ++++++------ src/allocTracer.h | 1 - src/jattach.c | 31 ++++++------- src/stackFrame_aarch64.cpp | 20 ++++---- src/symbols_macos.cpp | 93 +++++++++++++++++--------------------- src/vmEntry.cpp | 2 +- src/vmStructs.cpp | 35 +++++++------- src/vmStructs.h | 5 +- test/AllocatingTarget.java | 24 +++++----- test/Target.java | 32 ++++++------- 12 files changed, 138 insertions(+), 153 deletions(-) mode change 100644 => 100755 Makefile mode change 100644 => 100755 test/AllocatingTarget.java mode change 100644 => 100755 test/Target.java diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index dea2f061c..dd630d89a --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ build/$(JATTACH): src/jattach.c test: all test/smoke-test.sh + test/alloc-smoke-test.sh clean: rm -rf build diff --git a/profiler.sh b/profiler.sh index 5223d47f3..24a5e1ed8 100755 --- a/profiler.sh +++ b/profiler.sh @@ -31,18 +31,20 @@ show_agent_output() { fi } +function abspath() { + UNAME_S=$(uname -s) + if [ "$UNAME_S" == "Darwin" ]; then + perl -MCwd -e 'print Cwd::abs_path shift' $1 + else + readlink -f $1 + fi +} + OPTIND=1 SCRIPT_DIR=$(dirname $0) JATTACH=$SCRIPT_DIR/build/jattach -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 - +PROFILER=$(abspath $SCRIPT_DIR/build/libasyncProfiler.so) ACTION="collect" MODE="cpu" DURATION="60" diff --git a/src/allocTracer.cpp b/src/allocTracer.cpp index 12d8239ae..b800b756b 100755 --- a/src/allocTracer.cpp +++ b/src/allocTracer.cpp @@ -45,17 +45,6 @@ void Trap::uninstall() { } -bool AllocTracer::checkTracerSymbols() { - if (_in_new_tlab._entry == NULL || _outside_tlab._entry == NULL) { - NativeCodeCache* libjvm = Profiler::_instance.jvmLibrary(); - if (libjvm != NULL) { - _in_new_tlab._entry = (instruction_t*)libjvm->findSymbol(_in_new_tlab._func_name); - _outside_tlab._entry = (instruction_t*)libjvm->findSymbol(_outside_tlab._func_name); - } - } - return _in_new_tlab._entry != NULL && _outside_tlab._entry != NULL; -} - void AllocTracer::installSignalHandler() { struct sigaction sa; sigemptyset(&sa.sa_mask); @@ -93,16 +82,26 @@ void AllocTracer::signalHandler(int signo, siginfo_t* siginfo, void* ucontext) { } bool AllocTracer::start() { - if (!VMStructs::available()) { - std::cerr << "VMStructs unavailable. Unsupported JVM?" << std::endl; + NativeCodeCache* libjvm = Profiler::_instance.jvmLibrary(); + if (libjvm == NULL) { + std::cerr << "libjvm not found among loaded libraries" << std::endl; return false; } - if (!checkTracerSymbols()) { - std::cerr << "No AllocTracer symbols found. Are JDK debug symbols installed?" << std::endl; + if (!VMStructs::init(libjvm)) { + std::cerr << "VMStructs unavailable. Unsupported JVM?" << std::endl; return false; } + if (_in_new_tlab._entry == NULL || _outside_tlab._entry == NULL) { + _in_new_tlab._entry = (instruction_t*)libjvm->findSymbol(_in_new_tlab._func_name); + _outside_tlab._entry = (instruction_t*)libjvm->findSymbol(_outside_tlab._func_name); + if (_in_new_tlab._entry == NULL || _outside_tlab._entry == NULL) { + std::cerr << "No AllocTracer symbols found. Are JDK debug symbols installed?" << std::endl; + return false; + } + } + installSignalHandler(); _in_new_tlab.install(); diff --git a/src/allocTracer.h b/src/allocTracer.h index 2ea5b743d..90f2fae75 100755 --- a/src/allocTracer.h +++ b/src/allocTracer.h @@ -44,7 +44,6 @@ class AllocTracer { static Trap _in_new_tlab; static Trap _outside_tlab; - static bool checkTracerSymbols(); static void installSignalHandler(); static void signalHandler(int signo, siginfo_t* siginfo, void* ucontext); diff --git a/src/jattach.c b/src/jattach.c index 67fc2c93d..7ee5993df 100755 --- a/src/jattach.c +++ b/src/jattach.c @@ -27,37 +27,32 @@ #include #include -#ifdef __linux__ -#define _GNU_SOURCE -#include -#endif - #define PATH_MAX 1024 -// See hotspot/src/os/bsd/vm/os_bsd.cpp -// This must be hard coded because it's the system's temporary -// directory not the java application's temp directory, ala java.io.tmpdir. -#ifdef __APPLE__ -// macosx has a secure per-user temporary directory -char temp_path_storage[PATH_MAX]; +#ifdef __APPLE__ +// macOS has a secure per-user temporary directory const char* get_temp_directory() { - static char *temp_path = NULL; - if (temp_path == NULL) { - int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, temp_path_storage, PATH_MAX); - if (pathSize == 0 || pathSize > PATH_MAX) { - strlcpy(temp_path_storage, "/tmp", sizeof (temp_path_storage)); + static char temp_path_storage[PATH_MAX] = {0}; + + if (temp_path_storage[0] == 0) { + int path_size = confstr(_CS_DARWIN_USER_TEMP_DIR, temp_path_storage, PATH_MAX); + if (path_size == 0 || path_size > PATH_MAX) { + strcpy(temp_path_storage, "/tmp"); } - temp_path = temp_path_storage; } - return temp_path; + return temp_path_storage; } + #else // __APPLE__ const char* get_temp_directory() { return "/tmp"; } + +int setns(int fd, int nstype); + #endif // __APPLE__ // Check if remote JVM has already opened socket for Dynamic Attach diff --git a/src/stackFrame_aarch64.cpp b/src/stackFrame_aarch64.cpp index de85f3e82..258cbfd80 100755 --- a/src/stackFrame_aarch64.cpp +++ b/src/stackFrame_aarch64.cpp @@ -21,7 +21,6 @@ #include "stackFrame.h" -#include #define REG_FP 29 #define REG_LR 30 @@ -56,16 +55,15 @@ void StackFrame::ret() { bool StackFrame::pop() { if (fp() == sp()) { - // Expected frame layout: - // sp 000000nnnnnnnnnn [stack] - // sp+8 000000nnnnnnnnnn [link] - fp() = stackAt(0); - pc() = stackAt(1); - sp() += 16; - } - else { - // Hope LR holds correct value - pc() = _ucontext->uc_mcontext.regs[REG_LR]; + // Expected frame layout: + // sp 000000nnnnnnnnnn [stack] + // sp+8 000000nnnnnnnnnn [link] + fp() = stackAt(0); + pc() = stackAt(1); + sp() += 16; + } else { + // Hope LR holds correct value + pc() = _ucontext->uc_mcontext.regs[REG_LR]; } return true; } diff --git a/src/symbols_macos.cpp b/src/symbols_macos.cpp index 703dfe24b..003b50e61 100755 --- a/src/symbols_macos.cpp +++ b/src/symbols_macos.cpp @@ -16,68 +16,60 @@ #ifdef __APPLE__ +#include +#include +#include +#include #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; + const char* _base; + const char* _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; - } + load_command* result = (load_command*)(_header + sizeof(mach_header_64)); for (uint32_t i = 0; i < header->ncmds; i++) { if (result->cmd == command) { - break; + return result; } - - result = (load_command*)((uint64_t)result + result->cmdsize); + result = (load_command*)((uintptr_t)result + result->cmdsize); } - return result; - } + return NULL; + } 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); - } - } + symtab_command* symtab = (symtab_command*)findCommand(LC_SYMTAB); + if (symtab == NULL) { + return; } - _cc->sort(); + nlist_64* symbol_table = (nlist_64*)(_header + symtab->symoff); + const char* str_table = _header + symtab->stroff; + + for (uint32_t i = 0; i < symtab->nsyms; i++) { + nlist_64 sym = symbol_table[i]; + if ((sym.n_type & 0xee) == 0x0e && sym.n_value != 0) { + _cc->add(_base + sym.n_value, 0, str_table + sym.n_un.n_strx + 1); + } + } } public: - MachOParser(NativeCodeCache* cc, uintptr_t base, const char* header) : _cc(cc), _base(base), _header(header) { + MachOParser(NativeCodeCache* cc, const char* base, const char* header) : _cc(cc), _base(base), _header(header) { } - static void parseFile(NativeCodeCache* cc, uintptr_t base, const char* file_name) { + static void parseFile(NativeCodeCache* cc, const char* base, const char* file_name) { int fd = open(file_name, O_RDONLY); if (fd == -1) { return; @@ -88,38 +80,37 @@ class MachOParser { close(fd); if (addr != NULL) { - MachOParser parser(cc, base, (char*)addr); + MachOParser parser(cc, base, (const char*)addr); parser.loadSymbols(); munmap(addr, length); } } }; + void Symbols::parseKernelSymbols(NativeCodeCache* cc) { } int Symbols::parseMaps(NativeCodeCache** array, int size) { + int count = 0; + const dyld_all_image_infos* all_images = _dyld_get_all_image_infos(); + + for (int i = 0; i < all_images->infoArrayCount && count < size; i++) { + const char* path = all_images->infoArray[i].imageFilePath; + const char* base = (const char*)all_images->infoArray[i].imageLoadAddress; - 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; + // For now load only libjvm symbols. As soon as native stack traces + // are supported on macOS, we'll take care about other native libraries 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 (length >= 12 && strcmp(path + length - 12, "libjvm.dylib") == 0) { + NativeCodeCache* cc = new NativeCodeCache(path); + MachOParser::parseFile(cc, base, path); + cc->sort(); + array[count++] = cc; } } - 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; + return count; } #endif // __APPLE__ diff --git a/src/vmEntry.cpp b/src/vmEntry.cpp index 4c9f9bde9..75a979bbd 100755 --- a/src/vmEntry.cpp +++ b/src/vmEntry.cpp @@ -20,7 +20,6 @@ #include "arguments.h" #include "profiler.h" #include "perfEvents.h" -#include "vmStructs.h" JavaVM* VM::_vm; @@ -64,6 +63,7 @@ bool VM::init(JavaVM* vm) { _jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL); PerfEvents::init(); + _asyncGetCallTrace = (AsyncGetCallTrace)dlsym(RTLD_DEFAULT, "AsyncGetCallTrace"); if (_asyncGetCallTrace == NULL) { std::cerr << "Could not find AsyncGetCallTrace function" << std::endl; diff --git a/src/vmStructs.cpp b/src/vmStructs.cpp index 0436f5c28..10a89fb77 100755 --- a/src/vmStructs.cpp +++ b/src/vmStructs.cpp @@ -13,43 +13,46 @@ * 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 dereferenceSymbol(NativeCodeCache* lib, const char* symbol_name) { +static uintptr_t readSymbol(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 + if (symbol == NULL) { + // Avoid JVM crash in case of missing symbols return 0; } - - return *((uintptr_t*)symbol); + return *(uintptr_t*)symbol; } -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"); +bool VMStructs::init(NativeCodeCache* libjvm) { + if (available()) { + return true; + } + + uintptr_t entry = readSymbol(libjvm, "gHotSpotVMStructs"); + uintptr_t stride = readSymbol(libjvm, "gHotSpotVMStructEntryArrayStride"); + uintptr_t type_offset = readSymbol(libjvm, "gHotSpotVMStructEntryTypeNameOffset"); + uintptr_t field_offset = readSymbol(libjvm, "gHotSpotVMStructEntryFieldNameOffset"); + uintptr_t offset_offset = readSymbol(libjvm, "gHotSpotVMStructEntryOffsetOffset"); if (entry == 0 || stride == 0) { - return; + return false; } while (true) { const char* type = *(const char**)(entry + type_offset); const char* field = *(const char**)(entry + field_offset); if (type == NULL || field == NULL) { - break; + return available(); } if (strcmp(type, "Klass") == 0) { diff --git a/src/vmStructs.h b/src/vmStructs.h index 676022ae0..dea260162 100755 --- a/src/vmStructs.h +++ b/src/vmStructs.h @@ -17,9 +17,8 @@ #ifndef _VMSTRUCTS_H #define _VMSTRUCTS_H -#include +#include "codeCache.h" -class NativeCodeCache; class VMStructs { protected: @@ -32,7 +31,7 @@ class VMStructs { } public: - static void init(NativeCodeCache* libjvm); + static bool init(NativeCodeCache* libjvm); static bool available() { return _klass_name_offset >= 0 diff --git a/test/AllocatingTarget.java b/test/AllocatingTarget.java old mode 100644 new mode 100755 index ab9624e67..2aa5e9ca0 --- a/test/AllocatingTarget.java +++ b/test/AllocatingTarget.java @@ -1,21 +1,19 @@ import java.util.concurrent.ThreadLocalRandom; - public class AllocatingTarget { + public static volatile Object sink; - public static volatile Object sink; - - public static void main(String[] args) { - while (true) { - allocate(); + 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]; + 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 old mode 100644 new mode 100755 index 0e3b6f517..0a6ad3c48 --- a/test/Target.java +++ b/test/Target.java @@ -2,31 +2,31 @@ import java.io.File; class Target { - private static volatile int value; + private static volatile int value; - private static void method1() { - for (int i = 0; i < 1000000; ++i) - ++value; - } + private static void method1() { + for (int i = 0; i < 1000000; ++i) + ++value; + } - private static void method2() { - for (int i = 0; i < 1000000; ++i) - ++value; - } + private static void method2() { + for (int i = 0; i < 1000000; ++i) + ++value; + } private static void method3() throws Exception { for (int i = 0; i < 1000; ++i) { - for (String s : new File("/tmp").list()) { + for (String s :new File("/tmp").list()) { value += s.hashCode(); } } } - public static void main(String[] args) throws Exception { - while (true) { - method1(); - method2(); - method3(); + public static void main(String[] args) throws Exception { + while (true) { + method1(); + method2(); + method3(); + } } - } }