Skip to content

Commit

Permalink
Merge pull request async-profiler#56 from jvm-profiling-tools/macOS
Browse files Browse the repository at this point in the history
macOS port
  • Loading branch information
Andrei Pangin authored Oct 8, 2017
2 parents 627adcf + 9026ed3 commit be6c503
Show file tree
Hide file tree
Showing 21 changed files with 445 additions and 160 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
12 changes: 9 additions & 3 deletions profiler.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/allocTracer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions src/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions src/jattach.c
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@
* limitations under the License.
*/

#ifdef __linux__
#define _GNU_SOURCE
#include <sched.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -32,6 +27,11 @@
#include <time.h>
#include <unistd.h>

#ifdef __linux__
#define _GNU_SOURCE
#include <sched.h>
#endif

#define PATH_MAX 1024

// See hotspot/src/os/bsd/vm/os_bsd.cpp
Expand Down Expand Up @@ -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
Expand Down
44 changes: 4 additions & 40 deletions src/perfEvent.h → src/perfEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,14 @@
* limitations under the License.
*/

#ifndef _PERFEVENT_H
#define _PERFEVENT_H
#ifndef _PERFEVENTS_H
#define _PERFEVENTS_H

#include <jvmti.h>
#include <signal.h>
#include <linux/perf_event.h>
#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:
Expand All @@ -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);
Expand All @@ -88,4 +52,4 @@ class PerfEvents {
}
};

#endif // _PERFEVENT_H
#endif // _PERFEVENTS_H
66 changes: 51 additions & 15 deletions src/perfEvent.cpp → src/perfEvents_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

#ifdef __linux__

#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
Expand All @@ -22,9 +24,11 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/perf_event.h>
#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
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -216,3 +250,5 @@ int PerfEvents::getCallChain(const void** callchain, int max_depth) {
event->unlock();
return depth;
}

#endif // __linux__
76 changes: 76 additions & 0 deletions src/perfEvents_macos.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/time.h>
#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__
6 changes: 4 additions & 2 deletions src/profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#include <cxxabi.h>
#include <sys/param.h>
#include "profiler.h"
#include "perfEvent.h"
#include "perfEvents.h"
#include "allocTracer.h"
#include "stackFrame.h"
#include "symbols.h"
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <iostream>
#include <pthread.h>
#include <time.h>
#include "arch.h"
#include "arguments.h"
#include "spinLock.h"
#include "codeCache.h"
Expand All @@ -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;
Expand Down
Loading

0 comments on commit be6c503

Please sign in to comment.