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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/hotspot/share/logging/logTag.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
LOG_TAG(loader) \
LOG_TAG(logging) \
LOG_TAG(malloc) \
LOG_TAG(map) \
LOG_TAG(mark) \
LOG_TAG(marking) \
LOG_TAG(membername) \
Expand Down
205 changes: 201 additions & 4 deletions src/hotspot/share/memory/archiveBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "logging/log.hpp"
#include "logging/logMessage.hpp"
#include "logging/logStream.hpp"
#include "memory/allStatic.hpp"
#include "memory/archiveBuilder.hpp"
#include "memory/archiveUtils.hpp"
#include "memory/cppVtables.hpp"
#include "memory/dumpAllocStats.hpp"
#include "memory/memRegion.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "oops/instanceKlass.hpp"
Expand Down Expand Up @@ -134,7 +136,7 @@ void ArchiveBuilder::SourceObjList::relocate(int i, ArchiveBuilder* builder) {
_ptrmap.iterate(&relocator, start, end);
}

ArchiveBuilder::ArchiveBuilder(DumpRegion* rw_region, DumpRegion* ro_region)
ArchiveBuilder::ArchiveBuilder(DumpRegion* mc_region, DumpRegion* rw_region, DumpRegion* ro_region)
: _rw_src_objs(), _ro_src_objs(), _src_obj_table(INITIAL_TABLE_SIZE) {
assert(_singleton == NULL, "must be");
_singleton = this;
Expand All @@ -148,6 +150,7 @@ ArchiveBuilder::ArchiveBuilder(DumpRegion* rw_region, DumpRegion* ro_region)
_num_type_array_klasses = 0;
_alloc_stats = new (ResourceObj::C_HEAP, mtClassShared) DumpAllocStats;

_mc_region = mc_region;
_rw_region = rw_region;
_ro_region = ro_region;

Expand Down Expand Up @@ -294,13 +297,13 @@ void ArchiveBuilder::iterate_sorted_roots(MetaspaceClosure* it, bool is_relocati
// original symbols.
int num_symbols = _symbols->length();
for (i = 0; i < num_symbols; i++) {
it->push(&_symbols->at(i));
it->push(_symbols->adr_at(i));
}
}

int num_klasses = _klasses->length();
for (i = 0; i < num_klasses; i++) {
it->push(&_klasses->at(i));
it->push(_klasses->adr_at(i));
}

iterate_roots(it, is_relocating_pointers);
Expand Down Expand Up @@ -592,6 +595,200 @@ void ArchiveBuilder::make_klasses_shareable() {
}
}

