提交 09121154 编写于 作者: D Denghui Dong 提交者: D-D-H

[Backport] 8225797: OldObjectSample event creates unexpected amount of checkpoint data

Summary:

Test Plan: jdk/jfr

Reviewed-by: yuleil

Issue: https://github.com/alibaba/dragonwell8/issues/112
上级 49c13aa0
...@@ -1461,7 +1461,7 @@ static void copy_method_trace_flags(const InstanceKlass* the_original_klass, con ...@@ -1461,7 +1461,7 @@ static void copy_method_trace_flags(const InstanceKlass* the_original_klass, con
assert(new_method != NULL, "invariant"); assert(new_method != NULL, "invariant");
assert(new_method->name() == old_method->name(), "invariant"); assert(new_method->name() == old_method->name(), "invariant");
assert(new_method->signature() == old_method->signature(), "invariant"); assert(new_method->signature() == old_method->signature(), "invariant");
*new_method->trace_flags_addr() = old_method->trace_flags(); new_method->set_trace_flags(old_method->trace_flags());
assert(new_method->trace_flags() == old_method->trace_flags(), "invariant"); assert(new_method->trace_flags() == old_method->trace_flags(), "invariant");
} }
} }
......
/* /*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -92,7 +92,9 @@ void Jfr::on_vm_shutdown(bool exception_handler) { ...@@ -92,7 +92,9 @@ void Jfr::on_vm_shutdown(bool exception_handler) {
} }
void Jfr::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { void Jfr::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
LeakProfiler::oops_do(is_alive, f); if (LeakProfiler::is_running()) {
LeakProfiler::oops_do(is_alive, f);
}
} }
void Jfr::weak_oops_do(OopClosure* f) { void Jfr::weak_oops_do(OopClosure* f) {
......
...@@ -55,18 +55,23 @@ bool EdgeStore::is_empty() const { ...@@ -55,18 +55,23 @@ bool EdgeStore::is_empty() const {
return !_edges->has_entries(); return !_edges->has_entries();
} }
void EdgeStore::assign_id(EdgeEntry* entry) { void EdgeStore::on_link(EdgeEntry* entry) {
assert(entry != NULL, "invariant"); assert(entry != NULL, "invariant");
assert(entry->id() == 0, "invariant"); assert(entry->id() == 0, "invariant");
entry->set_id(++_edge_id_counter); entry->set_id(++_edge_id_counter);
} }
bool EdgeStore::equals(const Edge& query, uintptr_t hash, const EdgeEntry* entry) { bool EdgeStore::on_equals(uintptr_t hash, const EdgeEntry* entry) {
assert(entry != NULL, "invariant"); assert(entry != NULL, "invariant");
assert(entry->hash() == hash, "invariant"); assert(entry->hash() == hash, "invariant");
return true; return true;
} }
void EdgeStore::on_unlink(EdgeEntry* entry) {
assert(entry != NULL, "invariant");
// nothing
}
#ifdef ASSERT #ifdef ASSERT
bool EdgeStore::contains(const oop* reference) const { bool EdgeStore::contains(const oop* reference) const {
return get(reference) != NULL; return get(reference) != NULL;
...@@ -75,22 +80,21 @@ bool EdgeStore::contains(const oop* reference) const { ...@@ -75,22 +80,21 @@ bool EdgeStore::contains(const oop* reference) const {
StoredEdge* EdgeStore::get(const oop* reference) const { StoredEdge* EdgeStore::get(const oop* reference) const {
assert(reference != NULL, "invariant"); assert(reference != NULL, "invariant");
const StoredEdge e(NULL, reference); EdgeEntry* const entry = _edges->lookup_only((uintptr_t)reference);
EdgeEntry* const entry = _edges->lookup_only(e, (uintptr_t)reference);
return entry != NULL ? entry->literal_addr() : NULL; return entry != NULL ? entry->literal_addr() : NULL;
} }
StoredEdge* EdgeStore::put(const oop* reference) { StoredEdge* EdgeStore::put(const oop* reference) {
assert(reference != NULL, "invariant"); assert(reference != NULL, "invariant");
const StoredEdge e(NULL, reference); const StoredEdge e(NULL, reference);
assert(NULL == _edges->lookup_only(e, (uintptr_t)reference), "invariant"); assert(NULL == _edges->lookup_only((uintptr_t)reference), "invariant");
EdgeEntry& entry = _edges->put(e, (uintptr_t)reference); EdgeEntry& entry = _edges->put((uintptr_t)reference, e);
return entry.literal_addr(); return entry.literal_addr();
} }
traceid EdgeStore::get_id(const Edge* edge) const { traceid EdgeStore::get_id(const Edge* edge) const {
assert(edge != NULL, "invariant"); assert(edge != NULL, "invariant");
EdgeEntry* const entry = _edges->lookup_only(*edge, (uintptr_t)edge->reference()); EdgeEntry* const entry = _edges->lookup_only((uintptr_t)edge->reference());
assert(entry != NULL, "invariant"); assert(entry != NULL, "invariant");
return entry->id(); return entry->id();
} }
......
...@@ -58,7 +58,7 @@ class StoredEdge : public Edge { ...@@ -58,7 +58,7 @@ class StoredEdge : public Edge {
}; };
class EdgeStore : public CHeapObj<mtTracing> { class EdgeStore : public CHeapObj<mtTracing> {
typedef HashTableHost<StoredEdge, traceid, Entry, EdgeStore> EdgeHashTable; typedef HashTableHost<StoredEdge, traceid, JfrHashtableEntry, EdgeStore> EdgeHashTable;
typedef EdgeHashTable::HashEntry EdgeEntry; typedef EdgeHashTable::HashEntry EdgeEntry;
template <typename, template <typename,
typename, typename,
...@@ -74,8 +74,9 @@ class EdgeStore : public CHeapObj<mtTracing> { ...@@ -74,8 +74,9 @@ class EdgeStore : public CHeapObj<mtTracing> {
EdgeHashTable* _edges; EdgeHashTable* _edges;
// Hash table callbacks // Hash table callbacks
void assign_id(EdgeEntry* entry); void on_link(EdgeEntry* entry);
bool equals(const Edge& query, uintptr_t hash, const EdgeEntry* entry); bool on_equals(uintptr_t hash, const EdgeEntry* entry);
void on_unlink(EdgeEntry* entry);
StoredEdge* get(const oop* reference) const; StoredEdge* get(const oop* reference) const;
StoredEdge* put(const oop* reference); StoredEdge* put(const oop* reference);
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/leakprofiler/sampling/objectSampler.hpp"
#include "jfr/leakprofiler/utilities/granularTimer.hpp" #include "jfr/leakprofiler/utilities/granularTimer.hpp"
#include "memory/universe.hpp" #include "memory/universe.hpp"
#include "oops/markOop.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "runtime/safepoint.hpp" #include "runtime/safepoint.hpp"
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
...@@ -101,7 +100,7 @@ void PathToGcRootsOperation::doit() { ...@@ -101,7 +100,7 @@ void PathToGcRootsOperation::doit() {
// Save the original markWord for the potential leak objects, // Save the original markWord for the potential leak objects,
// to be restored on function exit // to be restored on function exit
ObjectSampleMarker marker; ObjectSampleMarker marker;
if (ObjectSampleCheckpoint::mark(_sampler, marker, _emit_all) == 0) { if (ObjectSampleCheckpoint::save_mark_words(_sampler, marker, _emit_all) == 0) {
// no valid samples to process // no valid samples to process
return; return;
} }
......
...@@ -26,27 +26,35 @@ ...@@ -26,27 +26,35 @@
#define SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP #define SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "jfr/utilities/jfrTypes.hpp"
class EdgeStore; class EdgeStore;
class JavaThread;
class JfrCheckpointWriter; class JfrCheckpointWriter;
class JfrStackTrace;
class JfrStackTraceRepository; class JfrStackTraceRepository;
class Klass;
class Method;
class ObjectSample;
class ObjectSampleMarker; class ObjectSampleMarker;
class ObjectSampler; class ObjectSampler;
class Thread;
class ObjectSampleCheckpoint : AllStatic { class ObjectSampleCheckpoint : AllStatic {
public: friend class EventEmitter;
static void install(JfrCheckpointWriter& writer, bool class_unload, bool type_set); friend class PathToGcRootsOperation;
static void write(ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread); friend class StackTraceBlobInstaller;
static int mark(ObjectSampler* sampler, ObjectSampleMarker& marker, bool emit_all);
};
class WriteObjectSampleStacktrace : public StackObj {
private: private:
ObjectSampler* const _sampler; static void add_to_leakp_set(const Method* method, traceid method_id);
JfrStackTraceRepository& _stack_trace_repo; static int save_mark_words(const ObjectSampler* sampler, ObjectSampleMarker& marker, bool emit_all);
static void write_stacktrace(const JfrStackTrace* trace, JfrCheckpointWriter& writer);
static void write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread);
public: public:
WriteObjectSampleStacktrace(ObjectSampler* sampler, JfrStackTraceRepository& repo); static void on_klass_unload(const Klass* k);
bool process(); static void on_type_set(JfrCheckpointWriter& writer);
static void on_type_set_unload(JfrCheckpointWriter& writer);
static void on_thread_exit(JavaThread* jt);
static void on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& repo);
}; };
#endif // SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP #endif // SHARE_VM_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
...@@ -33,8 +33,8 @@ ...@@ -33,8 +33,8 @@
#include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/leakprofiler/sampling/objectSampler.hpp"
#include "jfr/leakprofiler/utilities/rootType.hpp" #include "jfr/leakprofiler/utilities/rootType.hpp"
#include "jfr/leakprofiler/utilities/unifiedOop.hpp" #include "jfr/leakprofiler/utilities/unifiedOop.hpp"
#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" #include "jfr/metadata/jfrSerializer.hpp"
#include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp" #include "jfr/writers/jfrTypeWriterHost.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "oops/symbol.hpp" #include "oops/symbol.hpp"
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
...@@ -137,30 +137,33 @@ class FieldTable : public ResourceObj { ...@@ -137,30 +137,33 @@ class FieldTable : public ResourceObj {
typename, typename,
size_t> size_t>
friend class HashTableHost; friend class HashTableHost;
typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, Entry, FieldTable, 109> FieldInfoTable; typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, JfrHashtableEntry, FieldTable, 109> FieldInfoTable;
public: public:
typedef FieldInfoTable::HashEntry FieldInfoEntry; typedef FieldInfoTable::HashEntry FieldInfoEntry;
private: private:
static traceid _field_id_counter; static traceid _field_id_counter;
FieldInfoTable* _table; FieldInfoTable* _table;
const ObjectSampleFieldInfo* _lookup;
void assign_id(FieldInfoEntry* entry) { void on_link(FieldInfoEntry* entry) {
assert(entry != NULL, "invariant"); assert(entry != NULL, "invariant");
entry->set_id(++_field_id_counter); entry->set_id(++_field_id_counter);
} }
bool equals(const ObjectSampleFieldInfo* query, uintptr_t hash, const FieldInfoEntry* entry) { bool on_equals(uintptr_t hash, const FieldInfoEntry* entry) {
assert(hash == entry->hash(), "invariant"); assert(hash == entry->hash(), "invariant");
assert(query != NULL, "invariant"); assert(_lookup != NULL, "invariant");
const ObjectSampleFieldInfo* stored = entry->literal(); return entry->literal()->_field_modifiers == _lookup->_field_modifiers;
assert(stored != NULL, "invariant"); }
assert(((Symbol*)stored->_field_name_symbol)->identity_hash() == ((Symbol*)query->_field_name_symbol)->identity_hash(), "invariant");
return stored->_field_modifiers == query->_field_modifiers; void on_unlink(FieldInfoEntry* entry) {
assert(entry != NULL, "invariant");
// nothing
} }
public: public:
FieldTable() : _table(new FieldInfoTable(this)) {} FieldTable() : _table(new FieldInfoTable(this)), _lookup(NULL) {}
~FieldTable() { ~FieldTable() {
assert(_table != NULL, "invariant"); assert(_table != NULL, "invariant");
delete _table; delete _table;
...@@ -168,8 +171,8 @@ class FieldTable : public ResourceObj { ...@@ -168,8 +171,8 @@ class FieldTable : public ResourceObj {
traceid store(const ObjectSampleFieldInfo* field_info) { traceid store(const ObjectSampleFieldInfo* field_info) {
assert(field_info != NULL, "invariant"); assert(field_info != NULL, "invariant");
const FieldInfoEntry& entry =_table->lookup_put(field_info, _lookup = field_info;
((Symbol*)field_info->_field_name_symbol)->identity_hash()); const FieldInfoEntry& entry = _table->lookup_put(((Symbol*)field_info->_field_name_symbol)->identity_hash(), field_info);
return entry.id(); return entry.id();
} }
...@@ -196,7 +199,7 @@ static ArrayInfo* array_infos = NULL; ...@@ -196,7 +199,7 @@ static ArrayInfo* array_infos = NULL;
static FieldTable* field_infos = NULL; static FieldTable* field_infos = NULL;
static RootDescriptionInfo* root_infos = NULL; static RootDescriptionInfo* root_infos = NULL;
int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* si) { int __write_sample_info__(JfrCheckpointWriter* writer, const void* si) {
assert(writer != NULL, "invariant"); assert(writer != NULL, "invariant");
assert(si != NULL, "invariant"); assert(si != NULL, "invariant");
const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si; const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si;
...@@ -211,17 +214,17 @@ int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, c ...@@ -211,17 +214,17 @@ int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, c
return 1; return 1;
} }
typedef JfrArtifactWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl; typedef JfrTypeWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;
typedef JfrArtifactWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter; typedef JfrTypeWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;
static void write_sample_infos(JfrCheckpointWriter& writer) { static void write_sample_infos(JfrCheckpointWriter& writer) {
if (sample_infos != NULL) { if (sample_infos != NULL) {
SampleWriter sw(&writer, NULL, false); SampleWriter sw(&writer);
sample_infos->iterate(sw); sample_infos->iterate(sw);
} }
} }
int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ri) { int __write_reference_info__(JfrCheckpointWriter* writer, const void* ri) {
assert(writer != NULL, "invariant"); assert(writer != NULL, "invariant");
assert(ri != NULL, "invariant"); assert(ri != NULL, "invariant");
const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri; const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri;
...@@ -233,17 +236,17 @@ int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused ...@@ -233,17 +236,17 @@ int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused
return 1; return 1;
} }
typedef JfrArtifactWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl; typedef JfrTypeWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;
typedef JfrArtifactWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter; typedef JfrTypeWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;
static void write_reference_infos(JfrCheckpointWriter& writer) { static void write_reference_infos(JfrCheckpointWriter& writer) {
if (ref_infos != NULL) { if (ref_infos != NULL) {
ReferenceWriter rw(&writer, NULL, false); ReferenceWriter rw(&writer);
ref_infos->iterate(rw); ref_infos->iterate(rw);
} }
} }
int __write_array_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ai) { int __write_array_info__(JfrCheckpointWriter* writer, const void* ai) {
assert(writer != NULL, "invariant"); assert(writer != NULL, "invariant");
assert(ai != NULL, "invariant"); assert(ai != NULL, "invariant");
const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai; const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai;
...@@ -270,17 +273,17 @@ static traceid get_array_info_id(const Edge& edge, traceid id) { ...@@ -270,17 +273,17 @@ static traceid get_array_info_id(const Edge& edge, traceid id) {
return array_infos->store(osai); return array_infos->store(osai);
} }
typedef JfrArtifactWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl; typedef JfrTypeWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;
typedef JfrArtifactWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter; typedef JfrTypeWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;
static void write_array_infos(JfrCheckpointWriter& writer) { static void write_array_infos(JfrCheckpointWriter& writer) {
if (array_infos != NULL) { if (array_infos != NULL) {
ArrayWriter aw(&writer, NULL, false); ArrayWriter aw(&writer);
array_infos->iterate(aw); array_infos->iterate(aw);
} }
} }
int __write_field_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* fi) { int __write_field_info__(JfrCheckpointWriter* writer, const void* fi) {
assert(writer != NULL, "invariant"); assert(writer != NULL, "invariant");
assert(fi != NULL, "invariant"); assert(fi != NULL, "invariant");
const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi; const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi;
...@@ -314,12 +317,12 @@ static traceid get_field_info_id(const Edge& edge) { ...@@ -314,12 +317,12 @@ static traceid get_field_info_id(const Edge& edge) {
return field_infos->store(osfi); return field_infos->store(osfi);
} }
typedef JfrArtifactWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl; typedef JfrTypeWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;
typedef JfrArtifactWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter; typedef JfrTypeWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;
static void write_field_infos(JfrCheckpointWriter& writer) { static void write_field_infos(JfrCheckpointWriter& writer) {
if (field_infos != NULL) { if (field_infos != NULL) {
FieldWriter fw(&writer, NULL, false); FieldWriter fw(&writer);
field_infos->iterate(fw); field_infos->iterate(fw);
} }
} }
...@@ -339,7 +342,7 @@ static const char* description(const ObjectSampleRootDescriptionInfo* osdi) { ...@@ -339,7 +342,7 @@ static const char* description(const ObjectSampleRootDescriptionInfo* osdi) {
return description.description(); return description.description();
} }
int __write_root_description_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* di) { int __write_root_description_info__(JfrCheckpointWriter* writer, const void* di) {
assert(writer != NULL, "invariant"); assert(writer != NULL, "invariant");
assert(di != NULL, "invariant"); assert(di != NULL, "invariant");
const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di; const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di;
...@@ -366,8 +369,8 @@ static traceid get_gc_root_description_info_id(const Edge& edge, traceid id) { ...@@ -366,8 +369,8 @@ static traceid get_gc_root_description_info_id(const Edge& edge, traceid id) {
return root_infos->store(oodi); return root_infos->store(oodi);
} }
typedef JfrArtifactWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl; typedef JfrTypeWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;
typedef JfrArtifactWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter; typedef JfrTypeWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;
int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) { int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) {
...@@ -513,7 +516,7 @@ static void write_root_descriptors(JfrCheckpointWriter& writer) { ...@@ -513,7 +516,7 @@ static void write_root_descriptors(JfrCheckpointWriter& writer) {
RootResolutionSet rrs(root_infos); RootResolutionSet rrs(root_infos);
RootResolver::resolve(rrs); RootResolver::resolve(rrs);
// write roots // write roots
RootDescriptionWriter rw(&writer, NULL, false); RootDescriptionWriter rw(&writer);
root_infos->iterate(rw); root_infos->iterate(rw);
} }
} }
...@@ -576,11 +579,45 @@ void ObjectSampleWriter::write(const StoredEdge* edge) { ...@@ -576,11 +579,45 @@ void ObjectSampleWriter::write(const StoredEdge* edge) {
} }
} }
class RootSystemType : public JfrSerializer {
public:
void serialize(JfrCheckpointWriter& writer) {
const u4 nof_root_systems = OldObjectRoot::_number_of_systems;
writer.write_count(nof_root_systems);
for (u4 i = 0; i < nof_root_systems; ++i) {
writer.write_key(i);
writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i));
}
}
};
class RootType : public JfrSerializer {
public:
void serialize(JfrCheckpointWriter& writer) {
const u4 nof_root_types = OldObjectRoot::_number_of_types;
writer.write_count(nof_root_types);
for (u4 i = 0; i < nof_root_types; ++i) {
writer.write_key(i);
writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i));
}
}
};
static void register_serializers() {
static bool is_registered = false;
if (!is_registered) {
JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType());
JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType());
is_registered = true;
}
}
ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, EdgeStore* store) : ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, EdgeStore* store) :
_writer(writer), _writer(writer),
_store(store) { _store(store) {
assert(store != NULL, "invariant"); assert(store != NULL, "invariant");
assert(!store->is_empty(), "invariant"); assert(!store->is_empty(), "invariant");
register_serializers();
sample_infos = NULL; sample_infos = NULL;
ref_infos = NULL; ref_infos = NULL;
array_infos = NULL; array_infos = NULL;
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include "jfr/leakprofiler/checkpoint/rootResolver.hpp" #include "jfr/leakprofiler/checkpoint/rootResolver.hpp"
#include "memory/iterator.hpp" #include "memory/iterator.hpp"
#include "oops/klass.hpp" #include "oops/klass.hpp"
#include "oops/markOop.hpp"
#include "oops/oop.hpp" #include "oops/oop.hpp"
#include "prims/jvmtiThreadState.hpp" #include "prims/jvmtiThreadState.hpp"
#include "prims/privilegedStack.hpp" #include "prims/privilegedStack.hpp"
......
...@@ -25,13 +25,14 @@ ...@@ -25,13 +25,14 @@
#ifndef SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP #ifndef SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
#define SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP #define SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
#include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrAllocation.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrTypes.hpp" #include "jfr/utilities/jfrTypes.hpp"
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "oops/oop.hpp" #include "oops/oop.hpp"
#include "utilities/ticks.hpp" #include "utilities/ticks.hpp"
/* /*
* Handle for diagnosing Java memory leaks. * Handle for diagnosing Java memory leaks.
* *
...@@ -44,8 +45,9 @@ class ObjectSample : public JfrCHeapObj { ...@@ -44,8 +45,9 @@ class ObjectSample : public JfrCHeapObj {
private: private:
ObjectSample* _next; ObjectSample* _next;
ObjectSample* _previous; ObjectSample* _previous;
JfrCheckpointBlobHandle _thread_cp; JfrBlobHandle _stacktrace;
JfrCheckpointBlobHandle _klass_cp; JfrBlobHandle _thread;
JfrBlobHandle _type_set;
oop _object; oop _object;
Ticks _allocation_time; Ticks _allocation_time;
traceid _stack_trace_id; traceid _stack_trace_id;
...@@ -62,17 +64,14 @@ class ObjectSample : public JfrCHeapObj { ...@@ -62,17 +64,14 @@ class ObjectSample : public JfrCHeapObj {
} }
void release_references() { void release_references() {
if (_thread_cp.valid()) { _stacktrace.~JfrBlobHandle();
_thread_cp.~JfrCheckpointBlobHandle(); _thread.~JfrBlobHandle();
} _type_set.~JfrBlobHandle();
if (_klass_cp.valid()) {
_klass_cp.~JfrCheckpointBlobHandle();
}
} }
void reset() { void reset() {
set_stack_trace_id(0); set_stack_trace_id(0);
set_stack_trace_hash(0), set_stack_trace_hash(0);
release_references(); release_references();
_dead = false; _dead = false;
} }
...@@ -80,8 +79,9 @@ class ObjectSample : public JfrCHeapObj { ...@@ -80,8 +79,9 @@ class ObjectSample : public JfrCHeapObj {
public: public:
ObjectSample() : _next(NULL), ObjectSample() : _next(NULL),
_previous(NULL), _previous(NULL),
_thread_cp(), _stacktrace(),
_klass_cp(), _thread(),
_type_set(),
_object(NULL), _object(NULL),
_allocation_time(), _allocation_time(),
_stack_trace_id(0), _stack_trace_id(0),
...@@ -174,7 +174,7 @@ class ObjectSample : public JfrCHeapObj { ...@@ -174,7 +174,7 @@ class ObjectSample : public JfrCHeapObj {
return _heap_used_at_last_gc; return _heap_used_at_last_gc;
} }
bool has_stack_trace() const { bool has_stack_trace_id() const {
return stack_trace_id() != 0; return stack_trace_id() != 0;
} }
...@@ -194,10 +194,6 @@ class ObjectSample : public JfrCHeapObj { ...@@ -194,10 +194,6 @@ class ObjectSample : public JfrCHeapObj {
_stack_trace_hash = hash; _stack_trace_hash = hash;
} }
bool has_thread() const {
return _thread_id != 0;
}
traceid thread_id() const { traceid thread_id() const {
return _thread_id; return _thread_id;
} }
...@@ -211,37 +207,51 @@ class ObjectSample : public JfrCHeapObj { ...@@ -211,37 +207,51 @@ class ObjectSample : public JfrCHeapObj {
_allocation_time.ft_value() : _allocation_time.value()) < time_stamp; _allocation_time.ft_value() : _allocation_time.value()) < time_stamp;
} }
const JfrCheckpointBlobHandle& thread_checkpoint() const { const JfrBlobHandle& stacktrace() const {
return _thread_cp; return _stacktrace;
} }
bool has_thread_checkpoint() const { bool has_stacktrace() const {
return _thread_cp.valid(); return _stacktrace.valid();
} }
// JfrCheckpointBlobHandle assignment operator // JfrBlobHandle assignment operator
// maintains proper reference counting // maintains proper reference counting
void set_thread_checkpoint(const JfrCheckpointBlobHandle& ref) { void set_stacktrace(const JfrBlobHandle& ref) {
if (_thread_cp != ref) { if (_stacktrace != ref) {
_thread_cp = ref; _stacktrace = ref;
}
}
const JfrBlobHandle& thread() const {
return _thread;
}
bool has_thread() const {
return _thread.valid();
}
void set_thread(const JfrBlobHandle& ref) {
if (_thread != ref) {
_thread = ref;
} }
} }
const JfrCheckpointBlobHandle& klass_checkpoint() const { const JfrBlobHandle& type_set() const {
return _klass_cp; return _type_set;
} }
bool has_klass_checkpoint() const { bool has_type_set() const {
return _klass_cp.valid(); return _type_set.valid();
} }
void set_klass_checkpoint(const JfrCheckpointBlobHandle& ref) { void set_type_set(const JfrBlobHandle& ref) {
if (_klass_cp != ref) { if (_type_set != ref) {
if (_klass_cp.valid()) { if (_type_set.valid()) {
_klass_cp->set_next(ref); _type_set->set_next(ref);
return; return;
} }
_klass_cp = ref; _type_set = ref;
} }
} }
}; };
......
/* /*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -108,47 +108,28 @@ static traceid get_thread_id(JavaThread* thread) { ...@@ -108,47 +108,28 @@ static traceid get_thread_id(JavaThread* thread) {
} }
const JfrThreadLocal* const tl = thread->jfr_thread_local(); const JfrThreadLocal* const tl = thread->jfr_thread_local();
assert(tl != NULL, "invariant"); assert(tl != NULL, "invariant");
if (!tl->has_thread_checkpoint()) { if (!tl->has_thread_blob()) {
JfrCheckpointManager::create_thread_checkpoint(thread); JfrCheckpointManager::create_thread_blob(thread);
} }
assert(tl->has_thread_checkpoint(), "invariant"); assert(tl->has_thread_blob(), "invariant");
return tl->thread_id(); return tl->thread_id();
} }
// Populates the thread local stack frames, but does not add them static void record_stacktrace(JavaThread* thread) {
// to the stacktrace repository (...yet, see stacktrace_id() below)
//
void ObjectSampler::fill_stacktrace(JfrStackTrace* stacktrace, JavaThread* thread) {
assert(stacktrace != NULL, "invariant");
assert(thread != NULL, "invariant"); assert(thread != NULL, "invariant");
if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) { if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) {
JfrStackTraceRepository::fill_stacktrace_for(thread, stacktrace, 0, WALK_BY_DEFAULT); JfrStackTraceRepository::record_and_cache(thread, 0, WALK_BY_DEFAULT);
} }
} }
// We were successful in acquiring the try lock and have been selected for adding a sample.
// Go ahead with installing our previously taken stacktrace into the stacktrace repository.
//
traceid ObjectSampler::stacktrace_id(const JfrStackTrace* stacktrace, JavaThread* thread) {
assert(stacktrace != NULL, "invariant");
assert(stacktrace->hash() != 0, "invariant");
const traceid stacktrace_id = JfrStackTraceRepository::add(stacktrace, thread);
thread->jfr_thread_local()->set_cached_stack_trace_id(stacktrace_id, stacktrace->hash());
return stacktrace_id;
}
void ObjectSampler::sample(HeapWord* obj, size_t allocated, JavaThread* thread) { void ObjectSampler::sample(HeapWord* obj, size_t allocated, JavaThread* thread) {
assert(thread != NULL, "invariant"); assert(thread != NULL, "invariant");
assert(is_created(), "invariant"); assert(is_created(), "invariant");
const traceid thread_id = get_thread_id(thread); const traceid thread_id = get_thread_id(thread);
if (thread_id == 0) { if (thread_id == 0) {
return; return;
} }
const JfrThreadLocal* const tl = thread->jfr_thread_local(); record_stacktrace(thread);
JfrStackTrace stacktrace(tl->stackframes(), tl->stackdepth());
fill_stacktrace(&stacktrace, thread);
// try enter critical section // try enter critical section
JfrTryLock tryLock(&_lock); JfrTryLock tryLock(&_lock);
if (!tryLock.has_lock()) { if (!tryLock.has_lock()) {
...@@ -156,14 +137,14 @@ void ObjectSampler::sample(HeapWord* obj, size_t allocated, JavaThread* thread) ...@@ -156,14 +137,14 @@ void ObjectSampler::sample(HeapWord* obj, size_t allocated, JavaThread* thread)
return; return;
} }
instance().add(obj, allocated, thread_id, &stacktrace, thread); instance().add(obj, allocated, thread_id, thread);
} }
void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JfrStackTrace* stacktrace, JavaThread* thread) { void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JavaThread* thread) {
assert(stacktrace != NULL, "invariant"); assert(obj != NULL, "invariant");
assert(thread_id != 0, "invariant"); assert(thread_id != 0, "invariant");
assert(thread != NULL, "invariant"); assert(thread != NULL, "invariant");
assert(thread->jfr_thread_local()->has_thread_checkpoint(), "invariant"); assert(thread->jfr_thread_local()->has_thread_blob(), "invariant");
if (_dead_samples) { if (_dead_samples) {
scavenge(); scavenge();
...@@ -187,11 +168,13 @@ void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JfrS ...@@ -187,11 +168,13 @@ void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JfrS
assert(sample != NULL, "invariant"); assert(sample != NULL, "invariant");
sample->set_thread_id(thread_id); sample->set_thread_id(thread_id);
sample->set_thread_checkpoint(thread->jfr_thread_local()->thread_checkpoint());
const unsigned int stacktrace_hash = stacktrace->hash(); const JfrThreadLocal* const tl = thread->jfr_thread_local();
sample->set_thread(tl->thread_blob());
const unsigned int stacktrace_hash = tl->cached_stack_trace_hash();
if (stacktrace_hash != 0) { if (stacktrace_hash != 0) {
sample->set_stack_trace_id(stacktrace_id(stacktrace, thread)); sample->set_stack_trace_id(tl->cached_stack_trace_id());
sample->set_stack_trace_hash(stacktrace_hash); sample->set_stack_trace_hash(stacktrace_hash);
} }
...@@ -250,7 +233,7 @@ void ObjectSampler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) { ...@@ -250,7 +233,7 @@ void ObjectSampler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
sampler._last_sweep = JfrTicks::now(); sampler._last_sweep = JfrTicks::now();
} }
const ObjectSample* ObjectSampler::last() const { ObjectSample* ObjectSampler::last() const {
return _list->last(); return _list->last();
} }
......
...@@ -31,25 +31,19 @@ ...@@ -31,25 +31,19 @@
typedef u8 traceid; typedef u8 traceid;
class BoolObjectClosure; class BoolObjectClosure;
class JfrStackTrace; class JavaThread;
class OopClosure; class OopClosure;
class ObjectSample; class ObjectSample;
class ObjectSampler;
class SampleList; class SampleList;
class SamplePriorityQueue; class SamplePriorityQueue;
class Thread;
// Class reponsible for holding samples and // Class reponsible for holding samples and
// making sure the samples are evenly distributed as // making sure the samples are evenly distributed as
// new entries are added and removed. // new entries are added and removed.
class ObjectSampler : public CHeapObj<mtTracing> { class ObjectSampler : public CHeapObj<mtTracing> {
friend class EventEmitter;
friend class JfrRecorderService;
friend class LeakProfiler; friend class LeakProfiler;
friend class StartOperation; friend class StartOperation;
friend class StopOperation; friend class StopOperation;
friend class ObjectSampleCheckpoint;
friend class WriteObjectSampleStacktrace;
private: private:
SamplePriorityQueue* _priority_queue; SamplePriorityQueue* _priority_queue;
SampleList* _list; SampleList* _list;
...@@ -64,20 +58,11 @@ class ObjectSampler : public CHeapObj<mtTracing> { ...@@ -64,20 +58,11 @@ class ObjectSampler : public CHeapObj<mtTracing> {
~ObjectSampler(); ~ObjectSampler();
static bool create(size_t size); static bool create(size_t size);
static bool is_created(); static bool is_created();
static ObjectSampler* sampler();
static void destroy(); static void destroy();
// For operations that require exclusive access (non-safepoint)
static ObjectSampler* acquire();
static void release();
// Stacktrace
static void fill_stacktrace(JfrStackTrace* stacktrace, JavaThread* thread);
traceid stacktrace_id(const JfrStackTrace* stacktrace, JavaThread* thread);
// Sampling // Sampling
static void sample(HeapWord* object, size_t size, JavaThread* thread); static void sample(HeapWord* object, size_t size, JavaThread* thread);
void add(HeapWord* object, size_t size, traceid thread_id, JfrStackTrace* stacktrace, JavaThread* thread); void add(HeapWord* object, size_t size, traceid thread_id, JavaThread* thread);
void scavenge(); void scavenge();
void remove_dead(ObjectSample* sample); void remove_dead(ObjectSample* sample);
...@@ -87,8 +72,15 @@ class ObjectSampler : public CHeapObj<mtTracing> { ...@@ -87,8 +72,15 @@ class ObjectSampler : public CHeapObj<mtTracing> {
const ObjectSample* item_at(int index) const; const ObjectSample* item_at(int index) const;
ObjectSample* item_at(int index); ObjectSample* item_at(int index);
int item_count() const; int item_count() const;
public:
static ObjectSampler* sampler();
// For operations that require exclusive access (non-safepoint)
static ObjectSampler* acquire();
static void release();
const ObjectSample* first() const; const ObjectSample* first() const;
const ObjectSample* last() const; ObjectSample* last() const;
const ObjectSample* last_resolved() const; const ObjectSample* last_resolved() const;
void set_last_resolved(const ObjectSample* sample); void set_last_resolved(const ObjectSample* sample);
const JfrTicks& last_sweep() const; const JfrTicks& last_sweep() const;
......
...@@ -50,12 +50,12 @@ class SampleList : public JfrCHeapObj { ...@@ -50,12 +50,12 @@ class SampleList : public JfrCHeapObj {
SampleList(size_t limit, size_t cache_size = 0); SampleList(size_t limit, size_t cache_size = 0);
~SampleList(); ~SampleList();
void set_last_resolved(const ObjectSample* sample);
ObjectSample* get(); ObjectSample* get();
ObjectSample* last() const;
ObjectSample* first() const; ObjectSample* first() const;
void release(ObjectSample* sample); ObjectSample* last() const;
const ObjectSample* last_resolved() const; const ObjectSample* last_resolved() const;
void set_last_resolved(const ObjectSample* sample);
void release(ObjectSample* sample);
ObjectSample* reuse(ObjectSample* sample); ObjectSample* reuse(ObjectSample* sample);
bool is_full() const; bool is_full() const;
size_t count() const; size_t count() const;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "jfr/utilities/jfrBigEndian.hpp" #include "jfr/utilities/jfrBigEndian.hpp"
#include "jfr/utilities/jfrTypes.hpp" #include "jfr/utilities/jfrTypes.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/mutexLocker.hpp" #include "runtime/mutexLocker.hpp"
#include "runtime/orderAccess.inline.hpp" #include "runtime/orderAccess.inline.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
...@@ -86,22 +87,18 @@ static const size_t unlimited_mspace_size = 0; ...@@ -86,22 +87,18 @@ static const size_t unlimited_mspace_size = 0;
static const size_t checkpoint_buffer_cache_count = 2; static const size_t checkpoint_buffer_cache_count = 2;
static const size_t checkpoint_buffer_size = 512 * K; static const size_t checkpoint_buffer_size = 512 * K;
static JfrCheckpointMspace* create_mspace(size_t buffer_size, size_t limit, size_t cache_count, JfrCheckpointManager* system) { static JfrCheckpointMspace* allocate_mspace(size_t size, size_t limit, size_t cache_count, JfrCheckpointManager* mgr) {
JfrCheckpointMspace* mspace = new JfrCheckpointMspace(buffer_size, limit, cache_count, system); return create_mspace<JfrCheckpointMspace, JfrCheckpointManager>(size, limit, cache_count, mgr);
if (mspace != NULL) {
mspace->initialize();
}
return mspace;
} }
bool JfrCheckpointManager::initialize() { bool JfrCheckpointManager::initialize() {
assert(_free_list_mspace == NULL, "invariant"); assert(_free_list_mspace == NULL, "invariant");
_free_list_mspace = create_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this); _free_list_mspace = allocate_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
if (_free_list_mspace == NULL) { if (_free_list_mspace == NULL) {
return false; return false;
} }
assert(_epoch_transition_mspace == NULL, "invariant"); assert(_epoch_transition_mspace == NULL, "invariant");
_epoch_transition_mspace = create_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this); _epoch_transition_mspace = allocate_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
if (_epoch_transition_mspace == NULL) { if (_epoch_transition_mspace == NULL) {
return false; return false;
} }
...@@ -113,22 +110,6 @@ bool JfrCheckpointManager::initialize() { ...@@ -113,22 +110,6 @@ bool JfrCheckpointManager::initialize() {
return JfrTypeManager::initialize(); return JfrTypeManager::initialize();
} }
bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const {
return _service_thread != thread && OrderAccess::load_acquire((u1*)&_checkpoint_epoch_state) != JfrTraceIdEpoch::current();
}
void JfrCheckpointManager::synchronize_epoch() {
assert(_checkpoint_epoch_state != JfrTraceIdEpoch::current(), "invariant");
OrderAccess::storestore();
_checkpoint_epoch_state = JfrTraceIdEpoch::current();
}
void JfrCheckpointManager::shift_epoch() {
debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();)
JfrTraceIdEpoch::shift_epoch();
assert(current_epoch != JfrTraceIdEpoch::current(), "invariant");
}
void JfrCheckpointManager::register_service_thread(const Thread* thread) { void JfrCheckpointManager::register_service_thread(const Thread* thread) {
_service_thread = thread; _service_thread = thread;
} }
...@@ -150,7 +131,6 @@ void JfrCheckpointManager::unlock() { ...@@ -150,7 +131,6 @@ void JfrCheckpointManager::unlock() {
} }
#ifdef ASSERT #ifdef ASSERT
bool JfrCheckpointManager::is_locked() const { bool JfrCheckpointManager::is_locked() const {
return _lock->owned_by_self(); return _lock->owned_by_self();
} }
...@@ -166,7 +146,6 @@ static void assert_release(const BufferPtr buffer) { ...@@ -166,7 +146,6 @@ static void assert_release(const BufferPtr buffer) {
assert(buffer->lease(), "invariant"); assert(buffer->lease(), "invariant");
assert(buffer->acquired_by_self(), "invariant"); assert(buffer->acquired_by_self(), "invariant");
} }
#endif // ASSERT #endif // ASSERT
static BufferPtr lease_free(size_t size, JfrCheckpointMspace* mspace, size_t retry_count, Thread* thread) { static BufferPtr lease_free(size_t size, JfrCheckpointMspace* mspace, size_t retry_count, Thread* thread) {
...@@ -184,6 +163,10 @@ static BufferPtr lease_free(size_t size, JfrCheckpointMspace* mspace, size_t ret ...@@ -184,6 +163,10 @@ static BufferPtr lease_free(size_t size, JfrCheckpointMspace* mspace, size_t ret
return buffer; return buffer;
} }
bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const {
return _service_thread != thread && OrderAccess::load_acquire((u1*)&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch();
}
static const size_t lease_retry = 10; static const size_t lease_retry = 10;
BufferPtr JfrCheckpointManager::lease_buffer(Thread* thread, size_t size /* 0 */) { BufferPtr JfrCheckpointManager::lease_buffer(Thread* thread, size_t size /* 0 */) {
...@@ -255,33 +238,33 @@ static juint number_of_types(const u1* data) { ...@@ -255,33 +238,33 @@ static juint number_of_types(const u1* data) {
return read_data<juint>(data + types_offset); return read_data<juint>(data + types_offset);
} }
static void write_checkpoint_header(JfrChunkWriter& cw, intptr_t offset_prev_cp_event, const u1* data) { static void write_checkpoint_header(JfrChunkWriter& cw, int64_t offset_prev_cp_event, const u1* data) {
cw.reserve(sizeof(u4)); cw.reserve(sizeof(u4));
cw.write((u8)EVENT_CHECKPOINT); cw.write<u8>(EVENT_CHECKPOINT);
cw.write(starttime(data)); cw.write(starttime(data));
cw.write(duration(data)); cw.write(duration(data));
cw.write((jlong)offset_prev_cp_event); cw.write(offset_prev_cp_event);
cw.write(is_flushpoint(data)); cw.write(is_flushpoint(data));
cw.write(number_of_types(data)); cw.write(number_of_types(data));
} }
static void write_checkpoint_content(JfrChunkWriter& cw, const u1* data, size_t size) { static void write_checkpoint_content(JfrChunkWriter& cw, const u1* data, size_t size) {
assert(data != NULL, "invariant"); assert(data != NULL, "invariant");
cw.write_unbuffered(data + payload_offset, size); cw.write_unbuffered(data + payload_offset, size - sizeof(JfrCheckpointEntry));
} }
static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) { static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) {
assert(data != NULL, "invariant"); assert(data != NULL, "invariant");
const intptr_t previous_checkpoint_event = cw.previous_checkpoint_offset(); const int64_t event_begin = cw.current_offset();
const intptr_t event_begin = cw.current_offset(); const int64_t last_checkpoint_event = cw.last_checkpoint_offset();
const intptr_t offset_to_previous_checkpoint_event = 0 == previous_checkpoint_event ? 0 : previous_checkpoint_event - event_begin; const int64_t delta = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin;
const jlong total_checkpoint_size = total_size(data); const int64_t checkpoint_size = total_size(data);
write_checkpoint_header(cw, offset_to_previous_checkpoint_event, data); write_checkpoint_header(cw, delta, data);
write_checkpoint_content(cw, data, total_checkpoint_size - sizeof(JfrCheckpointEntry)); write_checkpoint_content(cw, data, checkpoint_size);
const jlong checkpoint_event_size = cw.current_offset() - event_begin; const int64_t event_size = cw.current_offset() - event_begin;
cw.write_padded_at_offset<u4>(checkpoint_event_size, event_begin); cw.write_padded_at_offset<u4>(event_size, event_begin);
cw.set_previous_checkpoint_offset(event_begin); cw.set_last_checkpoint_offset(event_begin);
return (size_t)total_checkpoint_size; return (size_t)checkpoint_size;
} }
static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) { static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) {
...@@ -289,14 +272,14 @@ static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) ...@@ -289,14 +272,14 @@ static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size)
assert(data != NULL, "invariant"); assert(data != NULL, "invariant");
assert(size > 0, "invariant"); assert(size > 0, "invariant");
const u1* const limit = data + size; const u1* const limit = data + size;
const u1* next_entry = data; const u1* next = data;
size_t processed = 0; size_t processed = 0;
while (next_entry < limit) { while (next < limit) {
const size_t checkpoint_size = write_checkpoint_event(cw, next_entry); const size_t checkpoint_size = write_checkpoint_event(cw, next);
processed += checkpoint_size; processed += checkpoint_size;
next_entry += checkpoint_size; next += checkpoint_size;
} }
assert(next_entry == limit, "invariant"); assert(next == limit, "invariant");
return processed; return processed;
} }
...@@ -331,6 +314,12 @@ static size_t write_mspace_exclusive(JfrCheckpointMspace* mspace, JfrChunkWriter ...@@ -331,6 +314,12 @@ static size_t write_mspace_exclusive(JfrCheckpointMspace* mspace, JfrChunkWriter
return wo.processed(); return wo.processed();
} }
void JfrCheckpointManager::synchronize_epoch() {
assert(_checkpoint_epoch_state != JfrTraceIdEpoch::epoch(), "invariant");
OrderAccess::storestore();
_checkpoint_epoch_state = JfrTraceIdEpoch::epoch();
}
size_t JfrCheckpointManager::write() { size_t JfrCheckpointManager::write() {
const size_t processed = write_mspace_exclusive(_free_list_mspace, _chunkwriter); const size_t processed = write_mspace_exclusive(_free_list_mspace, _chunkwriter);
synchronize_epoch(); synchronize_epoch();
...@@ -372,10 +361,16 @@ void JfrCheckpointManager::write_type_set_for_unloaded_classes() { ...@@ -372,10 +361,16 @@ void JfrCheckpointManager::write_type_set_for_unloaded_classes() {
JfrTypeManager::write_type_set_for_unloaded_classes(); JfrTypeManager::write_type_set_for_unloaded_classes();
} }
void JfrCheckpointManager::create_thread_checkpoint(JavaThread* jt) { void JfrCheckpointManager::create_thread_blob(JavaThread* jt) {
JfrTypeManager::create_thread_checkpoint(jt); JfrTypeManager::create_thread_blob(jt);
} }
void JfrCheckpointManager::write_thread_checkpoint(JavaThread* jt) { void JfrCheckpointManager::write_thread_checkpoint(JavaThread* jt) {
JfrTypeManager::write_thread_checkpoint(jt); JfrTypeManager::write_thread_checkpoint(jt);
} }
void JfrCheckpointManager::shift_epoch() {
debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();)
JfrTraceIdEpoch::shift_epoch();
assert(current_epoch != JfrTraceIdEpoch::current(), "invariant");
}
...@@ -92,7 +92,7 @@ class JfrCheckpointManager : public JfrCHeapObj { ...@@ -92,7 +92,7 @@ class JfrCheckpointManager : public JfrCHeapObj {
public: public:
void register_service_thread(const Thread* t); void register_service_thread(const Thread* t);
static void write_type_set_for_unloaded_classes(); static void write_type_set_for_unloaded_classes();
static void create_thread_checkpoint(JavaThread* jt); static void create_thread_blob(JavaThread* jt);
static void write_thread_checkpoint(JavaThread* jt); static void write_thread_checkpoint(JavaThread* jt);
friend class JfrRecorder; friend class JfrRecorder;
......
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/writers/jfrBigEndianWriter.hpp" #include "jfr/writers/jfrBigEndianWriter.hpp"
JfrCheckpointFlush::JfrCheckpointFlush(Type* old, size_t used, size_t requested, Thread* t) : JfrCheckpointFlush::JfrCheckpointFlush(Type* old, size_t used, size_t requested, Thread* t) :
...@@ -126,7 +127,7 @@ void JfrCheckpointWriter::write_count(u4 nof_entries, jlong offset) { ...@@ -126,7 +127,7 @@ void JfrCheckpointWriter::write_count(u4 nof_entries, jlong offset) {
write_padded_at_offset(nof_entries, offset); write_padded_at_offset(nof_entries, offset);
} }
const u1* JfrCheckpointWriter::session_data(size_t* size, const JfrCheckpointContext* ctx /* 0 */) { const u1* JfrCheckpointWriter::session_data(size_t* size, bool move /* false */, const JfrCheckpointContext* ctx /* 0 */) {
assert(this->is_acquired(), "wrong state!"); assert(this->is_acquired(), "wrong state!");
if (!this->is_valid()) { if (!this->is_valid()) {
*size = 0; *size = 0;
...@@ -140,8 +141,10 @@ const u1* JfrCheckpointWriter::session_data(size_t* size, const JfrCheckpointCon ...@@ -140,8 +141,10 @@ const u1* JfrCheckpointWriter::session_data(size_t* size, const JfrCheckpointCon
*size = this->used_size(); *size = this->used_size();
assert(this->start_pos() + *size == this->current_pos(), "invariant"); assert(this->start_pos() + *size == this->current_pos(), "invariant");
write_checkpoint_header(const_cast<u1*>(this->start_pos()), this->used_offset(), _time, is_flushpoint(), count()); write_checkpoint_header(const_cast<u1*>(this->start_pos()), this->used_offset(), _time, is_flushpoint(), count());
this->seek(_offset + (_header ? sizeof(JfrCheckpointEntry) : 0)); _header = false; // the header was just written
set_count(0); if (move) {
this->seek(_offset);
}
return this->start_pos(); return this->start_pos();
} }
...@@ -160,26 +163,19 @@ bool JfrCheckpointWriter::has_data() const { ...@@ -160,26 +163,19 @@ bool JfrCheckpointWriter::has_data() const {
return this->used_size() > sizeof(JfrCheckpointEntry); return this->used_size() > sizeof(JfrCheckpointEntry);
} }
JfrCheckpointBlobHandle JfrCheckpointWriter::checkpoint_blob() { JfrBlobHandle JfrCheckpointWriter::copy(const JfrCheckpointContext* ctx /* 0 */) {
size_t size = 0; size_t size = 0;
const u1* data = session_data(&size); const u1* data = session_data(&size, false, ctx);
return JfrCheckpointBlob::make(data, size); return JfrBlob::make(data, size);
} }
JfrCheckpointBlobHandle JfrCheckpointWriter::copy(const JfrCheckpointContext* ctx /* 0 */) { JfrBlobHandle JfrCheckpointWriter::move(const JfrCheckpointContext* ctx /* 0 */) {
if (ctx == NULL) {
return checkpoint_blob();
}
size_t size = 0; size_t size = 0;
const u1* data = session_data(&size, ctx); const u1* data = session_data(&size, true, ctx);
return JfrCheckpointBlob::make(data, size); JfrBlobHandle blob = JfrBlob::make(data, size);
}
JfrCheckpointBlobHandle JfrCheckpointWriter::move(const JfrCheckpointContext* ctx /* 0 */) {
JfrCheckpointBlobHandle data = copy(ctx);
if (ctx != NULL) { if (ctx != NULL) {
const_cast<JfrCheckpointContext*>(ctx)->count = 0; const_cast<JfrCheckpointContext*>(ctx)->count = 0;
set_context(*ctx); set_context(*ctx);
} }
return data; return blob;
} }
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP #ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
#define SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP #define SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
#include "jfr/recorder/storage/jfrBuffer.hpp" #include "jfr/recorder/storage/jfrBuffer.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrTypes.hpp" #include "jfr/utilities/jfrTypes.hpp"
#include "jfr/writers/jfrEventWriterHost.inline.hpp" #include "jfr/writers/jfrEventWriterHost.inline.hpp"
...@@ -67,9 +67,8 @@ class JfrCheckpointWriter : public JfrCheckpointWriterBase { ...@@ -67,9 +67,8 @@ class JfrCheckpointWriter : public JfrCheckpointWriterBase {
void increment(); void increment();
void set_flushpoint(bool flushpoint); void set_flushpoint(bool flushpoint);
bool is_flushpoint() const; bool is_flushpoint() const;
const u1* session_data(size_t* size, const JfrCheckpointContext* ctx = NULL); const u1* session_data(size_t* size, bool move = false, const JfrCheckpointContext* ctx = NULL);
void release(); void release();
public: public:
JfrCheckpointWriter(bool flushpoint, bool header, Thread* thread); JfrCheckpointWriter(bool flushpoint, bool header, Thread* thread);
~JfrCheckpointWriter(); ~JfrCheckpointWriter();
...@@ -80,9 +79,8 @@ class JfrCheckpointWriter : public JfrCheckpointWriterBase { ...@@ -80,9 +79,8 @@ class JfrCheckpointWriter : public JfrCheckpointWriterBase {
const JfrCheckpointContext context() const; const JfrCheckpointContext context() const;
void set_context(const JfrCheckpointContext ctx); void set_context(const JfrCheckpointContext ctx);
bool has_data() const; bool has_data() const;
JfrCheckpointBlobHandle checkpoint_blob(); JfrBlobHandle copy(const JfrCheckpointContext* ctx = NULL);
JfrCheckpointBlobHandle copy(const JfrCheckpointContext* ctx = NULL); JfrBlobHandle move(const JfrCheckpointContext* ctx = NULL);
JfrCheckpointBlobHandle move(const JfrCheckpointContext* ctx = NULL);
}; };
#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP #endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include "gc_interface/gcName.hpp" #include "gc_interface/gcName.hpp"
#include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/gcWhen.hpp"
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
#include "jfr/recorder/checkpoint/types/jfrType.hpp" #include "jfr/recorder/checkpoint/types/jfrType.hpp"
...@@ -295,34 +294,26 @@ void VMOperationTypeConstant::serialize(JfrCheckpointWriter& writer) { ...@@ -295,34 +294,26 @@ void VMOperationTypeConstant::serialize(JfrCheckpointWriter& writer) {
class TypeSetSerialization { class TypeSetSerialization {
private: private:
JfrCheckpointWriter* _leakp_writer;
bool _class_unload; bool _class_unload;
public: public:
explicit TypeSetSerialization(bool class_unload) : _class_unload(class_unload) {} TypeSetSerialization(bool class_unload, JfrCheckpointWriter* leakp_writer = NULL) :
void write(JfrCheckpointWriter& writer, JfrCheckpointWriter* leakp_writer) { _leakp_writer(leakp_writer), _class_unload(class_unload) {}
JfrTypeSet::serialize(&writer, leakp_writer, _class_unload); void write(JfrCheckpointWriter& writer) {
JfrTypeSet::serialize(&writer, _leakp_writer, _class_unload);
} }
}; };
void ClassUnloadTypeSet::serialize(JfrCheckpointWriter& writer) { void ClassUnloadTypeSet::serialize(JfrCheckpointWriter& writer) {
TypeSetSerialization type_set(true); TypeSetSerialization type_set(true);
if (LeakProfiler::is_running()) { type_set.write(writer);
JfrCheckpointWriter leakp_writer(false, true, Thread::current());
type_set.write(writer, &leakp_writer);
ObjectSampleCheckpoint::install(leakp_writer, true, true);
return;
}
type_set.write(writer, NULL);
}; };
TypeSet::TypeSet(JfrCheckpointWriter* leakp_writer) : _leakp_writer(leakp_writer) {}
void TypeSet::serialize(JfrCheckpointWriter& writer) { void TypeSet::serialize(JfrCheckpointWriter& writer) {
TypeSetSerialization type_set(false); TypeSetSerialization type_set(false, _leakp_writer);
if (LeakProfiler::is_running()) { type_set.write(writer);
JfrCheckpointWriter leakp_writer(false, true, Thread::current());
type_set.write(writer, &leakp_writer);
ObjectSampleCheckpoint::install(leakp_writer, false, true);
return;
}
type_set.write(writer, NULL);
}; };
void ThreadStateConstant::serialize(JfrCheckpointWriter& writer) { void ThreadStateConstant::serialize(JfrCheckpointWriter& writer) {
...@@ -333,7 +324,6 @@ void JfrThreadConstant::serialize(JfrCheckpointWriter& writer) { ...@@ -333,7 +324,6 @@ void JfrThreadConstant::serialize(JfrCheckpointWriter& writer) {
assert(_thread != NULL, "invariant"); assert(_thread != NULL, "invariant");
assert(_thread == Thread::current(), "invariant"); assert(_thread == Thread::current(), "invariant");
assert(_thread->is_Java_thread(), "invariant"); assert(_thread->is_Java_thread(), "invariant");
assert(!_thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
ResourceMark rm(_thread); ResourceMark rm(_thread);
const oop threadObj = _thread->threadObj(); const oop threadObj = _thread->threadObj();
assert(threadObj != NULL, "invariant"); assert(threadObj != NULL, "invariant");
......
...@@ -118,7 +118,10 @@ class VMOperationTypeConstant : public JfrSerializer { ...@@ -118,7 +118,10 @@ class VMOperationTypeConstant : public JfrSerializer {
}; };
class TypeSet : public JfrSerializer { class TypeSet : public JfrSerializer {
private:
JfrCheckpointWriter* _leakp_writer;
public: public:
explicit TypeSet(JfrCheckpointWriter* leakp_writer = NULL);
void serialize(JfrCheckpointWriter& writer); void serialize(JfrCheckpointWriter& writer);
}; };
......
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -23,12 +23,17 @@ ...@@ -23,12 +23,17 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "jfr/jfr.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
#include "jfr/metadata/jfrSerializer.hpp" #include "jfr/metadata/jfrSerializer.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/recorder/checkpoint/types/jfrType.hpp" #include "jfr/recorder/checkpoint/types/jfrType.hpp"
#include "jfr/recorder/checkpoint/types/jfrTypeManager.hpp" #include "jfr/recorder/checkpoint/types/jfrTypeManager.hpp"
#include "jfr/utilities/jfrDoublyLinkedList.hpp" #include "jfr/utilities/jfrDoublyLinkedList.hpp"
#include "jfr/utilities/jfrIterator.hpp" #include "jfr/utilities/jfrIterator.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/safepoint.hpp" #include "runtime/safepoint.hpp"
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "utilities/exceptions.hpp" #include "utilities/exceptions.hpp"
...@@ -39,7 +44,7 @@ class JfrSerializerRegistration : public JfrCHeapObj { ...@@ -39,7 +44,7 @@ class JfrSerializerRegistration : public JfrCHeapObj {
JfrSerializerRegistration* _next; JfrSerializerRegistration* _next;
JfrSerializerRegistration* _prev; JfrSerializerRegistration* _prev;
JfrSerializer* _serializer; JfrSerializer* _serializer;
mutable JfrCheckpointBlobHandle _cache; mutable JfrBlobHandle _cache;
JfrTypeId _id; JfrTypeId _id;
bool _permit_cache; bool _permit_cache;
...@@ -148,43 +153,58 @@ void JfrTypeManager::write_safepoint_types(JfrCheckpointWriter& writer) { ...@@ -148,43 +153,58 @@ void JfrTypeManager::write_safepoint_types(JfrCheckpointWriter& writer) {
} }
void JfrTypeManager::write_type_set() { void JfrTypeManager::write_type_set() {
// can safepoint here because of PackageTable_lock assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
MutexLockerEx lock(SafepointSynchronize::is_at_safepoint() ? NULL : PackageTable_lock); // can safepoint here
JfrCheckpointWriter writer(true, true, Thread::current()); MutexLocker module_lock(PackageTable_lock);
TypeSet set; if (!LeakProfiler::is_running()) {
JfrCheckpointWriter writer(true, true, Thread::current());
TypeSet set;
set.serialize(writer);
return;
}
JfrCheckpointWriter leakp_writer(false, true, Thread::current());
JfrCheckpointWriter writer(false, true, Thread::current());
TypeSet set(&leakp_writer);
set.serialize(writer); set.serialize(writer);
ObjectSampleCheckpoint::on_type_set(leakp_writer);
} }
void JfrTypeManager::write_type_set_for_unloaded_classes() { void JfrTypeManager::write_type_set_for_unloaded_classes() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant"); assert(SafepointSynchronize::is_at_safepoint(), "invariant");
JfrCheckpointWriter writer(false, true, Thread::current()); JfrCheckpointWriter writer(false, true, Thread::current());
const JfrCheckpointContext ctx = writer.context();
ClassUnloadTypeSet class_unload_set; ClassUnloadTypeSet class_unload_set;
class_unload_set.serialize(writer); class_unload_set.serialize(writer);
if (LeakProfiler::is_running()) {
ObjectSampleCheckpoint::on_type_set_unload(writer);
}
if (!Jfr::is_recording()) {
// discard anything written
writer.set_context(ctx);
}
} }
void JfrTypeManager::create_thread_checkpoint(JavaThread* jt) { void JfrTypeManager::create_thread_blob(JavaThread* jt) {
assert(jt != NULL, "invariant"); assert(jt != NULL, "invariant");
ResourceMark rm(jt);
HandleMark hm(jt);
JfrThreadConstant type_thread(jt); JfrThreadConstant type_thread(jt);
JfrCheckpointWriter writer(false, true, jt); JfrCheckpointWriter writer(false, true, jt);
writer.write_type(TYPE_THREAD); writer.write_type(TYPE_THREAD);
type_thread.serialize(writer); type_thread.serialize(writer);
// create and install a checkpoint blob // create and install a checkpoint blob
jt->jfr_thread_local()->set_thread_checkpoint(writer.checkpoint_blob()); jt->jfr_thread_local()->set_thread_blob(writer.move());
assert(jt->jfr_thread_local()->has_thread_checkpoint(), "invariant"); assert(jt->jfr_thread_local()->has_thread_blob(), "invariant");
} }
void JfrTypeManager::write_thread_checkpoint(JavaThread* jt) { void JfrTypeManager::write_thread_checkpoint(JavaThread* jt) {
assert(jt != NULL, "JavaThread is NULL!"); assert(jt != NULL, "JavaThread is NULL!");
ResourceMark rm(jt); ResourceMark rm(jt);
if (jt->jfr_thread_local()->has_thread_checkpoint()) { HandleMark hm(jt);
JfrCheckpointWriter writer(false, false, jt); JfrThreadConstant type_thread(jt);
jt->jfr_thread_local()->thread_checkpoint()->write(writer); JfrCheckpointWriter writer(false, true, jt);
} else { writer.write_type(TYPE_THREAD);
JfrThreadConstant type_thread(jt); type_thread.serialize(writer);
JfrCheckpointWriter writer(false, true, jt);
writer.write_type(TYPE_THREAD);
type_thread.serialize(writer);
}
} }
#ifdef ASSERT #ifdef ASSERT
......
...@@ -37,7 +37,7 @@ class JfrTypeManager : public AllStatic { ...@@ -37,7 +37,7 @@ class JfrTypeManager : public AllStatic {
static void write_safepoint_types(JfrCheckpointWriter& writer); static void write_safepoint_types(JfrCheckpointWriter& writer);
static void write_type_set(); static void write_type_set();
static void write_type_set_for_unloaded_classes(); static void write_type_set_for_unloaded_classes();
static void create_thread_checkpoint(JavaThread* jt); static void create_thread_blob(JavaThread* jt);
static void write_thread_checkpoint(JavaThread* jt); static void write_thread_checkpoint(JavaThread* jt);
}; };
......
...@@ -27,42 +27,11 @@ ...@@ -27,42 +27,11 @@
#include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrAllocation.hpp"
class ClassLoaderData;
class JfrArtifactClosure;
class JfrArtifactSet;
class JfrCheckpointWriter; class JfrCheckpointWriter;
class Klass;
// XXX class PackageEntry;
class JfrTypeSet : AllStatic { class JfrTypeSet : AllStatic {
friend class CLDCallback; public:
friend class JfrTypeManager; static size_t serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload);
friend class TypeSetSerialization;
private:
static JfrArtifactSet* _artifacts;
static JfrArtifactClosure* _subsystem_callback;
static bool _class_unload;
static void do_klass(Klass* k);
static void do_unloaded_klass(Klass* k);
static void do_klasses();
// XXX
// static void do_package(PackageEntry* entry);
// static void do_unloaded_package(PackageEntry* entry);
// static void do_packages();
static void do_class_loader_data(ClassLoaderData* cld);
static void do_unloaded_class_loader_data(ClassLoaderData* cld);
static void do_class_loaders();
static void write_klass_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
static void write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
static void write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
static void write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
static void write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
static void serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload);
}; };
#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESET_HPP #endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESET_HPP
/* /*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -28,17 +28,30 @@ ...@@ -28,17 +28,30 @@
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "oops/symbol.hpp" #include "oops/symbol.hpp"
JfrSymbolId::JfrSymbolId() : _symbol_id_counter(0), _sym_table(new SymbolTable(this)), static JfrSymbolId::CStringEntry* bootstrap = NULL;
_cstring_table(new CStringTable(this)), _pkg_table(new CStringTable(this)) {
JfrSymbolId::JfrSymbolId() :
_sym_table(new SymbolTable(this)),
_cstring_table(new CStringTable(this)),
_pkg_table(new CStringTable(this)),
_sym_list(NULL),
_cstring_list(NULL),
_symbol_id_counter(1),
_class_unload(false) {
assert(_sym_table != NULL, "invariant"); assert(_sym_table != NULL, "invariant");
assert(_cstring_table != NULL, "invariant"); assert(_cstring_table != NULL, "invariant");
assert(_pkg_table != NULL, "invariant"); assert(_pkg_table != NULL, "invariant");
initialize(); bootstrap = new CStringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME);
assert(bootstrap != NULL, "invariant");
bootstrap->set_id(1);
_cstring_list = bootstrap;
} }
void JfrSymbolId::initialize() { JfrSymbolId::~JfrSymbolId() {
clear(); clear();
assert(_symbol_id_counter == 0, "invariant"); delete _sym_table;
delete _cstring_table;
delete bootstrap;
} }
void JfrSymbolId::clear() { void JfrSymbolId::clear() {
...@@ -53,117 +66,139 @@ void JfrSymbolId::clear() { ...@@ -53,117 +66,139 @@ void JfrSymbolId::clear() {
_cstring_table->clear_entries(); _cstring_table->clear_entries();
} }
assert(!_cstring_table->has_entries(), "invariant"); assert(!_cstring_table->has_entries(), "invariant");
_symbol_id_counter = 0;
assert(_pkg_table != NULL, "invariant"); assert(_pkg_table != NULL, "invariant");
if (_pkg_table->has_entries()) { if (_pkg_table->has_entries()) {
_pkg_table->clear_entries(); _pkg_table->clear_entries();
} }
assert(!_pkg_table->has_entries(), "invariant"); assert(!_pkg_table->has_entries(), "invariant");
}
JfrSymbolId::~JfrSymbolId() {
delete _sym_table;
delete _cstring_table;
}
traceid JfrSymbolId::mark_anonymous_klass_name(const Klass* k) {
assert(k != NULL, "invariant");
assert(k->oop_is_instance(), "invariant");
assert(is_anonymous_klass(k), "invariant");
uintptr_t anonymous_symbol_hash_code = 0;
const char* const anonymous_symbol =
create_anonymous_klass_symbol((const InstanceKlass*)k, anonymous_symbol_hash_code);
if (anonymous_symbol == NULL) {
return 0;
}
assert(anonymous_symbol_hash_code != 0, "invariant"); _sym_list = NULL;
traceid symbol_id = mark(anonymous_symbol, anonymous_symbol_hash_code); _cstring_list = NULL;
assert(mark(anonymous_symbol, anonymous_symbol_hash_code) == symbol_id, "invariant"); _symbol_id_counter = 1;
return symbol_id;
}
const JfrSymbolId::SymbolEntry* JfrSymbolId::map_symbol(const Symbol* symbol) const {
return _sym_table->lookup_only(symbol, (uintptr_t)const_cast<Symbol*>(symbol)->identity_hash());
}
const JfrSymbolId::SymbolEntry* JfrSymbolId::map_symbol(uintptr_t hash) const { assert(bootstrap != NULL, "invariant");
return _sym_table->lookup_only(NULL, hash); bootstrap->reset();
_cstring_list = bootstrap;
} }
const JfrSymbolId::CStringEntry* JfrSymbolId::map_cstring(uintptr_t hash) const { void JfrSymbolId::set_class_unload(bool class_unload) {
return _cstring_table->lookup_only(NULL, hash); _class_unload = class_unload;
} }
void JfrSymbolId::assign_id(SymbolEntry* entry) { void JfrSymbolId::on_link(const SymbolEntry* entry) {
assert(entry != NULL, "invariant"); assert(entry != NULL, "invariant");
const_cast<Symbol*>(entry->literal())->increment_refcount();
assert(entry->id() == 0, "invariant"); assert(entry->id() == 0, "invariant");
entry->set_id(++_symbol_id_counter); entry->set_id(++_symbol_id_counter);
entry->set_list_next(_sym_list);
_sym_list = entry;
} }
bool JfrSymbolId::equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry) { bool JfrSymbolId::on_equals(uintptr_t hash, const SymbolEntry* entry) {
// query might be NULL // query might be NULL
assert(entry != NULL, "invariant"); assert(entry != NULL, "invariant");
assert(entry->hash() == hash, "invariant"); assert(entry->hash() == hash, "invariant");
return true; return true;
} }
void JfrSymbolId::assign_id(CStringEntry* entry) { void JfrSymbolId::on_unlink(const SymbolEntry* entry) {
assert(entry != NULL, "invariant");
const_cast<Symbol*>(entry->literal())->decrement_refcount();
}
void JfrSymbolId::on_link(const CStringEntry* entry) {
assert(entry != NULL, "invariant"); assert(entry != NULL, "invariant");
assert(entry->id() == 0, "invariant"); assert(entry->id() == 0, "invariant");
entry->set_id(++_symbol_id_counter); entry->set_id(++_symbol_id_counter);
entry->set_list_next(_cstring_list);
_cstring_list = entry;
} }
bool JfrSymbolId::equals(const char* query, uintptr_t hash, const CStringEntry* entry) { bool JfrSymbolId::on_equals(uintptr_t hash, const CStringEntry* entry) {
// query might be NULL
assert(entry != NULL, "invariant"); assert(entry != NULL, "invariant");
assert(entry->hash() == hash, "invariant"); assert(entry->hash() == hash, "invariant");
return true; return true;
} }
traceid JfrSymbolId::mark(const Klass* k) { void JfrSymbolId::on_unlink(const CStringEntry* entry) {
assert(k != NULL, "invariant"); assert(entry != NULL, "invariant");
traceid symbol_id = 0; JfrCHeapObj::free(const_cast<char*>(entry->literal()), strlen(entry->literal() + 1));
if (is_anonymous_klass(k)) { }
symbol_id = mark_anonymous_klass_name(k);
} traceid JfrSymbolId::bootstrap_name(bool leakp) {
if (0 == symbol_id) { assert(bootstrap != NULL, "invariant");
const Symbol* const sym = k->name(); if (leakp) {
if (sym != NULL) { bootstrap->set_leakp();
symbol_id = mark(sym);
}
} }
assert(symbol_id > 0, "a symbol handler must mark the symbol for writing"); return 1;
return symbol_id;
} }
traceid JfrSymbolId::mark(const Symbol* symbol) { traceid JfrSymbolId::mark(const Symbol* symbol, bool leakp) {
assert(symbol != NULL, "invariant"); assert(symbol != NULL, "invariant");
return mark(symbol, (uintptr_t)const_cast<Symbol*>(symbol)->identity_hash()); return mark((uintptr_t)((Symbol*)symbol)->identity_hash(), symbol, leakp);
} }
traceid JfrSymbolId::mark(const Symbol* data, uintptr_t hash) { static unsigned int last_symbol_hash = 0;
static traceid last_symbol_id = 0;
traceid JfrSymbolId::mark(uintptr_t hash, const Symbol* data, bool leakp) {
assert(data != NULL, "invariant"); assert(data != NULL, "invariant");
assert(_sym_table != NULL, "invariant"); assert(_sym_table != NULL, "invariant");
return _sym_table->id(data, hash); if (hash == last_symbol_hash) {
assert(last_symbol_id != 0, "invariant");
return last_symbol_id;
}
const SymbolEntry& entry = _sym_table->lookup_put(hash, data);
if (_class_unload) {
entry.set_unloading();
}
if (leakp) {
entry.set_leakp();
}
last_symbol_hash = hash;
last_symbol_id = entry.id();
return last_symbol_id;
} }
traceid JfrSymbolId::mark(const char* str, uintptr_t hash) { static unsigned int last_cstring_hash_for_pkg = 0;
assert(str != NULL, "invariant"); static traceid last_cstring_id_for_pkg = 0;
return _cstring_table->id(str, hash); static unsigned int last_cstring_hash = 0;
} static traceid last_cstring_id = 0;
traceid JfrSymbolId::markPackage(const char* name, uintptr_t hash) { traceid JfrSymbolId::markPackage(const char* name, uintptr_t hash) {
assert(name != NULL, "invariant"); assert(name != NULL, "invariant");
assert(_pkg_table != NULL, "invariant"); assert(_pkg_table != NULL, "invariant");
return _pkg_table->id(name, hash); if (hash == last_cstring_hash_for_pkg) {
assert(last_cstring_id_for_pkg != 0, "invariant");
return last_cstring_id_for_pkg;
}
const CStringEntry& entry = _pkg_table->lookup_put(hash, name);
if (_class_unload) {
entry.set_unloading();
}
last_cstring_hash_for_pkg = hash;
last_cstring_id_for_pkg = entry.id();
return last_cstring_id_for_pkg;
} }
bool JfrSymbolId::is_anonymous_klass(const Klass* k) { traceid JfrSymbolId::mark(uintptr_t hash, const char* str, bool leakp) {
assert(k != NULL, "invariant"); assert(str != NULL, "invariant");
return k->oop_is_instance() && ((const InstanceKlass*)k)->is_anonymous(); assert(_cstring_table != NULL, "invariant");
if (hash == last_cstring_hash) {
assert(last_cstring_id != 0, "invariant");
return last_cstring_id;
}
const CStringEntry& entry = _cstring_table->lookup_put(hash, str);
if (_class_unload) {
entry.set_unloading();
}
if (leakp) {
entry.set_leakp();
}
last_cstring_hash = hash;
last_cstring_id = entry.id();
return last_cstring_id;
} }
/* /*
...@@ -174,7 +209,7 @@ bool JfrSymbolId::is_anonymous_klass(const Klass* k) { ...@@ -174,7 +209,7 @@ bool JfrSymbolId::is_anonymous_klass(const Klass* k) {
* caller needs ResourceMark * caller needs ResourceMark
*/ */
uintptr_t JfrSymbolId::anonymous_klass_name_hash_code(const InstanceKlass* ik) { uintptr_t JfrSymbolId::unsafe_anonymous_klass_name_hash(const InstanceKlass* ik) {
assert(ik != NULL, "invariant"); assert(ik != NULL, "invariant");
assert(ik->is_anonymous(), "invariant"); assert(ik->is_anonymous(), "invariant");
const oop mirror = ik->java_mirror(); const oop mirror = ik->java_mirror();
...@@ -182,19 +217,18 @@ uintptr_t JfrSymbolId::anonymous_klass_name_hash_code(const InstanceKlass* ik) { ...@@ -182,19 +217,18 @@ uintptr_t JfrSymbolId::anonymous_klass_name_hash_code(const InstanceKlass* ik) {
return (uintptr_t)mirror->identity_hash(); return (uintptr_t)mirror->identity_hash();
} }
const char* JfrSymbolId::create_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode) { static const char* create_unsafe_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t hash) {
assert(ik != NULL, "invariant"); assert(ik != NULL, "invariant");
assert(ik->is_anonymous(), "invariant"); assert(ik->is_anonymous(), "invariant");
assert(0 == hashcode, "invariant"); assert(hash != 0, "invariant");
char* anonymous_symbol = NULL; char* anonymous_symbol = NULL;
const oop mirror = ik->java_mirror(); const oop mirror = ik->java_mirror();
assert(mirror != NULL, "invariant"); assert(mirror != NULL, "invariant");
char hash_buf[40]; char hash_buf[40];
hashcode = anonymous_klass_name_hash_code(ik); sprintf(hash_buf, "/" UINTX_FORMAT, hash);
sprintf(hash_buf, "/" UINTX_FORMAT, hashcode);
const size_t hash_len = strlen(hash_buf); const size_t hash_len = strlen(hash_buf);
const size_t result_len = ik->name()->utf8_length(); const size_t result_len = ik->name()->utf8_length();
anonymous_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); anonymous_symbol = JfrCHeapObj::new_array<char>(result_len + hash_len + 1);
ik->name()->as_klass_external_name(anonymous_symbol, (int)result_len + 1); ik->name()->as_klass_external_name(anonymous_symbol, (int)result_len + 1);
assert(strlen(anonymous_symbol) == result_len, "invariant"); assert(strlen(anonymous_symbol) == result_len, "invariant");
strcpy(anonymous_symbol + result_len, hash_buf); strcpy(anonymous_symbol + result_len, hash_buf);
...@@ -202,74 +236,107 @@ const char* JfrSymbolId::create_anonymous_klass_symbol(const InstanceKlass* ik, ...@@ -202,74 +236,107 @@ const char* JfrSymbolId::create_anonymous_klass_symbol(const InstanceKlass* ik,
return anonymous_symbol; return anonymous_symbol;
} }
uintptr_t JfrSymbolId::regular_klass_name_hash_code(const Klass* k) { bool JfrSymbolId::is_unsafe_anonymous_klass(const Klass* k) {
assert(k != NULL, "invariant"); assert(k != NULL, "invariant");
const Symbol* const sym = k->name(); return k->oop_is_instance() && ((const InstanceKlass*)k)->is_anonymous();
assert(sym != NULL, "invariant"); }
return (uintptr_t)const_cast<Symbol*>(sym)->identity_hash();
static unsigned int last_anonymous_hash = 0;
static traceid last_anonymous_id = 0;
traceid JfrSymbolId::mark_unsafe_anonymous_klass_name(const InstanceKlass* ik, bool leakp) {
assert(ik != NULL, "invariant");
assert(ik->is_anonymous(), "invariant");
const uintptr_t hash = unsafe_anonymous_klass_name_hash(ik);
if (hash == last_anonymous_hash) {
assert(last_anonymous_id != 0, "invariant");
return last_anonymous_id;
}
last_anonymous_hash = hash;
const CStringEntry* const entry = _cstring_table->lookup_only(hash);
last_anonymous_id = entry != NULL ? entry->id() : mark(hash, create_unsafe_anonymous_klass_symbol(ik, hash), leakp);
return last_anonymous_id;
}
traceid JfrSymbolId::mark(const Klass* k, bool leakp) {
assert(k != NULL, "invariant");
traceid symbol_id = 0;
if (is_unsafe_anonymous_klass(k)) {
assert(k->oop_is_instance(), "invariant");
symbol_id = mark_unsafe_anonymous_klass_name((const InstanceKlass*)k, leakp);
}
if (0 == symbol_id) {
Symbol* const sym = k->name();
if (sym != NULL) {
symbol_id = mark(sym, leakp);
}
}
assert(symbol_id > 0, "a symbol handler must mark the symbol for writing");
return symbol_id;
}
static void reset_symbol_caches() {
last_anonymous_hash = 0;
last_symbol_hash = 0;
last_cstring_hash = 0;
last_cstring_hash_for_pkg = 0;
} }
JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_id(new JfrSymbolId()), JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_id(new JfrSymbolId()),
_klass_list(NULL), _klass_list(NULL),
_class_unload(class_unload) { _total_count(0) {
initialize(class_unload); initialize(class_unload);
assert(_klass_list != NULL, "invariant"); assert(_klass_list != NULL, "invariant");
} }
static const size_t initial_class_list_size = 200; static const size_t initial_class_list_size = 200;
void JfrArtifactSet::initialize(bool class_unload) { void JfrArtifactSet::initialize(bool class_unload) {
assert(_symbol_id != NULL, "invariant"); assert(_symbol_id != NULL, "invariant");
_symbol_id->initialize(); _symbol_id->set_class_unload(class_unload);
assert(!_symbol_id->has_entries(), "invariant"); _total_count = 0;
_symbol_id->mark(BOOTSTRAP_LOADER_NAME, 0); // pre-load "bootstrap"
_class_unload = class_unload;
// resource allocation // resource allocation
_klass_list = new GrowableArray<const Klass*>(initial_class_list_size, false, mtTracing); _klass_list = new GrowableArray<const Klass*>(initial_class_list_size, false, mtTracing);
} }
JfrArtifactSet::~JfrArtifactSet() { JfrArtifactSet::~JfrArtifactSet() {
clear(); clear();
delete _symbol_id;
} }
void JfrArtifactSet::clear() { void JfrArtifactSet::clear() {
reset_symbol_caches();
_symbol_id->clear(); _symbol_id->clear();
// _klass_list will be cleared by a ResourceMark // _klass_list will be cleared by a ResourceMark
} }
traceid JfrArtifactSet::mark_anonymous_klass_name(const Klass* klass) { traceid JfrArtifactSet::bootstrap_name(bool leakp) {
return _symbol_id->mark_anonymous_klass_name(klass); return _symbol_id->bootstrap_name(leakp);
}
traceid JfrArtifactSet::mark(const Symbol* sym, uintptr_t hash) {
return _symbol_id->mark(sym, hash);
} }
traceid JfrArtifactSet::mark(const Klass* klass) { traceid JfrArtifactSet::mark_unsafe_anonymous_klass_name(const Klass* klass, bool leakp) {
return _symbol_id->mark(klass); assert(klass->oop_is_instance(), "invariant");
return _symbol_id->mark_unsafe_anonymous_klass_name((const InstanceKlass*)klass, leakp);
} }
traceid JfrArtifactSet::mark(const Symbol* symbol) { traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) {
return _symbol_id->mark(symbol); return _symbol_id->mark(hash, sym, leakp);
} }
traceid JfrArtifactSet::mark(const char* const str, uintptr_t hash) { traceid JfrArtifactSet::mark(const Klass* klass, bool leakp) {
return _symbol_id->mark(str, hash); return _symbol_id->mark(klass, leakp);
} }
traceid JfrArtifactSet::markPackage(const char* const name, uintptr_t hash) { traceid JfrArtifactSet::markPackage(const char* const name, uintptr_t hash) {
return _symbol_id->markPackage(name, hash); return _symbol_id->markPackage(name, hash);
} }
const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(const Symbol* symbol) const { traceid JfrArtifactSet::mark(const Symbol* symbol, bool leakp) {
return _symbol_id->map_symbol(symbol); return _symbol_id->mark(symbol, leakp);
} }
const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(uintptr_t hash) const { traceid JfrArtifactSet::mark(uintptr_t hash, const char* const str, bool leakp) {
return _symbol_id->map_symbol(hash); return _symbol_id->mark(hash, str, leakp);
}
const JfrSymbolId::CStringEntry* JfrArtifactSet::map_cstring(uintptr_t hash) const {
return _symbol_id->map_cstring(hash);
} }
bool JfrArtifactSet::has_klass_entries() const { bool JfrArtifactSet::has_klass_entries() const {
...@@ -286,3 +353,7 @@ void JfrArtifactSet::register_klass(const Klass* k) { ...@@ -286,3 +353,7 @@ void JfrArtifactSet::register_klass(const Klass* k) {
assert(_klass_list->find(k) == -1, "invariant"); assert(_klass_list->find(k) == -1, "invariant");
_klass_list->append(k); _klass_list->append(k);
} }
size_t JfrArtifactSet::total_count() const {
return _total_count;
}
/* /*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
* *
*/ */
#ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP #ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP
#define SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP #define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrAllocation.hpp"
...@@ -81,183 +81,185 @@ class KlassToFieldEnvelope { ...@@ -81,183 +81,185 @@ class KlassToFieldEnvelope {
}; };
template <typename T> template <typename T>
void tag_leakp_artifact(T const& value, bool class_unload) { class ClearArtifact {
assert(value != NULL, "invariant"); public:
if (class_unload) { bool operator()(T const& value) {
SET_LEAKP_USED_THIS_EPOCH(value); CLEAR_METHOD_AND_CLASS_PREV_EPOCH(value);
assert(LEAKP_USED_THIS_EPOCH(value), "invariant"); CLEAR_SERIALIZED(value);
} else { assert(IS_NOT_SERIALIZED(value), "invariant");
SET_LEAKP_USED_PREV_EPOCH(value); return true;
assert(LEAKP_USED_PREV_EPOCH(value), "invariant");
} }
} };
template <typename T> template <>
class LeakpClearArtifact { class ClearArtifact<const Method*> {
bool _class_unload;
public: public:
LeakpClearArtifact(bool class_unload) : _class_unload(class_unload) {} bool operator()(const Method* method) {
bool operator()(T const& value) { assert(METHOD_FLAG_USED_PREV_EPOCH(method), "invariant");
if (_class_unload) { CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method);
if (LEAKP_USED_THIS_EPOCH(value)) { CLEAR_METHOD_SERIALIZED(method);
LEAKP_UNUSE_THIS_EPOCH(value); assert(METHOD_NOT_SERIALIZED(method), "invariant");
}
} else {
if (LEAKP_USED_PREV_EPOCH(value)) {
LEAKP_UNUSE_PREV_EPOCH(value);
}
}
return true; return true;
} }
}; };
template <typename T> template <typename T>
class ClearArtifact { class JfrStub {
public:
bool operator()(T const& value) { return true; }
};
template <typename T>
class SerializePredicate {
bool _class_unload; bool _class_unload;
public: public:
ClearArtifact(bool class_unload) : _class_unload(class_unload) {} SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
bool operator()(T const& value) { bool operator()(T const& value) {
if (_class_unload) { assert(value != NULL, "invariant");
if (LEAKP_USED_THIS_EPOCH(value)) { return _class_unload ? true : IS_NOT_SERIALIZED(value);
LEAKP_UNUSE_THIS_EPOCH(value);
}
if (USED_THIS_EPOCH(value)) {
UNUSE_THIS_EPOCH(value);
}
if (METHOD_USED_THIS_EPOCH(value)) {
UNUSE_METHOD_THIS_EPOCH(value);
}
} else {
if (LEAKP_USED_PREV_EPOCH(value)) {
LEAKP_UNUSE_PREV_EPOCH(value);
}
if (USED_PREV_EPOCH(value)) {
UNUSE_PREV_EPOCH(value);
}
if (METHOD_USED_PREV_EPOCH(value)) {
UNUSE_METHOD_PREV_EPOCH(value);
}
}
return true;
} }
}; };
template <> template <>
class ClearArtifact<const Method*> { class SerializePredicate<const Method*> {
bool _class_unload; bool _class_unload;
public: public:
ClearArtifact(bool class_unload) : _class_unload(class_unload) {} SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
bool operator()(const Method* method) { bool operator()(const Method* method) {
if (_class_unload) { assert(method != NULL, "invariant");
if (METHOD_FLAG_USED_THIS_EPOCH(method)) { return _class_unload ? true : METHOD_NOT_SERIALIZED(method);
CLEAR_METHOD_FLAG_USED_THIS_EPOCH(method);
}
} else {
if (METHOD_FLAG_USED_PREV_EPOCH(method)) {
CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method);
}
}
return true;
} }
}; };
template <typename T> template <typename T, bool leakp>
class LeakPredicate { class SymbolPredicate {
bool _class_unload; bool _class_unload;
public: public:
LeakPredicate(bool class_unload) : _class_unload(class_unload) {} SymbolPredicate(bool class_unload) : _class_unload(class_unload) {}
bool operator()(T const& value) { bool operator()(T const& value) {
return _class_unload ? LEAKP_USED_THIS_EPOCH(value) : LEAKP_USED_PREV_EPOCH(value); assert(value != NULL, "invariant");
if (_class_unload) {
return leakp ? value->is_leakp() : value->is_unloading();
}
return leakp ? value->is_leakp() : !value->is_serialized();
} }
}; };
template <typename T> template <bool leakp>
class UsedPredicate { class MethodUsedPredicate {
bool _class_unload; bool _current_epoch;
public:
MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
bool operator()(const Klass* klass) {
if (_current_epoch) {
return leakp ? IS_LEAKP(klass) : METHOD_USED_THIS_EPOCH(klass);
}
return leakp ? IS_LEAKP(klass) : METHOD_USED_PREV_EPOCH(klass);
}
};
template <bool leakp>
class MethodFlagPredicate {
bool _current_epoch;
public: public:
UsedPredicate(bool class_unload) : _class_unload(class_unload) {} MethodFlagPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
bool operator()(T const& value) { bool operator()(const Method* method) {
return _class_unload ? USED_THIS_EPOCH(value) : USED_PREV_EPOCH(value); if (_current_epoch) {
return leakp ? IS_METHOD_LEAKP_USED(method) : METHOD_FLAG_USED_THIS_EPOCH(method);
}
return leakp ? IS_METHOD_LEAKP_USED(method) : METHOD_FLAG_USED_PREV_EPOCH(method);
} }
}; };
template <typename T, int compare(const T&, const T&)> template <typename T>
class UniquePredicate { class LeakPredicate {
private:
GrowableArray<T> _seen;
public: public:
UniquePredicate(bool) : _seen() {} LeakPredicate(bool class_unload) {}
bool operator()(T const& value) { bool operator()(T const& value) {
bool not_unique; return IS_LEAKP(value);
_seen.template find_sorted<T, compare>(value, not_unique);
if (not_unique) {
return false;
}
_seen.template insert_sorted<compare>(value);
return true;
} }
}; };
class MethodFlagPredicate { template <>
bool _class_unload; class LeakPredicate<const Method*> {
public: public:
MethodFlagPredicate(bool class_unload) : _class_unload(class_unload) {} LeakPredicate(bool class_unload) {}
bool operator()(const Method* method) { bool operator()(const Method* method) {
return _class_unload ? METHOD_FLAG_USED_THIS_EPOCH(method) : METHOD_FLAG_USED_PREV_EPOCH(method); assert(method != NULL, "invariant");
return IS_METHOD_LEAKP_USED(method);
} }
}; };
template <bool leakp> template <typename T, typename IdType>
class MethodUsedPredicate { class ListEntry : public JfrHashtableEntry<T, IdType> {
bool _class_unload;
public: public:
MethodUsedPredicate(bool class_unload) : _class_unload(class_unload) {} ListEntry(uintptr_t hash, const T& data) : JfrHashtableEntry<T, IdType>(hash, data),
bool operator()(const Klass* klass) { _list_next(NULL), _serialized(false), _unloading(false), _leakp(false) {}
assert(ANY_USED(klass), "invariant"); const ListEntry<T, IdType>* list_next() const { return _list_next; }
if (_class_unload) { void reset() const {
return leakp ? LEAKP_METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_THIS_EPOCH(klass); _list_next = NULL; _serialized = false; _unloading = false; _leakp = false;
}
return leakp ? LEAKP_METHOD_USED_PREV_EPOCH(klass) : METHOD_USED_PREV_EPOCH(klass);
} }
void set_list_next(const ListEntry<T, IdType>* next) const { _list_next = next; }
bool is_serialized() const { return _serialized; }
void set_serialized() const { _serialized = true; }
bool is_unloading() const { return _unloading; }
void set_unloading() const { _unloading = true; }
bool is_leakp() const { return _leakp; }
void set_leakp() const { _leakp = true; }
private:
mutable const ListEntry<T, IdType>* _list_next;
mutable bool _serialized;
mutable bool _unloading;
mutable bool _leakp;
}; };
class JfrSymbolId : public JfrCHeapObj { class JfrSymbolId : public JfrCHeapObj {
template <typename, typename, template<typename, typename> class, typename, size_t> template <typename, typename, template<typename, typename> class, typename, size_t>
friend class HashTableHost; friend class HashTableHost;
typedef HashTableHost<const Symbol*, traceid, Entry, JfrSymbolId> SymbolTable; typedef HashTableHost<const Symbol*, traceid, ListEntry, JfrSymbolId> SymbolTable;
typedef HashTableHost<const char*, traceid, Entry, JfrSymbolId> CStringTable; typedef HashTableHost<const char*, traceid, ListEntry, JfrSymbolId> CStringTable;
friend class JfrArtifactSet;
public: public:
typedef SymbolTable::HashEntry SymbolEntry; typedef SymbolTable::HashEntry SymbolEntry;
typedef CStringTable::HashEntry CStringEntry; typedef CStringTable::HashEntry CStringEntry;
private: private:
traceid _symbol_id_counter;
SymbolTable* _sym_table; SymbolTable* _sym_table;
CStringTable* _cstring_table; CStringTable* _cstring_table;
CStringTable* _pkg_table; CStringTable* _pkg_table;
const SymbolEntry* _sym_list;
const CStringEntry* _cstring_list;
traceid _symbol_id_counter;
bool _class_unload;
// hashtable(s) callbacks // hashtable(s) callbacks
void assign_id(SymbolEntry* entry); void on_link(const SymbolEntry* entry);
bool equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry); bool on_equals(uintptr_t hash, const SymbolEntry* entry);
void assign_id(CStringEntry* entry); void on_unlink(const SymbolEntry* entry);
bool equals(const char* query, uintptr_t hash, const CStringEntry* entry); void on_link(const CStringEntry* entry);
bool on_equals(uintptr_t hash, const CStringEntry* entry);
void on_unlink(const CStringEntry* entry);
template <typename Functor, typename T>
void iterate(Functor& functor, const T* list) {
const T* symbol = list;
while (symbol != NULL) {
const T* next = symbol->list_next();
functor(symbol);
symbol = next;
}
}
public: traceid mark_unsafe_anonymous_klass_name(const InstanceKlass* k, bool leakp);
static bool is_anonymous_klass(const Klass* k); bool is_unsafe_anonymous_klass(const Klass* k);
static const char* create_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode); uintptr_t unsafe_anonymous_klass_name_hash(const InstanceKlass* ik);
static uintptr_t anonymous_klass_name_hash_code(const InstanceKlass* ik);
static uintptr_t regular_klass_name_hash_code(const Klass* k);
public:
JfrSymbolId(); JfrSymbolId();
~JfrSymbolId(); ~JfrSymbolId();
void initialize();
void clear(); void clear();
void set_class_unload(bool class_unload);
traceid mark_anonymous_klass_name(const Klass* k);
traceid mark(const Symbol* sym, uintptr_t hash);
traceid mark(const Klass* k);
traceid mark(const Symbol* symbol);
traceid mark(const char* str, uintptr_t hash);
traceid markPackage(const char* name, uintptr_t hash); traceid markPackage(const char* name, uintptr_t hash);
template <typename T> template <typename T>
...@@ -265,46 +267,25 @@ class JfrSymbolId : public JfrCHeapObj { ...@@ -265,46 +267,25 @@ class JfrSymbolId : public JfrCHeapObj {
_pkg_table->iterate_entry(functor); _pkg_table->iterate_entry(functor);
} }
const SymbolEntry* map_symbol(const Symbol* symbol) const; traceid mark(uintptr_t hash, const Symbol* sym, bool leakp);
const SymbolEntry* map_symbol(uintptr_t hash) const; traceid mark(const Klass* k, bool leakp);
const CStringEntry* map_cstring(uintptr_t hash) const; traceid mark(const Symbol* symbol, bool leakp);
traceid mark(uintptr_t hash, const char* str, bool leakp);
traceid bootstrap_name(bool leakp);
template <typename T> template <typename Functor>
void symbol(T& functor, const Klass* k) { void iterate_symbols(Functor& functor) {
if (is_anonymous_klass(k)) { iterate(functor, _sym_list);
return;
}
functor(map_symbol(regular_klass_name_hash_code(k)));
}
template <typename T>
void symbol(T& functor, const Method* method) {
assert(method != NULL, "invariant");
functor(map_symbol((uintptr_t)method->name()->identity_hash()));
functor(map_symbol((uintptr_t)method->signature()->identity_hash()));
}
template <typename T>
void cstring(T& functor, const Klass* k) {
if (!is_anonymous_klass(k)) {
return;
}
functor(map_cstring(anonymous_klass_name_hash_code((const InstanceKlass*)k)));
}
template <typename T>
void iterate_symbols(T& functor) {
_sym_table->iterate_entry(functor);
} }
template <typename T> template <typename Functor>
void iterate_cstrings(T& functor) { void iterate_cstrings(Functor& functor) {
_cstring_table->iterate_entry(functor); iterate(functor, _cstring_list);
} }
bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); } bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); }
bool has_symbol_entries() const { return _sym_table->has_entries(); } bool has_symbol_entries() const { return _sym_list != NULL; }
bool has_cstring_entries() const { return _cstring_table->has_entries(); } bool has_cstring_entries() const { return _cstring_list != NULL; }
}; };
/** /**
...@@ -325,7 +306,7 @@ class JfrArtifactSet : public JfrCHeapObj { ...@@ -325,7 +306,7 @@ class JfrArtifactSet : public JfrCHeapObj {
private: private:
JfrSymbolId* _symbol_id; JfrSymbolId* _symbol_id;
GrowableArray<const Klass*>* _klass_list; GrowableArray<const Klass*>* _klass_list;
bool _class_unload; size_t _total_count;
public: public:
JfrArtifactSet(bool class_unload); JfrArtifactSet(bool class_unload);
...@@ -335,11 +316,13 @@ class JfrArtifactSet : public JfrCHeapObj { ...@@ -335,11 +316,13 @@ class JfrArtifactSet : public JfrCHeapObj {
void initialize(bool class_unload); void initialize(bool class_unload);
void clear(); void clear();
traceid mark(const Symbol* sym, uintptr_t hash);
traceid mark(const Klass* klass); traceid mark(uintptr_t hash, const Symbol* sym, bool leakp);
traceid mark(const Symbol* symbol); traceid mark(const Klass* klass, bool leakp);
traceid mark(const char* const str, uintptr_t hash); traceid mark(const Symbol* symbol, bool leakp);
traceid mark_anonymous_klass_name(const Klass* klass); traceid mark(uintptr_t hash, const char* const str, bool leakp);
traceid mark_unsafe_anonymous_klass_name(const Klass* klass, bool leakp);
traceid bootstrap_name(bool leakp);
traceid markPackage(const char* const name, uintptr_t hash); traceid markPackage(const char* const name, uintptr_t hash);
...@@ -349,6 +332,7 @@ class JfrArtifactSet : public JfrCHeapObj { ...@@ -349,6 +332,7 @@ class JfrArtifactSet : public JfrCHeapObj {
bool has_klass_entries() const; bool has_klass_entries() const;
int entries() const; int entries() const;
size_t total_count() const;
void register_klass(const Klass* k); void register_klass(const Klass* k);
template <typename Functor> template <typename Functor>
...@@ -374,6 +358,12 @@ class JfrArtifactSet : public JfrCHeapObj { ...@@ -374,6 +358,12 @@ class JfrArtifactSet : public JfrCHeapObj {
void iterate_packages(T& functor) { void iterate_packages(T& functor) {
_symbol_id->iterate_packages(functor); _symbol_id->iterate_packages(functor);
} }
template <typename Writer>
void tally(Writer& writer) {
_total_count += writer.count();
}
}; };
class KlassArtifactRegistrator { class KlassArtifactRegistrator {
...@@ -392,4 +382,4 @@ class KlassArtifactRegistrator { ...@@ -392,4 +382,4 @@ class KlassArtifactRegistrator {
} }
}; };
#endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP
...@@ -130,7 +130,7 @@ void JfrTraceId::remove(const Klass* k) { ...@@ -130,7 +130,7 @@ void JfrTraceId::remove(const Klass* k) {
// This mechanism will retain the event specific flags // This mechanism will retain the event specific flags
// in the archive, allowing for event flag restoration // in the archive, allowing for event flag restoration
// when renewing the traceid on klass revival. // when renewing the traceid on klass revival.
k->set_trace_id(EVENT_FLAGS_MASK(k)); k->set_trace_id(EVENT_KLASS_MASK(k));
} }
// used by CDS / APPCDS as part of "restore_unshareable_info" // used by CDS / APPCDS as part of "restore_unshareable_info"
...@@ -152,12 +152,12 @@ traceid JfrTraceId::get(jclass jc) { ...@@ -152,12 +152,12 @@ traceid JfrTraceId::get(jclass jc) {
return get(java_lang_Class::as_Klass(my_oop)); return get(java_lang_Class::as_Klass(my_oop));
} }
traceid JfrTraceId::use(jclass jc, bool leakp /* false */) { traceid JfrTraceId::use(jclass jc) {
assert(jc != NULL, "invariant"); assert(jc != NULL, "invariant");
assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant"); assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
const oop my_oop = JNIHandles::resolve(jc); const oop my_oop = JNIHandles::resolve(jc);
assert(my_oop != NULL, "invariant"); assert(my_oop != NULL, "invariant");
return use(java_lang_Class::as_Klass(my_oop), leakp); return use(java_lang_Class::as_Klass(my_oop));
} }
bool JfrTraceId::in_visible_set(const jclass jc) { bool JfrTraceId::in_visible_set(const jclass jc) {
......
...@@ -87,11 +87,15 @@ class JfrTraceId : public AllStatic { ...@@ -87,11 +87,15 @@ class JfrTraceId : public AllStatic {
static traceid get(const Thread* thread); static traceid get(const Thread* thread);
// tag construct as used, returns pre-tagged traceid // tag construct as used, returns pre-tagged traceid
static traceid use(const Klass* klass, bool leakp = false); static traceid use(const Klass* klass);
static traceid use(jclass jc, bool leakp = false); static traceid use(jclass jc);
static traceid use(const Method* method, bool leakp = false); static traceid use(const Method* method);
// XXX static traceid use(const PackageEntry* package, bool leakp = false); static traceid use(const Klass* klass, const Method* method);
static traceid use(const ClassLoaderData* cld, bool leakp = false); // XXX static traceid use(const PackageEntry* package);
static traceid use(const ClassLoaderData* cld);
// leak profiler
static void set_leakp(const Method* method);
static void remove(const Klass* klass); static void remove(const Klass* klass);
static void restore(const Klass* klass); static void restore(const Klass* klass);
......
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -22,12 +22,15 @@ ...@@ -22,12 +22,15 @@
* *
*/ */
#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTYPEIDS_INLINE_HPP #ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEID_INLINE_HPP
#define SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTYPEIDS_INLINE_HPP #define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEID_INLINE_HPP
#include "classfile/classLoaderData.hpp" #include "classfile/classLoaderData.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
#include "jfr/support/jfrKlassExtension.hpp"
#include "oops/arrayKlass.hpp" #include "oops/arrayKlass.hpp"
#include "oops/klass.hpp" #include "oops/klass.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
...@@ -36,21 +39,11 @@ ...@@ -36,21 +39,11 @@
#include "utilities/debug.hpp" #include "utilities/debug.hpp"
template <typename T> template <typename T>
inline traceid set_used_and_get(const T* type, bool leakp) { inline traceid set_used_and_get(const T* type) {
assert(type != NULL, "invariant"); assert(type != NULL, "invariant");
if (leakp) {
SET_LEAKP_USED_THIS_EPOCH(type);
assert(LEAKP_USED_THIS_EPOCH(type), "invariant");
}
SET_USED_THIS_EPOCH(type); SET_USED_THIS_EPOCH(type);
assert(USED_THIS_EPOCH(type), "invariant"); assert(USED_THIS_EPOCH(type), "invariant");
return TRACE_ID_MASKED_PTR(type); return TRACE_ID(type);
}
template <typename T>
inline traceid set_used_and_get_shifted(const T* type, bool leakp) {
assert(type != NULL, "invariant");
return set_used_and_get(type, leakp) >> TRACE_ID_SHIFT;
} }
inline traceid JfrTraceId::get(const Klass* klass) { inline traceid JfrTraceId::get(const Klass* klass) {
...@@ -63,34 +56,45 @@ inline traceid JfrTraceId::get(const Thread* t) { ...@@ -63,34 +56,45 @@ inline traceid JfrTraceId::get(const Thread* t) {
return TRACE_ID_RAW(t->jfr_thread_local()); return TRACE_ID_RAW(t->jfr_thread_local());
} }
inline traceid JfrTraceId::use(const Klass* klass, bool leakp /* false */) { inline traceid JfrTraceId::use(const Klass* klass) {
assert(klass != NULL, "invariant"); assert(klass != NULL, "invariant");
return set_used_and_get_shifted(klass, leakp); return set_used_and_get(klass);
} }
inline traceid JfrTraceId::use(const Method* method, bool leakp /* false */) { inline traceid JfrTraceId::use(const Method* method) {
assert(method != NULL, "invariant"); assert(method != NULL, "invariant");
SET_METHOD_FLAG_USED_THIS_EPOCH(method); return use(method->method_holder(), method);
const Klass* const klass = method->method_holder(); }
inline traceid JfrTraceId::use(const Klass* klass, const Method* method) {
assert(klass != NULL, "invariant"); assert(klass != NULL, "invariant");
if (leakp) { assert(method != NULL, "invariant");
SET_LEAKP_USED_THIS_EPOCH(klass); SET_METHOD_FLAG_USED_THIS_EPOCH(method);
assert(LEAKP_USED_THIS_EPOCH(klass), "invariant");
}
SET_METHOD_AND_CLASS_USED_THIS_EPOCH(klass); SET_METHOD_AND_CLASS_USED_THIS_EPOCH(klass);
assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant"); assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
return (METHOD_ID(klass, method)); return (METHOD_ID(klass, method));
} }
// XXX // XXX
//inline traceid JfrTraceId::use(const PackageEntry* package, bool leakp /* false */) { //inline traceid JfrTraceId::use(const PackageEntry* package) {
// assert(package != NULL, "invariant"); // assert(package != NULL, "invariant");
// return set_used_and_get_shifted(package, leakp); // return set_used_and_get(package);
//} //}
inline traceid JfrTraceId::use(const ClassLoaderData* cld, bool leakp /* false */) { inline traceid JfrTraceId::use(const ClassLoaderData* cld) {
assert(cld != NULL, "invariant"); assert(cld != NULL, "invariant");
return cld->is_anonymous() ? 0 : set_used_and_get_shifted(cld, leakp); return cld->is_anonymous() ? 0 : set_used_and_get(cld);
}
inline void JfrTraceId::set_leakp(const Method* method) {
assert(method != NULL, "invariant");
const Klass* const klass = method->method_holder();
assert(klass != NULL, "invariant");
assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
assert(METHOD_FLAG_USED_THIS_EPOCH(method), "invariant");
SET_LEAKP(klass);
SET_METHOD_LEAKP(method);
} }
inline bool JfrTraceId::in_visible_set(const Klass* klass) { inline bool JfrTraceId::in_visible_set(const Klass* klass) {
...@@ -106,10 +110,10 @@ inline bool JfrTraceId::is_jdk_jfr_event(const Klass* k) { ...@@ -106,10 +110,10 @@ inline bool JfrTraceId::is_jdk_jfr_event(const Klass* k) {
inline void JfrTraceId::tag_as_jdk_jfr_event(const Klass* klass) { inline void JfrTraceId::tag_as_jdk_jfr_event(const Klass* klass) {
assert(klass != NULL, "invariant"); assert(klass != NULL, "invariant");
assert(IS_NOT_AN_EVENT_KLASS(klass), "invariant"); // assert(IS_NOT_AN_EVENT_KLASS(klass), "invariant");
SET_TAG(klass, JDK_JFR_EVENT_KLASS); SET_JDK_JFR_EVENT_KLASS(klass);
assert(IS_JDK_JFR_EVENT_KLASS(klass), "invariant"); assert(IS_JDK_JFR_EVENT_KLASS(klass), "invariant");
assert(IS_NOT_AN_EVENT_SUB_KLASS(klass), "invariant"); // assert(IS_NOT_AN_EVENT_SUB_KLASS(klass), "invariant");
} }
inline bool JfrTraceId::is_jdk_jfr_event_sub(const Klass* k) { inline bool JfrTraceId::is_jdk_jfr_event_sub(const Klass* k) {
...@@ -119,8 +123,8 @@ inline bool JfrTraceId::is_jdk_jfr_event_sub(const Klass* k) { ...@@ -119,8 +123,8 @@ inline bool JfrTraceId::is_jdk_jfr_event_sub(const Klass* k) {
inline void JfrTraceId::tag_as_jdk_jfr_event_sub(const Klass* k) { inline void JfrTraceId::tag_as_jdk_jfr_event_sub(const Klass* k) {
assert(k != NULL, "invariant"); assert(k != NULL, "invariant");
if (IS_NOT_AN_EVENT_KLASS(k)) { if (IS_NOT_AN_EVENT_SUB_KLASS(k)) {
SET_TAG(k, JDK_JFR_EVENT_SUBKLASS); SET_JDK_JFR_EVENT_SUBKLASS(k);
} }
assert(IS_JDK_JFR_EVENT_SUBKLASS(k), "invariant"); assert(IS_JDK_JFR_EVENT_SUBKLASS(k), "invariant");
} }
...@@ -141,8 +145,8 @@ inline bool JfrTraceId::is_event_host(const Klass* k) { ...@@ -141,8 +145,8 @@ inline bool JfrTraceId::is_event_host(const Klass* k) {
inline void JfrTraceId::tag_as_event_host(const Klass* k) { inline void JfrTraceId::tag_as_event_host(const Klass* k) {
assert(k != NULL, "invariant"); assert(k != NULL, "invariant");
SET_TAG(k, EVENT_HOST_KLASS); SET_EVENT_HOST_KLASS(k);
assert(IS_EVENT_HOST_KLASS(k), "invariant"); assert(IS_EVENT_HOST_KLASS(k), "invariant");
} }
#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTYPEIDS_INLINE_HPP #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEID_INLINE_HPP
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
* *
*/ */
#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP #ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP
#define SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP #define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP
#include "jfr/utilities/jfrTypes.hpp" #include "jfr/utilities/jfrTypes.hpp"
#include "runtime/atomic.inline.hpp" #include "runtime/atomic.inline.hpp"
...@@ -31,10 +31,10 @@ ...@@ -31,10 +31,10 @@
#ifdef VM_LITTLE_ENDIAN #ifdef VM_LITTLE_ENDIAN
static const int low_offset = 0; static const int low_offset = 0;
static const int leakp_offset = low_offset + 1; static const int meta_offset = low_offset + 1;
#else #else
static const int low_offset = 7; static const int low_offset = 7;
static const int leakp_offset = low_offset - 1; static const int meta_offset = low_offset - 1;
#endif #endif
inline void set_bits(jbyte bits, jbyte* const dest) { inline void set_bits(jbyte bits, jbyte* const dest) {
...@@ -92,17 +92,28 @@ inline void set_traceid_mask(jbyte mask, traceid* dest) { ...@@ -92,17 +92,28 @@ inline void set_traceid_mask(jbyte mask, traceid* dest) {
set_mask(mask, ((jbyte*)dest) + low_offset); set_mask(mask, ((jbyte*)dest) + low_offset);
} }
inline void set_leakp_traceid_bits(jbyte bits, traceid* dest) { inline void set_meta_bits(jbyte bits, jbyte* const dest) {
set_bits(bits, ((jbyte*)dest) + leakp_offset); assert(dest != NULL, "invariant");
*dest |= bits;
}
inline void set_traceid_meta_bits(jbyte bits, traceid* dest) {
set_meta_bits(bits, ((jbyte*)dest) + meta_offset);
} }
inline void set_leakp_traceid_bits_cas(jbyte bits, traceid* dest) { inline void set_meta_mask(jbyte mask, jbyte* const dest) {
set_bits_cas(bits, ((jbyte*)dest) + leakp_offset); assert(dest != NULL, "invariant");
*dest &= mask;
} }
inline void set_leakp_traceid_mask(jbyte mask, traceid* dest) { inline void set_traceid_meta_mask(jbyte mask, traceid* dest) {
set_mask(mask, ((jbyte*)dest) + leakp_offset); set_meta_mask(mask, ((jbyte*)dest) + meta_offset);
} }
#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP // only used by a single thread with no visibility requirements
inline void clear_meta_bits(jbyte bits, jbyte* const dest) {
assert(dest != NULL, "invariant");
*dest ^= bits;
}
#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP
...@@ -32,12 +32,8 @@ ...@@ -32,12 +32,8 @@
#define METHOD_USED_BIT (USED_BIT << 2) #define METHOD_USED_BIT (USED_BIT << 2)
#define EPOCH_1_SHIFT 0 #define EPOCH_1_SHIFT 0
#define EPOCH_2_SHIFT 1 #define EPOCH_2_SHIFT 1
#define LEAKP_SHIFT 8
#define USED_EPOCH_1_BIT (USED_BIT << EPOCH_1_SHIFT) #define USED_EPOCH_1_BIT (USED_BIT << EPOCH_1_SHIFT)
#define USED_EPOCH_2_BIT (USED_BIT << EPOCH_2_SHIFT) #define USED_EPOCH_2_BIT (USED_BIT << EPOCH_2_SHIFT)
#define LEAKP_USED_EPOCH_1_BIT (USED_EPOCH_1_BIT << LEAKP_SHIFT)
#define LEAKP_USED_EPOCH_2_BIT (USED_EPOCH_2_BIT << LEAKP_SHIFT)
#define METHOD_USED_EPOCH_1_BIT (METHOD_USED_BIT << EPOCH_1_SHIFT) #define METHOD_USED_EPOCH_1_BIT (METHOD_USED_BIT << EPOCH_1_SHIFT)
#define METHOD_USED_EPOCH_2_BIT (METHOD_USED_BIT << EPOCH_2_SHIFT) #define METHOD_USED_EPOCH_2_BIT (METHOD_USED_BIT << EPOCH_2_SHIFT)
#define METHOD_AND_CLASS_IN_USE_BITS (METHOD_USED_BIT | USED_BIT) #define METHOD_AND_CLASS_IN_USE_BITS (METHOD_USED_BIT | USED_BIT)
...@@ -75,14 +71,6 @@ class JfrTraceIdEpoch : AllStatic { ...@@ -75,14 +71,6 @@ class JfrTraceIdEpoch : AllStatic {
return _epoch_state ? USED_EPOCH_1_BIT : USED_EPOCH_2_BIT; return _epoch_state ? USED_EPOCH_1_BIT : USED_EPOCH_2_BIT;
} }
static traceid leakp_in_use_this_epoch_bit() {
return _epoch_state ? LEAKP_USED_EPOCH_2_BIT : LEAKP_USED_EPOCH_1_BIT;
}
static traceid leakp_in_use_prev_epoch_bit() {
return _epoch_state ? LEAKP_USED_EPOCH_1_BIT : LEAKP_USED_EPOCH_2_BIT;
}
static traceid method_in_use_this_epoch_bit() { static traceid method_in_use_this_epoch_bit() {
return _epoch_state ? METHOD_USED_EPOCH_2_BIT : METHOD_USED_EPOCH_1_BIT; return _epoch_state ? METHOD_USED_EPOCH_2_BIT : METHOD_USED_EPOCH_1_BIT;
} }
......
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -22,13 +22,8 @@ ...@@ -22,13 +22,8 @@
* *
*/ */
#ifndef SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP #ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
#define SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP #define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
#include "jfr/support/jfrKlassExtension.hpp"
#include "utilities/globalDefinitions.hpp"
/** /**
* *
...@@ -38,150 +33,111 @@ ...@@ -38,150 +33,111 @@
* *
* LeakProfiler subsystem gets its own byte and uses the same tagging scheme but is shifted up 8. * LeakProfiler subsystem gets its own byte and uses the same tagging scheme but is shifted up 8.
* *
* We also tag the individual method by using the TraceFlag field, * We also tag individual methods by using the _trace_flags field,
* (see jfr/support/jfrTraceIdExtension.hpp for details) * (see jfr/support/jfrTraceIdExtension.hpp for details)
* *
*/ */
// these are defined in jfr/support/jfrKlassExtension.hpp // the following are defined in jfr/support/jfrKlassExtension.hpp
// //
// #define JDK_JFR_EVENT_SUBKLASS 16 // #define JDK_JFR_EVENT_SUBKLASS 16
// #define JDK_JFR_EVENT_KLASS 32 // #define JDK_JFR_EVENT_KLASS 32
// #define EVENT_HOST_KLASS 64 // #define EVENT_HOST_KLASS 64
#define IS_JDK_JFR_EVENT_SUBKLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_SUBKLASS)) != 0) // static bits
#define META_SHIFT 8
#define ANY_USED_BITS (USED_EPOCH_2_BIT | \ #define LEAKP_META_BIT USED_BIT
USED_EPOCH_1_BIT | \ #define LEAKP_BIT (LEAKP_META_BIT << META_SHIFT)
METHOD_USED_EPOCH_2_BIT | \ #define TRANSIENT_META_BIT (USED_BIT << 1)
METHOD_USED_EPOCH_1_BIT | \ #define TRANSIENT_BIT (TRANSIENT_META_BIT << META_SHIFT)
LEAKP_USED_EPOCH_2_BIT | \ #define SERIALIZED_META_BIT (USED_BIT << 2)
LEAKP_USED_EPOCH_1_BIT) #define SERIALIZED_BIT (SERIALIZED_META_BIT << META_SHIFT)
#define TRACE_ID_SHIFT 16
#define TRACE_ID_META_BITS (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | ANY_USED_BITS) #define METHOD_ID_NUM_MASK ((1 << TRACE_ID_SHIFT) - 1)
#define META_BITS (SERIALIZED_BIT | TRANSIENT_BIT | LEAKP_BIT)
#define ANY_EVENT (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS) #define EVENT_BITS (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)
#define IS_JDK_JFR_EVENT_KLASS(ptr) (((ptr)->trace_id() & JDK_JFR_EVENT_KLASS) != 0) #define USED_BITS (METHOD_USED_EPOCH_2_BIT | METHOD_USED_EPOCH_1_BIT | USED_EPOCH_2_BIT | USED_EPOCH_1_BIT)
#define IS_EVENT_HOST_KLASS(ptr) (((ptr)->trace_id() & EVENT_HOST_KLASS) != 0) #define ALL_BITS (META_BITS | EVENT_BITS | USED_BITS)
#define IS_NOT_AN_EVENT_KLASS(ptr) (!IS_EVENT_KLASS(ptr)) #define ALL_BITS_MASK (~(ALL_BITS))
#define IS_NOT_AN_EVENT_SUB_KLASS(ptr) (!IS_JDK_JFR_EVENT_SUBKLASS(ptr))
#define IS_NOT_JDK_JFR_EVENT_KLASS(ptr) (!IS_JDK_JFR_EVENT_KLASS(ptr)) // epoch relative bits
#define EVENT_FLAGS_MASK(ptr) (((ptr)->trace_id() & ANY_EVENT) != 0) #define IN_USE_THIS_EPOCH_BIT (JfrTraceIdEpoch::in_use_this_epoch_bit())
#define UNEVENT(ptr) ((ptr)->set_trace_id(((ptr)->trace_id()) & ~ANY_EVENT)) #define IN_USE_PREV_EPOCH_BIT (JfrTraceIdEpoch::in_use_prev_epoch_bit())
#define METHOD_IN_USE_THIS_EPOCH_BIT (JfrTraceIdEpoch::method_in_use_this_epoch_bit())
#define TRACE_ID_SHIFT 16 #define METHOD_IN_USE_PREV_EPOCH_BIT (JfrTraceIdEpoch::method_in_use_prev_epoch_bit())
#define METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS (JfrTraceIdEpoch::method_and_class_in_use_this_epoch_bits())
#define TRACE_ID_MASKED(id) (id & ~TRACE_ID_META_BITS) #define METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS (JfrTraceIdEpoch::method_and_class_in_use_prev_epoch_bits())
#define TRACE_ID_VALUE(id) (TRACE_ID_MASKED(id) >> TRACE_ID_SHIFT) #define METHOD_FLAG_IN_USE_THIS_EPOCH_BIT ((jbyte)IN_USE_THIS_EPOCH_BIT)
#define TRACE_ID_MASKED_PTR(ptr) (TRACE_ID_MASKED((ptr)->trace_id())) #define METHOD_FLAG_IN_USE_PREV_EPOCH_BIT ((jbyte)IN_USE_PREV_EPOCH_BIT)
#define TRACE_ID_RAW(ptr) ((ptr)->trace_id())
#define TRACE_ID(ptr) (TRACE_ID_MASKED_PTR(ptr) >> TRACE_ID_SHIFT) // operators
#define METHOD_ID(kls, meth) (TRACE_ID_MASKED_PTR(kls) | (meth)->method_idnum()) #define TRACE_ID_RAW(ptr) ((ptr)->trace_id())
#define SET_TAG(ptr, tag) (set_traceid_bits(tag, (ptr)->trace_id_addr())) #define TRACE_ID(ptr) (TRACE_ID_RAW(ptr) >> TRACE_ID_SHIFT)
#define SET_LEAKP_TAG(ptr, tag) (set_leakp_traceid_bits(tag, (ptr)->trace_id_addr())) #define TRACE_ID_MASKED(ptr) (TRACE_ID_RAW(ptr) & ALL_BITS_MASK)
#define SET_TAG_CAS(ptr, tag) (set_traceid_bits_cas(tag, (ptr)->trace_id_addr())) #define TRACE_ID_PREDICATE(ptr, bits) ((TRACE_ID_RAW(ptr) & bits) != 0)
#define SET_LEAKP_TAG_CAS(ptr, tag) (set_leakp_traceid_bits_cas(tag, (ptr)->trace_id_addr())) #define TRACE_ID_TAG(ptr, bits) (set_traceid_bits(bits, (ptr)->trace_id_addr()))
#define TRACE_ID_TAG_CAS(ptr, bits) (set_traceid_bits_cas(bits, (ptr)->trace_id_addr()))
#define IN_USE_THIS_EPOCH_BIT (JfrTraceIdEpoch::in_use_this_epoch_bit()) #define TRACE_ID_CLEAR(ptr, bits) (set_traceid_mask(bits, (ptr)->trace_id_addr()))
#define IN_USE_PREV_EPOCH_BIT (JfrTraceIdEpoch::in_use_prev_epoch_bit()) #define TRACE_ID_META_TAG(ptr, bits) (set_traceid_meta_bits(bits, (ptr)->trace_id_addr()))
#define LEAKP_IN_USE_THIS_EPOCH_BIT (JfrTraceIdEpoch::leakp_in_use_this_epoch_bit()) #define TRACE_ID_META_CLEAR(ptr, bits) (set_traceid_meta_mask(bits, (ptr)->trace_id_addr()))
#define LEAKP_IN_USE_PREV_EPOCH_BIT (JfrTraceIdEpoch::leakp_in_use_prev_epoch_bit()) #define METHOD_ID(kls, method) (TRACE_ID_MASKED(kls) | (method)->orig_method_idnum())
#define METHOD_FLAG_PREDICATE(method, bits) ((method)->is_trace_flag_set(bits))
#define METHOD_IN_USE_THIS_EPOCH_BIT (JfrTraceIdEpoch::method_in_use_this_epoch_bit()) #define METHOD_FLAG_TAG(method, bits) (set_bits(bits, (method)->trace_flags_addr()))
#define METHOD_IN_USE_PREV_EPOCH_BIT (JfrTraceIdEpoch::method_in_use_prev_epoch_bit()) #define METHOD_META_TAG(method, bits) (set_meta_bits(bits, (method)->trace_meta_addr()))
#define METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS (JfrTraceIdEpoch::method_and_class_in_use_this_epoch_bits()) #define METHOD_FLAG_CLEAR(method, bits) (clear_bits_cas(bits, (method)->trace_flags_addr()))
#define METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS (JfrTraceIdEpoch::method_and_class_in_use_prev_epoch_bits()) #define METHOD_META_CLEAR(method, bits) (set_meta_mask(bits, (method)->trace_meta_addr()))
#define UNUSE_THIS_EPOCH_MASK (~(IN_USE_THIS_EPOCH_BIT)) // predicates
#define UNUSE_PREV_EPOCH_MASK (~(IN_USE_PREV_EPOCH_BIT)) #define USED_THIS_EPOCH(ptr) (TRACE_ID_PREDICATE(ptr, (TRANSIENT_BIT | IN_USE_THIS_EPOCH_BIT)))
#define LEAKP_UNUSE_THIS_EPOCH_MASK UNUSE_THIS_EPOCH_MASK #define NOT_USED_THIS_EPOCH(ptr) (!(USED_THIS_EPOCH(ptr)))
#define LEAKP_UNUSE_PREV_EPOCH_MASK UNUSE_PREV_EPOCH_MASK #define USED_PREV_EPOCH(ptr) (TRACE_ID_PREDICATE(ptr, (TRANSIENT_BIT | IN_USE_PREV_EPOCH_BIT)))
#define USED_ANY_EPOCH(ptr) (TRACE_ID_PREDICATE(ptr, (TRANSIENT_BIT | USED_EPOCH_2_BIT | USED_EPOCH_1_BIT)))
#define UNUSE_METHOD_THIS_EPOCH_MASK (~(METHOD_IN_USE_THIS_EPOCH_BIT)) #define METHOD_USED_THIS_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (METHOD_IN_USE_THIS_EPOCH_BIT)))
#define UNUSE_METHOD_PREV_EPOCH_MASK (~(METHOD_IN_USE_PREV_EPOCH_BIT)) #define METHOD_NOT_USED_THIS_EPOCH(kls) (!(METHOD_USED_THIS_EPOCH(kls)))
#define LEAKP_UNUSE_METHOD_THIS_EPOCH_MASK (~(UNUSE_METHOD_THIS_EPOCH_MASK)) #define METHOD_USED_PREV_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (METHOD_IN_USE_PREV_EPOCH_BIT)))
#define LEAKP_UNUSE_METHOD_PREV_EPOCH_MASK (~UNUSE_METHOD_PREV_EPOCH_MASK)) #define METHOD_USED_ANY_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (METHOD_IN_USE_PREV_EPOCH_BIT | METHOD_IN_USE_THIS_EPOCH_BIT)))
#define METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS)))
#define UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK (~(METHOD_IN_USE_THIS_EPOCH_BIT | IN_USE_THIS_EPOCH_BIT)) #define METHOD_AND_CLASS_USED_PREV_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS)))
#define UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK (~(METHOD_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT)) #define METHOD_AND_CLASS_USED_ANY_EPOCH(kls) (METHOD_USED_ANY_EPOCH(kls) && USED_ANY_EPOCH(kls))
#define METHOD_FLAG_USED_THIS_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (METHOD_FLAG_IN_USE_THIS_EPOCH_BIT)))
#define SET_USED_THIS_EPOCH(ptr) (SET_TAG(ptr, IN_USE_THIS_EPOCH_BIT)) #define METHOD_FLAG_NOT_USED_THIS_EPOCH(method) (!(METHOD_FLAG_USED_THIS_EPOCH(method)))
#define SET_USED_PREV_EPOCH(ptr) (SET_TAG_CAS(ptr, IN_USE_PREV_EPOCH_BIT)) #define METHOD_FLAG_USED_PREV_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (METHOD_FLAG_IN_USE_PREV_EPOCH_BIT)))
#define SET_LEAKP_USED_THIS_EPOCH(ptr) (SET_LEAKP_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
#define SET_LEAKP_USED_PREV_EPOCH(ptr) (SET_LEAKP_TAG_CAS(ptr, IN_USE_PREV_EPOCH_BIT)) // setters
#define SET_METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (SET_TAG(kls, METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS)) #define SET_USED_THIS_EPOCH(ptr) (TRACE_ID_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
#define SET_METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (TRACE_ID_TAG(kls, METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS))
#define USED_THIS_EPOCH(ptr) (((ptr)->trace_id() & IN_USE_THIS_EPOCH_BIT) != 0) #define SET_METHOD_FLAG_USED_THIS_EPOCH(method) (METHOD_FLAG_TAG(method, METHOD_FLAG_IN_USE_THIS_EPOCH_BIT))
#define NOT_USED_THIS_EPOCH(ptr) (!USED_THIS_EPOCH(ptr)) #define CLEAR_METHOD_AND_CLASS_PREV_EPOCH_MASK (~(METHOD_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT))
#define USED_PREV_EPOCH(ptr) (((ptr)->trace_id() & IN_USE_PREV_EPOCH_BIT) != 0) #define CLEAR_METHOD_AND_CLASS_PREV_EPOCH(kls) (TRACE_ID_CLEAR(kls, CLEAR_METHOD_AND_CLASS_PREV_EPOCH_MASK))
#define NOT_USED_PREV_EPOCH(ptr) (!USED_PREV_EPOCH(ptr)) #define CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method) (METHOD_FLAG_CLEAR(method, METHOD_FLAG_IN_USE_PREV_EPOCH_BIT))
#define USED_ANY_EPOCH(ptr) (((ptr)->trace_id() & (USED_EPOCH_2_BIT | USED_EPOCH_1_BIT)) != 0)
#define NOT_USED_ANY_EPOCH(ptr) (!USED_ANY_EPOCH(ptr)) // types
#define IS_JDK_JFR_EVENT_KLASS(kls) (TRACE_ID_PREDICATE(kls, JDK_JFR_EVENT_KLASS))
#define LEAKP_USED_THIS_EPOCH(ptr) (((ptr)->trace_id() & LEAKP_IN_USE_THIS_EPOCH_BIT) != 0) #define IS_JDK_JFR_EVENT_SUBKLASS(kls) (TRACE_ID_PREDICATE(kls, JDK_JFR_EVENT_SUBKLASS))
#define LEAKP_NOT_USED_THIS_EPOCH(ptr) (!LEAKP_USED_THIS_EPOCH(ptr)) #define IS_NOT_AN_EVENT_SUB_KLASS(kls) (!(IS_JDK_JFR_EVENT_SUBKLASS(kls)))
#define LEAKP_USED_PREV_EPOCH(ptr) (((ptr)->trace_id() & LEAKP_IN_USE_PREV_EPOCH_BIT) != 0) #define IS_EVENT_HOST_KLASS(kls) (TRACE_ID_PREDICATE(kls, EVENT_HOST_KLASS))
#define LEAKP_NOT_USED_PREV_EPOCH(ptr) (!LEAKP_USED_PREV_EPOCH(ptr)) #define SET_JDK_JFR_EVENT_KLASS(kls) (TRACE_ID_TAG(kls, JDK_JFR_EVENT_KLASS))
#define LEAKP_USED_ANY_EPOCH(ptr) (((ptr)->trace_id() & (LEAKP_USED_EPOCH_2_BIT | LEAKP_USED_EPOCH_1_BIT)) != 0) #define SET_JDK_JFR_EVENT_SUBKLASS(kls) (TRACE_ID_TAG(kls, JDK_JFR_EVENT_SUBKLASS))
#define LEAKP_NOT_USED_ANY_EPOCH(ptr) (!LEAKP_USED_ANY_EPOCH(ptr)) #define SET_EVENT_HOST_KLASS(kls) (TRACE_ID_TAG(kls, EVENT_HOST_KLASS))
#define EVENT_KLASS_MASK(kls) (TRACE_ID_RAW(kls) & EVENT_BITS)
#define ANY_USED_THIS_EPOCH(ptr) (((ptr)->trace_id() & (LEAKP_IN_USE_THIS_EPOCH_BIT | IN_USE_THIS_EPOCH_BIT)) != 0)
#define ANY_NOT_USED_THIS_EPOCH(ptr) (!ANY_USED_THIS_EPOCH(ptr)) // meta
#define ANY_USED_PREV_EPOCH(ptr) (((ptr)->trace_id() & (LEAKP_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT)) != 0) #define META_MASK (~(SERIALIZED_META_BIT | TRANSIENT_META_BIT | LEAKP_META_BIT))
#define ANY_NOT_USED_PREV_EPOCH(ptr) (!ANY_USED_PREV_EPOCH(ptr)) #define SET_LEAKP(ptr) (TRACE_ID_META_TAG(ptr, LEAKP_META_BIT))
#define IS_LEAKP(ptr) (TRACE_ID_PREDICATE(ptr, LEAKP_BIT))
#define METHOD_USED_THIS_EPOCH(kls) (((kls)->trace_id() & METHOD_IN_USE_THIS_EPOCH_BIT) != 0) #define SET_TRANSIENT(ptr) (TRACE_ID_META_TAG(ptr, TRANSIENT_META_BIT))
#define METHOD_NOT_USED_THIS_EPOCH(kls) (!METHOD_USED_THIS_EPOCH(kls)) #define IS_SERIALIZED(ptr) (TRACE_ID_PREDICATE(ptr, SERIALIZED_BIT))
#define METHOD_USED_PREV_EPOCH(kls) (((kls)->trace_id() & METHOD_IN_USE_PREV_EPOCH_BIT) != 0) #define IS_NOT_SERIALIZED(ptr) (!(IS_SERIALIZED(ptr)))
#define METHOD_NOT_USED_PREV_EPOCH(kls) (!METHOD_USED_PREV_EPOCH(kls)) #define SHOULD_TAG(ptr) (NOT_USED_THIS_EPOCH(ptr))
#define METHOD_USED_ANY_EPOCH(kls) (((kls)->trace_id() & (METHOD_IN_USE_PREV_EPOCH_BIT | METHOD_IN_USE_THIS_EPOCH_BIT)) != 0) #define SHOULD_TAG_KLASS_METHOD(ptr) (METHOD_NOT_USED_THIS_EPOCH(ptr))
#define SET_SERIALIZED(ptr) (TRACE_ID_META_TAG(ptr, SERIALIZED_META_BIT))
#define METHOD_NOT_USED_ANY_EPOCH(kls) (!METHOD_USED_ANY_EPOCH(kls)) #define CLEAR_SERIALIZED(ptr) (TRACE_ID_META_CLEAR(ptr, META_MASK))
#define IS_METHOD_SERIALIZED(method) (METHOD_FLAG_PREDICATE(method, SERIALIZED_BIT))
#define METHOD_AND_CLASS_USED_THIS_EPOCH(kls) ((((kls)->trace_id() & METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS) == \ #define IS_METHOD_LEAKP_USED(method) (METHOD_FLAG_PREDICATE(method, LEAKP_BIT))
METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS) != 0) #define METHOD_NOT_SERIALIZED(method) (!(IS_METHOD_SERIALIZED(method)))
#define SET_METHOD_LEAKP(method) (METHOD_META_TAG(method, LEAKP_META_BIT))
#define METHOD_AND_CLASS_USED_PREV_EPOCH(kls) ((((kls)->trace_id() & METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS) == \ #define SET_METHOD_SERIALIZED(method) (METHOD_META_TAG(method, SERIALIZED_META_BIT))
METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS) != 0) #define CLEAR_METHOD_SERIALIZED(method) (METHOD_META_CLEAR(method, META_MASK))
#define CLEAR_LEAKP(ptr) (TRACE_ID_META_CLEAR(ptr, (~(LEAKP_META_BIT))))
#define METHOD_AND_CLASS_USED_ANY_EPOCH(kls) ((METHOD_USED_ANY_EPOCH(kls) && USED_ANY_EPOCH(kls)) != 0)
#define METHOD_AND_CLASS_NOT_USED_ANY_EPOCH(kls) (!METHOD_AND_CLASS_USED_ANY_EPOCH(kls)) #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
#define LEAKP_METHOD_IN_USE_THIS_EPOCH (LEAKP_IN_USE_THIS_EPOCH_BIT | METHOD_IN_USE_THIS_EPOCH_BIT)
#define LEAKP_METHOD_IN_USE_PREV_EPOCH (LEAKP_IN_USE_PREV_EPOCH_BIT | METHOD_IN_USE_PREV_EPOCH_BIT)
#define LEAKP_METHOD_USED_THIS_EPOCH(ptr) ((((ptr)->trace_id() & LEAKP_METHOD_IN_USE_THIS_EPOCH) == \
LEAKP_METHOD_IN_USE_THIS_EPOCH) != 0)
#define LEAKP_METHOD_NOT_USED_THIS_EPOCH(kls) (!LEAKP_METHOD_USED_THIS_EPOCH(kls))
#define LEAKP_METHOD_USED_PREV_EPOCH(ptr) ((((ptr)->trace_id() & LEAKP_METHOD_IN_USE_PREV_EPOCH) == \
LEAKP_METHOD_IN_USE_PREV_EPOCH) != 0)
#define LEAKP_METHOD_NOT_USED_PREV_EPOCH(kls) (!LEAKP_METHOD_USED_PREV_EPOCH(kls))
#define UNUSE_THIS_EPOCH(ptr) (set_traceid_mask(UNUSE_THIS_EPOCH_MASK, (ptr)->trace_id_addr()))
#define UNUSE_PREV_EPOCH(ptr) (set_traceid_mask(UNUSE_PREV_EPOCH_MASK, (ptr)->trace_id_addr()))
#define UNUSE_METHOD_THIS_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
#define UNUSE_METHOD_PREV_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
#define LEAKP_UNUSE_THIS_EPOCH(ptr) (set_leakp_traceid_mask(UNUSE_THIS_EPOCH_MASK, (ptr)->trace_id_addr()))
#define LEAKP_UNUSE_PREV_EPOCH(ptr) (set_leakp_traceid_mask(UNUSE_PREV_EPOCH_MASK, (ptr)->trace_id_addr()))
#define LEAKP_UNUSE_METHOD_THIS_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
#define LEAKP_UNUSE_METHOD_PREV_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
#define ANY_USED(ptr) (((ptr)->trace_id() & ANY_USED_BITS) != 0)
#define ANY_NOT_USED(ptr) (!ANY_USED(ptr))
#define UNUSE_METHOD_AND_CLASS_THIS_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
#define LEAKP_UNUSE_METHOD_AND_CLASS_THIS_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
#define UNUSE_METHOD_AND_CLASS_PREV_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
#define LEAKP_UNUSE_METHODS_AND_CLASS_PREV_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
#define METHOD_FLAG_USED_THIS_EPOCH(m) ((m)->is_trace_flag_set((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit()))
#define METHOD_FLAG_NOT_USED_THIS_EPOCH(m) (!METHOD_FLAG_USED_THIS_EPOCH(m))
#define SET_METHOD_FLAG_USED_THIS_EPOCH(m) ((m)->set_trace_flag((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit()))
#define METHOD_FLAG_USED_PREV_EPOCH(m) ((m)->is_trace_flag_set((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit()))
#define METHOD_FLAG_NOT_USED_PREV_EPOCH(m) (!METHOD_FLAG_USED_PREV_EPOCH(m))
#define METHOD_FLAG_USED_ANY_EPOCH(m) ((METHOD_FLAG_USED_THIS_EPOCH(m) || METHOD_FLAG_USED_PREV_EPOCH(m)) != 0)
#define METHOD_FLAG_NOT_USED_ANY_EPOCH(m) ((METHOD_FLAG_NOT_USED_THIS_EPOCH(m) && METHOD_FLAG_NOT_USED_PREV_EPOCH(m)) != 0)
#define CLEAR_METHOD_FLAG_USED_THIS_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit(), (m)->trace_flags_addr()))
#define CLEAR_METHOD_FLAG_USED_PREV_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit(), (m)->trace_flags_addr()))
#endif // SHARE_VM_JFR_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
...@@ -38,7 +38,7 @@ JfrChunkState::JfrChunkState() : ...@@ -38,7 +38,7 @@ JfrChunkState::JfrChunkState() :
_start_nanos(0), _start_nanos(0),
_previous_start_ticks(0), _previous_start_ticks(0),
_previous_start_nanos(0), _previous_start_nanos(0),
_previous_checkpoint_offset(0) {} _last_checkpoint_offset(0) {}
JfrChunkState::~JfrChunkState() { JfrChunkState::~JfrChunkState() {
reset(); reset();
...@@ -49,15 +49,15 @@ void JfrChunkState::reset() { ...@@ -49,15 +49,15 @@ void JfrChunkState::reset() {
JfrCHeapObj::free(_path, strlen(_path) + 1); JfrCHeapObj::free(_path, strlen(_path) + 1);
_path = NULL; _path = NULL;
} }
set_previous_checkpoint_offset(0); set_last_checkpoint_offset(0);
} }
void JfrChunkState::set_previous_checkpoint_offset(jlong offset) { void JfrChunkState::set_last_checkpoint_offset(int64_t offset) {
_previous_checkpoint_offset = offset; _last_checkpoint_offset = offset;
} }
jlong JfrChunkState::previous_checkpoint_offset() const { int64_t JfrChunkState::last_checkpoint_offset() const {
return _previous_checkpoint_offset; return _last_checkpoint_offset;
} }
jlong JfrChunkState::previous_start_ticks() const { jlong JfrChunkState::previous_start_ticks() const {
......
...@@ -37,7 +37,7 @@ class JfrChunkState : public JfrCHeapObj { ...@@ -37,7 +37,7 @@ class JfrChunkState : public JfrCHeapObj {
jlong _start_nanos; jlong _start_nanos;
jlong _previous_start_ticks; jlong _previous_start_ticks;
jlong _previous_start_nanos; jlong _previous_start_nanos;
jlong _previous_checkpoint_offset; int64_t _last_checkpoint_offset;
void update_start_ticks(); void update_start_ticks();
void update_start_nanos(); void update_start_nanos();
...@@ -47,8 +47,8 @@ class JfrChunkState : public JfrCHeapObj { ...@@ -47,8 +47,8 @@ class JfrChunkState : public JfrCHeapObj {
JfrChunkState(); JfrChunkState();
~JfrChunkState(); ~JfrChunkState();
void reset(); void reset();
jlong previous_checkpoint_offset() const; int64_t last_checkpoint_offset() const;
void set_previous_checkpoint_offset(jlong offset); void set_last_checkpoint_offset(int64_t offset);
jlong previous_start_ticks() const; jlong previous_start_ticks() const;
jlong previous_start_nanos() const; jlong previous_start_nanos() const;
jlong last_chunk_duration() const; jlong last_chunk_duration() const;
......
...@@ -87,7 +87,7 @@ void JfrChunkWriter::write_header(intptr_t metadata_offset) { ...@@ -87,7 +87,7 @@ void JfrChunkWriter::write_header(intptr_t metadata_offset) {
// Chunk size // Chunk size
this->write_be_at_offset((jlong)size_written(), CHUNK_SIZE_OFFSET); this->write_be_at_offset((jlong)size_written(), CHUNK_SIZE_OFFSET);
// initial checkpoint event offset // initial checkpoint event offset
this->write_be_at_offset(_chunkstate->previous_checkpoint_offset(), CHUNK_SIZE_OFFSET + (1 * FILEHEADER_SLOT_SIZE)); this->write_be_at_offset(_chunkstate->last_checkpoint_offset(), CHUNK_SIZE_OFFSET + (1 * FILEHEADER_SLOT_SIZE));
// metadata event offset // metadata event offset
this->write_be_at_offset((jlong)metadata_offset, CHUNK_SIZE_OFFSET + (2 * FILEHEADER_SLOT_SIZE)); this->write_be_at_offset((jlong)metadata_offset, CHUNK_SIZE_OFFSET + (2 * FILEHEADER_SLOT_SIZE));
// start of chunk in nanos since epoch // start of chunk in nanos since epoch
...@@ -106,12 +106,12 @@ intptr_t JfrChunkWriter::size_written() const { ...@@ -106,12 +106,12 @@ intptr_t JfrChunkWriter::size_written() const {
return this->is_valid() ? this->current_offset() : 0; return this->is_valid() ? this->current_offset() : 0;
} }
intptr_t JfrChunkWriter::previous_checkpoint_offset() const { int64_t JfrChunkWriter::last_checkpoint_offset() const {
return _chunkstate->previous_checkpoint_offset(); return _chunkstate->last_checkpoint_offset();
} }
void JfrChunkWriter::set_previous_checkpoint_offset(intptr_t offset) { void JfrChunkWriter::set_last_checkpoint_offset(int64_t offset) {
_chunkstate->set_previous_checkpoint_offset(offset); _chunkstate->set_last_checkpoint_offset(offset);
} }
void JfrChunkWriter::time_stamp_chunk_now() { void JfrChunkWriter::time_stamp_chunk_now() {
......
...@@ -49,8 +49,8 @@ class JfrChunkWriter : public JfrChunkWriterBase { ...@@ -49,8 +49,8 @@ class JfrChunkWriter : public JfrChunkWriterBase {
JfrChunkWriter(); JfrChunkWriter();
bool initialize(); bool initialize();
intptr_t size_written() const; intptr_t size_written() const;
intptr_t previous_checkpoint_offset() const; int64_t last_checkpoint_offset() const;
void set_previous_checkpoint_offset(intptr_t offset); void set_last_checkpoint_offset(int64_t offset);
void time_stamp_chunk_now(); void time_stamp_chunk_now();
}; };
......
...@@ -106,10 +106,6 @@ u4 JfrOptionSet::stackdepth() { ...@@ -106,10 +106,6 @@ u4 JfrOptionSet::stackdepth() {
return _stack_depth; return _stack_depth;
} }
static const u4 STACK_DEPTH_DEFAULT = 64;
static const u4 MIN_STACK_DEPTH = 1;
static const u4 MAX_STACK_DEPTH = 2048;
void JfrOptionSet::set_stackdepth(u4 depth) { void JfrOptionSet::set_stackdepth(u4 depth) {
if (depth < MIN_STACK_DEPTH) { if (depth < MIN_STACK_DEPTH) {
_stack_depth = MIN_STACK_DEPTH; _stack_depth = MIN_STACK_DEPTH;
......
...@@ -132,13 +132,13 @@ class RotationLock : public StackObj { ...@@ -132,13 +132,13 @@ class RotationLock : public StackObj {
}; };
static intptr_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) { static intptr_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) {
const intptr_t prev_cp_offset = cw.previous_checkpoint_offset(); const int64_t last_cp_offset = cw.last_checkpoint_offset();
const intptr_t prev_cp_relative_offset = 0 == prev_cp_offset ? 0 : prev_cp_offset - cw.current_offset(); const int64_t delta_to_last_checkpoint = 0 == last_cp_offset ? 0 : last_cp_offset - cw.current_offset();
cw.reserve(sizeof(u4)); cw.reserve(sizeof(u4));
cw.write<u8>(EVENT_CHECKPOINT); cw.write<u8>(EVENT_CHECKPOINT);
cw.write(JfrTicks::now()); cw.write(JfrTicks::now());
cw.write<jlong>((jlong)0); cw.write((int64_t)0); // duration
cw.write<jlong>((jlong)prev_cp_relative_offset); // write previous checkpoint offset delta cw.write(delta_to_last_checkpoint);
cw.write<bool>(false); // flushpoint cw.write<bool>(false); // flushpoint
cw.write<u4>((u4)1); // nof types in this checkpoint cw.write<u4>((u4)1); // nof types in this checkpoint
cw.write<u8>(type_id); cw.write<u8>(type_id);
...@@ -177,7 +177,7 @@ class WriteCheckpointEvent : public StackObj { ...@@ -177,7 +177,7 @@ class WriteCheckpointEvent : public StackObj {
_cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset); _cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset);
_cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset); _cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset);
// update writer with last checkpoint position // update writer with last checkpoint position
_cw.set_previous_checkpoint_offset(current_cp_offset); _cw.set_last_checkpoint_offset(current_cp_offset);
return true; return true;
} }
}; };
...@@ -316,19 +316,16 @@ void JfrRecorderService::rotate(int msgs) { ...@@ -316,19 +316,16 @@ void JfrRecorderService::rotate(int msgs) {
vm_error = true; vm_error = true;
prepare_for_vm_error_rotation(); prepare_for_vm_error_rotation();
} }
if (msgs & (MSGBIT(MSG_STOP))) { if (!_storage.control().to_disk()) {
stop();
}
// action determined by chunkwriter state
if (!_chunkwriter.is_valid()) {
in_memory_rotation(); in_memory_rotation();
return; } else if (vm_error) {
}
if (vm_error) {
vm_error_rotation(); vm_error_rotation();
return; } else {
chunk_rotation();
}
if (msgs & (MSGBIT(MSG_STOP))) {
stop();
} }
chunk_rotation();
} }
void JfrRecorderService::prepare_for_vm_error_rotation() { void JfrRecorderService::prepare_for_vm_error_rotation() {
...@@ -399,12 +396,6 @@ static void write_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_rep ...@@ -399,12 +396,6 @@ static void write_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_rep
WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo); WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo);
write_stack_trace_checkpoint.process(); write_stack_trace_checkpoint.process();
} }
static void write_object_sample_stacktrace(ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repository) {
WriteObjectSampleStacktrace object_sample_stacktrace(sampler, stack_trace_repository);
object_sample_stacktrace.process();
}
static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) { static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
WriteStringPool write_string_pool(string_pool); WriteStringPool write_string_pool(string_pool);
WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool); WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool);
...@@ -439,9 +430,7 @@ void JfrRecorderService::pre_safepoint_write() { ...@@ -439,9 +430,7 @@ void JfrRecorderService::pre_safepoint_write() {
if (LeakProfiler::is_running()) { if (LeakProfiler::is_running()) {
// Exclusive access to the object sampler instance. // Exclusive access to the object sampler instance.
// The sampler is released (unlocked) later in post_safepoint_write. // The sampler is released (unlocked) later in post_safepoint_write.
ObjectSampler* const sampler = ObjectSampler::acquire(); ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire(), _stack_trace_repository);
assert(sampler != NULL, "invariant");
write_object_sample_stacktrace(sampler, _stack_trace_repository);
} }
_storage.write(); _storage.write();
} }
......
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/stacktrace/jfrStackTrace.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/vframe.hpp"
static void copy_frames(JfrStackFrame** lhs_frames, u4 length, const JfrStackFrame* rhs_frames) {
assert(lhs_frames != NULL, "invariant");
assert(rhs_frames != NULL, "invariant");
if (length > 0) {
*lhs_frames = NEW_C_HEAP_ARRAY(JfrStackFrame, length, mtTracing);
memcpy(*lhs_frames, rhs_frames, length * sizeof(JfrStackFrame));
}
}
JfrStackFrame::JfrStackFrame(const traceid& id, int bci, int type, const Method* method) :
_method(method), _methodid(id), _line(0), _bci(bci), _type(type) {}
JfrStackFrame::JfrStackFrame(const traceid& id, int bci, int type, int lineno) :
_method(NULL), _methodid(id), _line(lineno), _bci(bci), _type(type) {}
JfrStackTrace::JfrStackTrace(JfrStackFrame* frames, u4 max_frames) :
_next(NULL),
_frames(frames),
_id(0),
_hash(0),
_nr_of_frames(0),
_max_frames(max_frames),
_frames_ownership(false),
_reached_root(false),
_lineno(false),
_written(false) {}
JfrStackTrace::JfrStackTrace(traceid id, const JfrStackTrace& trace, const JfrStackTrace* next) :
_next(next),
_frames(NULL),
_id(id),
_hash(trace._hash),
_nr_of_frames(trace._nr_of_frames),
_max_frames(trace._max_frames),
_frames_ownership(true),
_reached_root(trace._reached_root),
_lineno(trace._lineno),
_written(false) {
copy_frames(&_frames, trace._nr_of_frames, trace._frames);
}
JfrStackTrace::~JfrStackTrace() {
if (_frames_ownership) {
FREE_C_HEAP_ARRAY(JfrStackFrame, _frames, mtTracing);
}
}
template <typename Writer>
static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
w.write((u8)id);
w.write((u1)!reached_root);
w.write(nr_of_frames);
for (u4 i = 0; i < nr_of_frames; ++i) {
frames[i].write(w);
}
}
void JfrStackTrace::write(JfrChunkWriter& sw) const {
assert(!_written, "invariant");
write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
_written = true;
}
void JfrStackTrace::write(JfrCheckpointWriter& cpw) const {
write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
}
bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
}
bool JfrStackTrace::equals(const JfrStackTrace& rhs) const {
if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
return false;
}
for (u4 i = 0; i < _nr_of_frames; ++i) {
if (!_frames[i].equals(rhs._frames[i])) {
return false;
}
}
return true;
}
template <typename Writer>
static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
w.write((u8)methodid);
w.write((u4)line);
w.write((u4)bci);
w.write((u8)type);
}
void JfrStackFrame::write(JfrChunkWriter& cw) const {
write_frame(cw, _methodid, _line, _bci, _type);
}
void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
write_frame(cpw, _methodid, _line, _bci, _type);
}
class vframeStreamSamples : public vframeStreamCommon {
public:
// constructor that starts with sender of frame fr (top_frame)
vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
_stop_at_java_call_stub = stop_at_java_call_stub;
_frame = fr;
// We must always have a valid frame to start filling
bool filled_in = fill_from_frame();
assert(filled_in, "invariant");
}
void samples_next();
void stop() {}
};
// Solaris SPARC Compiler1 needs an additional check on the grandparent
// of the top_frame when the parent of the top_frame is interpreted and
// the grandparent is compiled. However, in this method we do not know
// the relationship of the current _frame relative to the top_frame so
// we implement a more broad sanity check. When the previous callee is
// interpreted and the current sender is compiled, we verify that the
// current sender is also walkable. If it is not walkable, then we mark
// the current vframeStream as at the end.
void vframeStreamSamples::samples_next() {
// handle frames with inlining
if (_mode == compiled_mode &&
vframeStreamCommon::fill_in_compiled_inlined_sender()) {
return;
}
// handle general case
u4 loop_count = 0;
u4 loop_max = MAX_STACK_DEPTH * 2;
do {
loop_count++;
// By the time we get here we should never see unsafe but better safe then segv'd
if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
_mode = at_end_mode;
return;
}
_frame = _frame.sender(&_reg_map);
} while (!fill_from_frame());
}
bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
vframeStreamSamples st(&thread, frame, false);
u4 count = 0;
_reached_root = true;
while (!st.at_end()) {
if (count >= _max_frames) {
_reached_root = false;
break;
}
const Method* method = st.method();
if (!method->is_valid_method()) {
// we throw away everything we've gathered in this sample since
// none of it is safe
return false;
}
const traceid mid = JfrTraceId::use(method);
int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
int bci = 0;
if (method->is_native()) {
type = JfrStackFrame::FRAME_NATIVE;
} else {
bci = st.bci();
}
const int lineno = method->line_number_from_bci(bci);
// Can we determine if it's inlined?
_hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
_frames[count] = JfrStackFrame(mid, bci, type, method);
st.samples_next();
count++;
}
_lineno = true;
_nr_of_frames = count;
return true;
}
void JfrStackFrame::resolve_lineno() const {
assert(_method, "no method pointer");
assert(_line == 0, "already have linenumber");
_line = _method->line_number_from_bci(_bci);
}
void JfrStackTrace::resolve_linenos() const {
for (unsigned int i = 0; i < _nr_of_frames; i++) {
_frames[i].resolve_lineno();
}
_lineno = true;
}
bool JfrStackTrace::record_safe(JavaThread* thread, int skip, StackWalkMode mode) {
bool success = false;
switch(mode) {
case WALK_BY_DEFAULT:
{
vframeStream vfs(thread);
success = fill_in(vfs, skip, mode);
break;
}
case WALK_BY_CURRENT_FRAME:
{
vframeStream vfs(thread, os::current_frame());
success = fill_in(vfs, skip, mode);
break;
}
default:
ShouldNotReachHere();
}
return success;
}
bool JfrStackTrace::fill_in(vframeStream& vfs, int skip, StackWalkMode mode) {
u4 count = 0;
_reached_root = true;
// Indicates whether the top frame is visited in this frames iteration.
// Top frame bci may be invalid and fill_in() will fix the top frame bci in a conservative way.
bool top_frame_visited = false;
for (int i = 0; i < skip; i++) {
if (vfs.at_end()) {
break;
}
// The top frame is in skip list.
// Mark top_frame_visited to avoid unnecessary top frame bci fixing.
if (!top_frame_visited) {
top_frame_visited = true;
}
vfs.next();
}
while (!vfs.at_end()) {
if (count >= _max_frames) {
_reached_root = false;
break;
}
const Method* method = vfs.method();
const traceid mid = JfrTraceId::use(method);
int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
int bci = 0;
if (method->is_native()) {
type = JfrStackFrame::FRAME_NATIVE;
// The top frame is in native.
// Mark top_frame_visited to avoid unnecessary top frame bci fixing.
if (!top_frame_visited) {
top_frame_visited = true;
}
}
else {
bci = vfs.bci();
// Hit the top frame and fix bci here.
if (!top_frame_visited) {
if (mode == WALK_BY_CURRENT_FRAME) {
// Only fix opto fast path allocation.
// All fast path allocations do not have cached event id.
if (!vfs.thread_ref()->jfr_thread_local()->has_cached_event_id()) {
assert(vfs.thread_ref()->jfr_thread_local()->has_cached_top_frame_bci(), "Invariant");
bci = vfs.thread_ref()->jfr_thread_local()->cached_top_frame_bci();
}
}
top_frame_visited = true;
}
}
// Can we determine if it's inlined?
_hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
_frames[count] = JfrStackFrame(mid, bci, type, method);
vfs.next();
count++;
}
_nr_of_frames = count;
return true;
}
此差异已折叠。
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define JDK_JFR_EVENT_SUBKLASS 16 #define JDK_JFR_EVENT_SUBKLASS 16
#define JDK_JFR_EVENT_KLASS 32 #define JDK_JFR_EVENT_KLASS 32
#define EVENT_HOST_KLASS 64 #define EVENT_HOST_KLASS 64
#define EVENT_RESERVED 128
#define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0) #define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0)
#define ON_KLASS_CREATION(k, p, t) if (IS_EVENT_KLASS(k)) JfrEventClassTransformer::on_klass_creation(k, p, t) #define ON_KLASS_CREATION(k, p, t) if (IS_EVENT_KLASS(k)) JfrEventClassTransformer::on_klass_creation(k, p, t)
......
...@@ -170,7 +170,7 @@ inline u1* WriterHost<BE, IE, WriterPolicyImpl>::ensure_size(size_t requested) { ...@@ -170,7 +170,7 @@ inline u1* WriterHost<BE, IE, WriterPolicyImpl>::ensure_size(size_t requested) {
} }
if (this->available_size() < requested + size_safety_cushion) { if (this->available_size() < requested + size_safety_cushion) {
if (!this->accommodate(this->used_size(), requested + size_safety_cushion)) { if (!this->accommodate(this->used_size(), requested + size_safety_cushion)) {
this->cancel(); assert(!this->is_valid(), "invariant");
return NULL; return NULL;
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册