Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ RUN mkdir /tmp/openssl && cd /tmp/openssl && \
# process of gRPC puts the OpenSSL static object files into the gRPC archive
# which causes link errors later when the agent is linked with the static
# OpenSSL library itself.
RUN git clone --depth=1 --recursive -b v1.11.0 https://github.com/grpc/grpc.git /tmp/grpc && \
RUN git clone --depth=1 --recursive -b v1.15.0 https://github.com/grpc/grpc.git /tmp/grpc && \
cd /tmp/grpc && \
cd third_party/protobuf && \
./autogen.sh && ./configure --with-pic CXXFLAGS=-Os && make -j && make install && ldconfig && \
Expand Down
3 changes: 2 additions & 1 deletion src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ using google::javaprofiler::kThreadExit;
using google::javaprofiler::kDeopt;
using google::javaprofiler::kSafepoint;

using google::javaprofiler::kNumCallTraceErrors;
using google::javaprofiler::kCallTraceErrorLineNum;
using google::javaprofiler::kMaxFramesToCapture;
using google::javaprofiler::kNativeFrameLineNum;
using google::javaprofiler::kNumCallTraceErrors;

using google::javaprofiler::JVMPI_CallFrame;
using google::javaprofiler::JVMPI_CallTrace;
Expand Down
801 changes: 85 additions & 716 deletions src/pem_roots.cc

Large diffs are not rendered by default.