// Write detailed info to a mapfile to analyze contents of the archive.
// static dump:
// java -Xshare:dump -Xlog:cds+map=trace:file=cds.map:none:filesize=0
// dynamic dump:
// java -cp MyApp.jar -XX:ArchiveClassesAtExit=MyApp.jsa \
// -Xlog:cds+map=trace:file=cds.map:none:filesize=0 MyApp
//
// We need to do some address translation because the buffers used at dump time may be mapped to
// a different location at runtime. At dump time, the buffers may be at arbitrary locations
// picked by the OS. At runtime, we try to map at a fixed location (SharedBaseAddress). For
// consistency, we log everything using runtime addresses.
class ArchiveBuilder::CDSMapLogger : AllStatic {
static intx buffer_to_runtime_delta() {
// Translate the buffers used by the MC/RW/RO regions to their eventual locations
// at runtime.
return _buffer_to_target_delta + MetaspaceShared::final_delta();
}

// mc/rw/ro regions only
static void write_dump_region(const char* name, DumpRegion* region) {
address region_base = address(region->base());
address region_top = address(region->top());
write_region(name, region_base, region_top, region_base + buffer_to_runtime_delta());
}

#define _LOG_PREFIX PTR_FORMAT ": @@ %-17s %d"

static void write_klass(Klass* k, address runtime_dest, const char* type_name, int bytes, Thread* THREAD) {
ResourceMark rm(THREAD);
log_debug(cds, map)(_LOG_PREFIX " %s",
p2i(runtime_dest), type_name, bytes, k->external_name());
}
static void write_method(Method* m, address runtime_dest, const char* type_name, int bytes, Thread* THREAD) {
ResourceMark rm(THREAD);
log_debug(cds, map)(_LOG_PREFIX " %s",
p2i(runtime_dest), type_name, bytes, m->external_name());
}

// rw/ro regions only
static void write_objects(DumpRegion* region, const ArchiveBuilder::SourceObjList* src_objs) {
address last_obj_base = address(region->base());
address last_obj_end = address(region->base());
address region_end = address(region->end());
Thread* THREAD = Thread::current();
for (int i = 0; i < src_objs->objs()->length(); i++) {
SourceObjInfo* src_info = src_objs->at(i);
address src = src_info->orig_obj();
address dest = src_info->dumped_addr();
write_data(last_obj_base, dest, last_obj_base + buffer_to_runtime_delta());
address runtime_dest = dest + buffer_to_runtime_delta();
int bytes = src_info->size_in_bytes();

MetaspaceObj::Type type = src_info->msotype();
const char* type_name = MetaspaceObj::type_name(type);

switch (type) {
case MetaspaceObj::ClassType:
write_klass((Klass*)src, runtime_dest, type_name, bytes, THREAD);
break;
case MetaspaceObj::ConstantPoolType:
write_klass(((ConstantPool*)src)->pool_holder(),
runtime_dest, type_name, bytes, THREAD);
break;
case MetaspaceObj::ConstantPoolCacheType:
write_klass(((ConstantPoolCache*)src)->constant_pool()->pool_holder(),
runtime_dest, type_name, bytes, THREAD);
break;
case MetaspaceObj::MethodType:
write_method((Method*)src, runtime_dest, type_name, bytes, THREAD);
break;
case MetaspaceObj::ConstMethodType:
write_method(((ConstMethod*)src)->method(), runtime_dest, type_name, bytes, THREAD);
break;
case MetaspaceObj::SymbolType:
{
ResourceMark rm(THREAD);
Symbol* s = (Symbol*)src;
log_debug(cds, map)(_LOG_PREFIX " %s", p2i(runtime_dest), type_name, bytes,
s->as_quoted_ascii());
}
break;
default:
log_debug(cds, map)(_LOG_PREFIX, p2i(runtime_dest), type_name, bytes);
break;
}

last_obj_base = dest;
last_obj_end = dest + bytes;
}

write_data(last_obj_base, last_obj_end, last_obj_base + buffer_to_runtime_delta());
if (last_obj_end < region_end) {
log_debug(cds, map)(PTR_FORMAT ": @@ Misc data " SIZE_FORMAT " bytes",
p2i(last_obj_end + buffer_to_runtime_delta()),
size_t(region_end - last_obj_end));
write_data(last_obj_end, region_end, last_obj_end + buffer_to_runtime_delta());
}
}

#undef _LOG_PREFIX

// Write information about a region, whose address at dump time is [base .. top). At
// runtime, this region will be mapped to runtime_base. runtime_base is 0 if this
// region will be mapped at os-selected addresses (such as the bitmap region), or will
// be accessed with os::read (the header).
static void write_region(const char* name, address base, address top, address runtime_base) {
size_t size = top - base;
base = runtime_base;
top = runtime_base + size;
log_info(cds, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " " SIZE_FORMAT_W(9) " bytes]",
name, p2i(base), p2i(top), size);
}

// open and closed archive regions
static void write_heap_region(const char* which, GrowableArray<MemRegion> *regions) {
for (int i = 0; i < regions->length(); i++) {
address start = address(regions->at(i).start());
address end = address(regions->at(i).end());
write_region(which, start, end, start);
write_data(start, end, start);
}
}

// Dump all the data [base...top). Pretend that the base address
// will be mapped to runtime_base at run-time.
static void write_data(address base, address top, address runtime_base) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider printing the data with os::print_hex_dump() instead. Would slim down this coding.

assert(top >= base, "must be");

LogStreamHandle(Trace, cds, map) lsh;
if (lsh.is_enabled()) {
os::print_hex_dump(&lsh, base, top, sizeof(address), 32, runtime_base);
}
}

static void write_header(FileMapInfo* mapinfo) {
LogStreamHandle(Info, cds, map) lsh;
if (lsh.is_enabled()) {
mapinfo->print(&lsh);
}
}

public:
static void write(ArchiveBuilder* builder, FileMapInfo* mapinfo,
GrowableArray<MemRegion> *closed_heap_regions,
GrowableArray<MemRegion> *open_heap_regions,
char* bitmap, size_t bitmap_size_in_bytes) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider, instead of directly writing to UL, writing to an outputStream*. That would make the code more versatile and reusable. You can then use LogStream to print to UL with the same result.

log_info(cds, map)("%s CDS archive map for %s", DumpSharedSpaces ? "Static" : "Dynamic", mapinfo->full_path());

address header = address(mapinfo->header());
address header_end = header + mapinfo->header()->header_size();
write_region("header", header, header_end, 0);
write_header(mapinfo);
write_data(header, header_end, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider writing out the header members human-readable, that would be more useful than a hexdump. I'd also print them already at Info level, since often the header info is the only thing interesting.


DumpRegion* mc_region = builder->_mc_region;
DumpRegion* rw_region = builder->_rw_region;
DumpRegion* ro_region = builder->_ro_region;

address mc = address(mc_region->base());
address mc_end = address(mc_region->end());
write_dump_region("mc region", mc_region);
write_data(mc, mc_end, mc + buffer_to_runtime_delta());

write_dump_region("rw region", rw_region);
write_objects(rw_region, &builder->_rw_src_objs);

write_dump_region("ro region", ro_region);
write_objects(ro_region, &builder->_ro_src_objs);

address bitmap_end = address(bitmap + bitmap_size_in_bytes);
write_region("bitmap", address(bitmap), bitmap_end, 0);
write_data(header, header_end, 0);

if (closed_heap_regions != NULL) {
write_heap_region("closed heap region", closed_heap_regions);
}
if (open_heap_regions != NULL) {
write_heap_region("open heap region", open_heap_regions);
}

log_info(cds, map)("[End of CDS archive map]");
}
};

void ArchiveBuilder::write_cds_map_to_log(FileMapInfo* mapinfo,
GrowableArray<MemRegion> *closed_heap_regions,
GrowableArray<MemRegion> *open_heap_regions,
char* bitmap, size_t bitmap_size_in_bytes) {
if (log_is_enabled(Info, cds, map)) {
CDSMapLogger::write(this, mapinfo, closed_heap_regions, open_heap_regions,
bitmap, bitmap_size_in_bytes);
}
}

void ArchiveBuilder::print_stats(int ro_all, int rw_all, int mc_all) {
_alloc_stats->print_stats(ro_all, rw_all, mc_all);
}
Expand Down
34 changes: 23 additions & 11 deletions src/hotspot/share/memory/archiveBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@
#include "utilities/resourceHash.hpp"

class CHeapBitMap;
class DumpAllocStats;
class FileMapInfo;
class Klass;
class MemRegion;
class Symbol;
class DumpAllocStats;