60 changes: 13 additions & 47 deletions src/profiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace cloud {
namespace profiler {

google::javaprofiler::AsyncSafeTraceMultiset *Profiler::fixed_traces_ = nullptr;
std::atomic<int> Profiler::failures_[kNumCallTraceErrors + 1];
std::atomic<int> Profiler::unknown_stack_count_;

namespace {

Expand Down Expand Up @@ -78,18 +78,20 @@ void Profiler::Handle(int signum, siginfo_t *info, void *context) {

if (trace.num_frames < 0) {
// Did not get a valid java trace.
int idx = -trace.num_frames;
if (idx > kNumCallTraceErrors) {
idx = -kUnknownState;
trace.frames[0] =
JVMPI_CallFrame{kCallTraceErrorLineNum,
reinterpret_cast<jmethodID>(trace.num_frames)};
trace.num_frames = 1;
if (!fixed_traces_->Add(attr, &trace)) {
unknown_stack_count_++;
}
failures_[idx]++;
return;
}

if (frames[0].lineno >= 0) {
// Leaf is a java frame, return java trace.
if (!fixed_traces_->Add(attr, &trace)) {
failures_[-kUnknownState]++;
unknown_stack_count_++;
}
return;
}
Expand Down Expand Up @@ -137,7 +139,7 @@ void Profiler::Handle(int signum, siginfo_t *info, void *context) {
}

if (!fixed_traces_->Add(attr, &trace)) {
failures_[-kUnknownState]++;
unknown_stack_count_++;
}
}

Expand Down Expand Up @@ -180,7 +182,7 @@ void Profiler::Reset() {
} else {
fixed_traces_->Reset();
}
memset(failures_, 0, sizeof(failures_));
unknown_stack_count_ = 0;

if (FLAGS_cprof_record_native_stack) {
// When native stack collection requested, gather a single backtrace before
Expand All @@ -195,47 +197,11 @@ void Profiler::Reset() {
old_action_ = handler_.SetAction(&Profiler::Handle);
}

string CallTraceErrorToName(int err) {
switch (err) {
case kNativeStackTrace:
return "[Native code]";
case kNoClassLoad:
return "[No class load event]";
case kGcActive:
return "[GC active]";
case kUnknownNotJava:
case kNotWalkableFrameNotJava:
return "[Unknown non-Java frame]";
case kUnknownJava:
case kNotWalkableFrameJava:
return "[Unknown Java frame]";
case kUnknownState:
return "[Unknown state]";
case kThreadExit:
return "[Thread exiting]";
case kDeopt:
return "[Deopt]";
case kSafepoint:
return "[Safepoint]";
default:
return "[Unknown]";
}
}

string Profiler::SerializeProfile(
const google::javaprofiler::NativeProcessInfo &native_info) {

std::vector<FrameCount> extra_frames;
for (int i = 0; i <= kNumCallTraceErrors; i++) {
if (failures_[i] > 0) {
extra_frames.emplace_back(
FrameCount{CallTraceErrorToName(-i), failures_[i]});
}
}

return SerializeAndClearJavaCpuTraces(jvmti_, native_info, ProfileType(),
extra_frames, duration_nanos_,
period_nanos_, &aggregated_traces_);
return SerializeAndClearJavaCpuTraces(
jvmti_, native_info, ProfileType(), duration_nanos_, period_nanos_,
&aggregated_traces_, unknown_stack_count_);
}

bool AlmostThere(const struct timespec &finish, const struct timespec &lap) {
Expand Down
4 changes: 2 additions & 2 deletions src/profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class Profiler {

struct sigaction old_action_;

static std::atomic<int> failures_[
google::javaprofiler::kNumCallTraceErrors + 1]; // 1-indexed.
// Number of samples where the stack aggregation failed.
static std::atomic<int> unknown_stack_count_;

DISALLOW_COPY_AND_ASSIGN(Profiler);
};
Expand Down
59 changes: 47 additions & 12 deletions src/proto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ class ProfileProtoBuilder {
void Populate(const char *profile_type,
const google::javaprofiler::TraceMultiset &traces,
int64_t duration_ns, int64_t period_ns);
void AddArtificialSample(const string &name, int64_t count, int64_t weight,
int64_t attr);
void AddArtificialSample(const string &name, int64_t count, int64_t weight);
int64_t TotalCount() const;
int64_t TotalWeight() const;

Expand All @@ -63,6 +62,7 @@ class ProfileProtoBuilder {
int64_t weight, int64_t attr);
uint64_t LocationID(const google::javaprofiler::JVMPI_CallFrame &frame);
uint64_t LocationID(uint64_t address);
uint64_t LocationID(const string &name);
uint64_t LocationID(const string &class_name, const string &method_name,
const string &signature, const string &file_name,
int line_number);
Expand All @@ -89,10 +89,40 @@ class ProfileProtoBuilder {
DISALLOW_COPY_AND_ASSIGN(ProfileProtoBuilder);
};

namespace {

string CallTraceErrorToName(int64_t err) {
switch (err) {
case kNativeStackTrace:
return "[Native code]";
case kNoClassLoad:
return "[No class load event]";
case kGcActive:
return "[GC active]";
case kUnknownNotJava:
case kNotWalkableFrameNotJava:
return "[Unknown non-Java frame]";
case kUnknownJava:
case kNotWalkableFrameJava:
return "[Unknown Java frame]";
case kUnknownState:
return "[Unknown state]";
case kThreadExit:
return "[Thread exiting]";
case kDeopt:
return "[Deopt]";
case kSafepoint:
return "[Safepoint]";
default:
return "[Unknown]";
}
}

} // namespace

void ProfileProtoBuilder::AddArtificialSample(const string &name, int64_t count,
int64_t weight, int64_t attr) {
std::vector<uint64_t> locations = {LocationID("", name, "", "", 0)};
AddSample(locations, count, weight, attr);
int64_t weight) {
AddSample({LocationID(name)}, count, weight, 0);
}

int64_t ProfileProtoBuilder::TotalCount() const { return total_count_; }
Expand All @@ -105,6 +135,11 @@ uint64_t ProfileProtoBuilder::LocationID(
return LocationID(reinterpret_cast<uint64_t>(frame.method_id));
}

if (frame.lineno == google::javaprofiler::kCallTraceErrorLineNum) {
return LocationID(
CallTraceErrorToName(reinterpret_cast<size_t>(frame.method_id)));
}

string method_name, class_name, file_name, signature;
int line_number = 0;
google::javaprofiler::GetStackFrameElements(jvmti_, frame, &file_name,
Expand Down Expand Up @@ -132,6 +167,10 @@ uint64_t ProfileProtoBuilder::LocationID(uint64_t address) {
return location_id;
}

uint64_t ProfileProtoBuilder::LocationID(const string &name) {
return LocationID("", name, "", "", 0);
}

uint64_t ProfileProtoBuilder::LocationID(const string &class_name,
const string &method_name,
const string &signature,
Expand Down Expand Up @@ -233,15 +272,11 @@ void ProfileProtoBuilder::AddSample(const std::vector<uint64_t> &locations,

string SerializeAndClearJavaCpuTraces(
jvmtiEnv *jvmti, const google::javaprofiler::NativeProcessInfo &native_info,
const char *profile_type, const std::vector<FrameCount> &extra_frames,
int64_t duration_ns, int64_t period_ns,
google::javaprofiler::TraceMultiset *traces) {
const char *profile_type, int64_t duration_ns, int64_t period_ns,
google::javaprofiler::TraceMultiset *traces, int64_t unknown_count) {
ProfileProtoBuilder b(jvmti, native_info);
b.Populate(profile_type, *traces, duration_ns, period_ns);
for (const auto &f : extra_frames) {
// TODO: Track and report attributes for artificial samples.
b.AddArtificialSample(f.name, f.value, f.value * period_ns, 0);
}
b.AddArtificialSample("[Unknown]", unknown_count, unknown_count * period_ns);
LOG(INFO) << "Collected a profile: total count=" << b.TotalCount()
<< ", weight=" << b.TotalWeight();

Expand Down
10 changes: 2 additions & 8 deletions src/proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,13 @@
namespace cloud {
namespace profiler {

struct FrameCount {
string name;
int64_t value;
};

// Generates a CPU profile in a compressed serialized profile.proto
// from a collection of java stack traces, symbolized using the jvmti.
// Data in traces will be cleared.
string SerializeAndClearJavaCpuTraces(
jvmtiEnv *jvmti, const google::javaprofiler::NativeProcessInfo &native_info,
const char *profile_type, const std::vector<FrameCount> &extra_frames,
int64_t duration_nanos, int64_t period_nanos,
google::javaprofiler::TraceMultiset *traces);
const char *profile_type, int64_t duration_nanos, int64_t period_nanos,
google::javaprofiler::TraceMultiset *traces, int64_t unknown_count);

} // namespace profiler
} // namespace cloud
Expand Down
13 changes: 8 additions & 5 deletions third_party/javaprofiler/stacktrace_decls.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ typedef struct {
JVMPI_CallFrame *frames;
} JVMPI_CallTrace;

// The placeholder (fake) line number for native frames in
// ASGCT_CallFrame. A native frame contains this value in the lineno
// field. The method_id field contains the native PC, instead of a
// jmethodID. Native frames can be recorded without changing the
// layout of ASGCT_CallFrame this way.
// Placeholder (fake) line number for native frames in ASGCT_CallFrame. A native
// frame contains this value in the lineno field. The method_id field contains
// the native PC, instead of a jmethodID. Native frames can be recorded without
// changing the layout of ASGCT_CallFrame this way.
const jint kNativeFrameLineNum = -99;

// Placeholder (fake) line number for call trace error frames. The method_id
// field contains a value from the CallTraceErrors enumeration defined below.
const jint kCallTraceErrorLineNum = -100;

enum CallTraceErrors {
// 0 is reserved for native stack traces. This includes JIT and GC threads.
kNativeStackTrace = 0,
Expand Down