class ArchiveBuilder : public StackObj {
public:
Expand Down Expand Up @@ -68,11 +70,18 @@ class ArchiveBuilder : public StackObj {
uintx _ptrmap_end; // The bit-offset of the end of this object (exclusive)
bool _read_only;
FollowMode _follow_mode;
int _size_in_bytes;
MetaspaceObj::Type _msotype;
address _dumped_addr; // Address this->obj(), as used by the dumped archive.
address _orig_obj; // The value of the original object (_ref->obj()) when this
// SourceObjInfo was created. Note that _ref->obj() may change
// later if _ref is relocated.

public:
SourceObjInfo(MetaspaceClosure::Ref* ref, bool read_only, FollowMode follow_mode) :
_ref(ref), _ptrmap_start(0), _ptrmap_end(0), _read_only(read_only), _follow_mode(follow_mode) {
_ref(ref), _ptrmap_start(0), _ptrmap_end(0), _read_only(read_only), _follow_mode(follow_mode),
_size_in_bytes(ref->size() * BytesPerWord), _msotype(ref->msotype()),
_orig_obj(ref->obj()) {
if (follow_mode == point_to_it) {
_dumped_addr = ref->obj();
} else {
Expand All @@ -93,8 +102,10 @@ class ArchiveBuilder : public StackObj {
uintx ptrmap_start() const { return _ptrmap_start; } // inclusive
uintx ptrmap_end() const { return _ptrmap_end; } // exclusive
bool read_only() const { return _read_only; }
int size_in_bytes() const { return _ref->size() * BytesPerWord; }
int size_in_bytes() const { return _size_in_bytes; }
address orig_obj() const { return _orig_obj; }
address dumped_addr() const { return _dumped_addr; }
MetaspaceObj::Type msotype() const { return _msotype; }

// convenience accessor
address obj() const { return ref()->obj(); }
Expand Down Expand Up @@ -127,9 +138,12 @@ class ArchiveBuilder : public StackObj {
}
};

class CDSMapLogger;

static const int INITIAL_TABLE_SIZE = 15889;
static const int MAX_TABLE_SIZE = 1000000;

DumpRegion* _mc_region;
DumpRegion* _rw_region;
DumpRegion* _ro_region;

Expand Down Expand Up @@ -180,19 +194,12 @@ class ArchiveBuilder : public StackObj {

bool is_excluded(Klass* k);
void clean_up_src_obj_table();

protected:
virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) = 0;

// Conservative estimate for number of bytes needed for:
size_t _estimated_metsapceobj_bytes; // all archived MetsapceObj's.

void set_dump_regions(DumpRegion* rw_region, DumpRegion* ro_region) {
assert(_rw_region == NULL && _ro_region == NULL, "do not change");
_rw_region = rw_region;
_ro_region = ro_region;
}

protected:
DumpRegion* _current_dump_space;
address _alloc_bottom;
Expand Down Expand Up @@ -225,7 +232,7 @@ class ArchiveBuilder : public StackObj {
}

public:
ArchiveBuilder(DumpRegion* rw_region, DumpRegion* ro_region);
ArchiveBuilder(DumpRegion* mc_region, DumpRegion* rw_region, DumpRegion* ro_region);
~ArchiveBuilder();

void gather_klasses_and_symbols();
Expand All @@ -240,6 +247,11 @@ class ArchiveBuilder : public StackObj {
void relocate_pointers();
void relocate_well_known_klasses();
void make_klasses_shareable();
void write_cds_map_to_log(FileMapInfo* mapinfo,
GrowableArray<MemRegion> *closed_heap_regions,
GrowableArray<MemRegion> *open_heap_regions,
char* bitmap, size_t bitmap_size_in_bytes);

address get_dumped_addr(address src_obj) const;

// All klasses and symbols that will be copied into the archive
Expand Down
12 changes: 9 additions & 3 deletions src/hotspot/share/memory/dynamicArchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
}

public:
DynamicArchiveBuilder() : ArchiveBuilder(NULL, NULL) {
DynamicArchiveBuilder() : ArchiveBuilder(MetaspaceShared::misc_code_dump_space(),
MetaspaceShared::read_write_dump_space(),
MetaspaceShared::read_only_dump_space()) {
_estimated_hashtable_bytes = 0;
_estimated_trampoline_bytes = 0;

Expand Down Expand Up @@ -177,7 +179,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder {

// rw space starts ...
address reserved_bottom = reserve_space_and_init_buffer_to_target_delta();
set_dump_regions(MetaspaceShared::read_write_dump_space(), MetaspaceShared::read_only_dump_space());
init_header(reserved_bottom);

CHeapBitMap ptrmap;
Expand Down Expand Up @@ -566,12 +567,17 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) {
// Now write the archived data including the file offsets.
const char* archive_name = Arguments::GetSharedDynamicArchivePath();
dynamic_info->open_for_write(archive_name);
MetaspaceShared::write_core_archive_regions(dynamic_info, NULL, NULL);
size_t bitmap_size_in_bytes;
char* bitmap = MetaspaceShared::write_core_archive_regions(dynamic_info, NULL, NULL, bitmap_size_in_bytes);
dynamic_info->set_final_requested_base((char*)MetaspaceShared::requested_base_address());
dynamic_info->set_header_crc(dynamic_info->compute_header_crc());
dynamic_info->write_header();
dynamic_info->close();

write_cds_map_to_log(dynamic_info, NULL, NULL,
bitmap, bitmap_size_in_bytes);
FREE_C_HEAP_ARRAY(char, bitmap);

address base = to_target(_alloc_bottom);
address top = address(current_dump_space()->top()) + _buffer_to_target_delta;
size_t file_size = pointer_delta(top, base, sizeof(char));
Expand Down
Loading