-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Copied in initial version of code from oneoff script
- Loading branch information
Matt Hagy
committed
Oct 28, 2015
1 parent
5f2de01
commit e7cf59c
Showing
5 changed files
with
528 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from pyhprof import * | ||
from pyhprof import __doc__ | ||
from pyhprof import __all__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
|
||
from contextlib import contextmanager | ||
|
||
class BaseBlock(object): | ||
|
||
def __init__(self, tag, parser, record_time, start, length): | ||
self.tag = tag | ||
self.parser = parser | ||
self.record_time = record_time | ||
self.start = start | ||
self.length = length | ||
|
||
@property | ||
def tag_name(self): | ||
return TAGS.get(self.tag, 'UNKOWN') | ||
|
||
@property | ||
def timestamp(self): | ||
return self.parser.start_time / 1e3 + self.record_time / 1e6 | ||
|
||
def __str__(self): | ||
return '%s @ %s of length %d' % (self.tag_name, time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(self.timestamp)), self.length) | ||
|
||
|
||
class GenericBlock(BaseBlock): | ||
|
||
pass | ||
|
||
class StringBlock(BaseBlock): | ||
|
||
_id = _contents = None | ||
|
||
def read_contents(self): | ||
with self.parser.goto(self.start): | ||
s_id = self.parser.read_id() | ||
contents = self.parser.f.read(self.length - self.parser.id_size) | ||
contents = contents.decode('utf-8') | ||
self._id = s_id | ||
self._contents = contents | ||
|
||
@property | ||
def id(self): | ||
if self._id is None: | ||
self.read_contents() | ||
return self._id | ||
|
||
@property | ||
def contents(self): | ||
if self._contents is None: | ||
self.read_contents() | ||
return self._contents | ||
|
||
def __str__(self): | ||
return '%s %d %r' % (self.tag_name, self.id, self.contents) | ||
|
||
|
||
class LoadClass(BaseBlock): | ||
_serial_number = _class_id = _stack_trace = _class_name_id = None | ||
|
||
def read_contents(self): | ||
with self.parser.goto(self.start): | ||
self._serial_number = self.parser.i4() | ||
self._class_id = self.parser.read_id() | ||
self._stack_trace = self.parser.i4() | ||
self._class_name_id = self.parser.read_id() | ||
|
||
@property | ||
def class_id(self): | ||
if self._class_id is None: | ||
self.read_contents() | ||
return self._class_id | ||
|
||
@property | ||
def class_name_id(self): | ||
if self._class_name_id is None: | ||
self.read_contents() | ||
return self._class_name_id | ||
|
||
|
||
class HeapDump(BaseBlock): | ||
|
||
@contextmanager | ||
def heap_parser(self): | ||
from .parsers import HeapDumpParser | ||
with self.parser.goto(self.start): | ||
yield HeapDumpParser(self.parser.f, self.parser.id_size, self.length) | ||
|
||
def __iter__(self): | ||
with heap_parser(self) as hp: | ||
for b in hp: | ||
yield b | ||
|
||
BLOCK_CLASSES_BY_TAG = { | ||
'STRING': StringBlock, | ||
'LOAD_CLASS': LoadClass, | ||
'HEAP_DUMP': HeapDump | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
|
||
TAGS = { | ||
0x01: 'STRING', | ||
0x02: 'LOAD_CLASS', | ||
0x03: 'UNLOAD_CLASS', | ||
0x04: 'STACK_FRAME', | ||
0x05: 'STACK_TRACE', | ||
0x06: 'ALLOC_SITES', | ||
0x07: 'HEAP_SUMMARY', | ||
0x0A: 'START_THREAD', | ||
0x0B: 'END_THREAD', | ||
0x0C: 'HEAP_DUMP', | ||
0x1C: 'HEAP_DUMP_SEGMENT', | ||
0x2C: 'HEAP_DUMP_END', | ||
0x0D: 'CPU_SAMPLES', | ||
0x0E: 'CONTROL_SETTINGS' | ||
} | ||
|
||
HEAP_DUMP_SUB_TAGS = { | ||
0xFF : 'ROOT_UNKNOWN', | ||
0x01 : 'ROOT_JNI_GLOBAL', | ||
0x02 : 'ROOT_JNI_LOCAL', | ||
0x03 : 'ROOT_JAVA_FRAME', | ||
0x04 : 'ROOT_NATIVE_STACK', | ||
0x05 : 'ROOT_STICKY_CLASS', | ||
0x06 : 'ROOT_THREAD_BLOCK', | ||
0x07 : 'ROOT_MONITOR_USED', | ||
0x08 : 'ROOT_THREAD_OBJECT', | ||
0x20 : 'CLASS_DUMP', | ||
0x21 : 'INSTANCE_DUMP', | ||
0x22 : 'OBJECT_ARRAY_DUMP', | ||
0x23 : 'PRIMITIVE_ARRAY_DUMP' | ||
} | ||
|
||
OBJECT_TYPES = { | ||
2: 'OBJECT', | ||
4: 'BOOLEAN', | ||
5: 'CHAR', | ||
6: 'FLOAT', | ||
7: 'DOUBLE', | ||
8: 'BYTE', | ||
9: 'SHORT', | ||
10: 'INT', | ||
11: 'LONG' | ||
} | ||
|
||
TYPE_SIZES = { | ||
'BOOLEAN': 1, | ||
'CHAR': 2, | ||
'FLOAT': 4, | ||
'DOUBLE': 8, | ||
'BYTE': 1, | ||
'SHORT': 2, | ||
'INT': 4, | ||
'LONG': 8 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
|
||
class BaseHeapDumpBlock(object): | ||
|
||
def __init__(self, id): | ||
self.id = id | ||
|
||
class BaseOnlyIdHeapDumpBlock(BaseHeapDumpBlock): | ||
|
||
@classmethod | ||
def parse(cls, p): | ||
return cls(p.read_id()) | ||
|
||
class BaseThreadHeapDumpBlock(BaseHeapDumpBlock): | ||
|
||
def __init__(self, id, thread_serial_number): | ||
super(BaseThreadFrameHeadDumpBlock, self).__init__(id) | ||
self.thread_serial_number = thread_serial_number | ||
|
||
@classmethod | ||
def parse(cls, p): | ||
return cls(p.read_id(), p.i4()) | ||
|
||
class BaseThreadFrameHeadDumpBlock(BaseThreadHeapDumpBlock): | ||
|
||
def __init__(self, id, thread_serial_number, frame_number): | ||
super(BaseThreadFrameHeadDumpBlock, self).__init__(id, thread_serial_number) | ||
self.frame_number = frame_number | ||
|
||
@classmethod | ||
def parse(cls, p): | ||
return cls(p.read_id(), p.i4(), p.i4()) | ||
|
||
class RootUnkown(BaseOnlyIdHeapDumpBlock): | ||
|
||
pass | ||
|
||
class RootJniGlobal(BaseHeapDumpBlock): | ||
|
||
def __init__(self, id, jni_global_ref): | ||
super(RootJniGlobal, self).__init__(id) | ||
self.jni_global_ref = jni_global_ref | ||
|
||
@classmethod | ||
def prase(cls, p): | ||
return cls(p.read_id(), p.read_id()) | ||
|
||
class RootJniLocal(BaseThreadFrameHeadDumpBlock): | ||
|
||
pass | ||
|
||
class RootJavaFrame(BaseThreadFrameHeadDumpBlock): | ||
|
||
pass | ||
|
||
class RootNativeStack(BaseThreadHeapDumpBlock): | ||
|
||
pass | ||
|
||
class RootStickyClass(BaseOnlyIdHeapDumpBlock): | ||
|
||
pass | ||
|
||
class RootThreadBlock(BaseThreadHeapDumpBlock): | ||
|
||
pass | ||
|
||
class RootMonitorUsed(BaseOnlyIdHeapDumpBlock): | ||
|
||
pass | ||
|
||
class RootThreadObject(BaseThreadHeapDumpBlock): | ||
|
||
def __init__(self, id, thread_serial_number, stack_trace_serial_number): | ||
super(BaseThreadFrameHeadDumpBlock, self).__init__(id, thread_serial_number) | ||
self.stack_trace_serial_number = stack_trace_serial_number | ||
|
||
@classmethod | ||
def parse(cls, p): | ||
return cls(p.read_id(), p.i4(), p.i4()) | ||
|
||
class ClassDump(BaseHeapDumpBlock): | ||
|
||
def __init__(self, | ||
id, | ||
stack_trace_serial_number, | ||
super_class_id, | ||
class_loader_id, | ||
signers_object_id, | ||
protection_domain_object_id, | ||
reserved1, | ||
reserved2, | ||
instance_size, | ||
constants_pool, | ||
static_fields, | ||
instance_fields): | ||
super(ClassDump, self).__init__(id) | ||
vars(self).update(locals()) | ||
del self.self | ||
|
||
@classmethod | ||
def parse(cls, p): | ||
id = p.read_id() | ||
stack_trace_serial_number = p.i4() | ||
super_class_id = p.read_id() | ||
class_loader_id = p.read_id() | ||
signers_object_id = p.read_id() | ||
protection_domain_object_id = p.read_id() | ||
reserved1 = p.read_id() | ||
reserved2 = p.read_id() | ||
instance_size = p.i4() | ||
constants = [cls.read_constant(p) for _ in xrange(p.i2())] | ||
static_fields = [cls.read_static_field(p) for _ in xrange(p.i2())] | ||
instance_fields = [cls.read_instance_field(p) for _ in xrange(p.i2())] | ||
return cls(id, stack_trace_serial_number, super_class_id, class_loader_id, signers_object_id, protection_domain_object_id, | ||
reserved1, reserved2, instance_size, constants, static_fields, instance_fields) | ||
|
||
@classmethod | ||
def read_constant(cls, p): | ||
pool_index = p.i2() | ||
tp = p.read_value_type() | ||
value = p.read_value(tp) | ||
return [pool_index, tp, value] | ||
|
||
@classmethod | ||
def read_static_field(cls, p): | ||
name_id = p.read_id() | ||
tp = p.read_value_type() | ||
value = p.read_value(tp) | ||
return [name_id, tp, value] | ||
|
||
@classmethod | ||
def read_instance_field(cls, p): | ||
name_id = p.read_id() | ||
tp = p.read_value_type() | ||
return [name_id, tp] | ||
|
||
class InstanceDump(BaseHeapDumpBlock): | ||
|
||
def __init__(self, id, stack_trace_serial_number, class_object_id, bytes): | ||
self.id = id | ||
self.stack_trace_serial_number = stack_trace_serial_number | ||
self.class_object_id = class_object_id | ||
self.bytes = bytes | ||
|
||
@classmethod | ||
def parse(cls, p): | ||
id = p.read_id() | ||
stack_trace_serial_number = p.i4() | ||
class_object_id = p.read_id() | ||
n_bytes = p.i4() | ||
bytes = p.read(n_bytes) | ||
return cls(id, stack_trace_serial_number, class_object_id, bytes) | ||
|
||
class ObjectArrayDump(BaseHeapDumpBlock): | ||
|
||
def __init__(self, id, stack_trace_serial_number, array_class_object_id, elements): | ||
self.id = id | ||
self.stack_trace_serial_number = stack_trace_serial_number | ||
self.array_class_object_id = array_class_object_id | ||
self.elements = elements | ||
|
||
@classmethod | ||
def parse(cls, p): | ||
id = p.read_id() | ||
stack_trace_serial_number = p.i4() | ||
n_elements = p.i4() | ||
array_class_object_id = p.read_id() | ||
elements = [p.read_id() for _ in xrange(n_elements)] | ||
return cls(id, stack_trace_serial_number, array_class_object_id, elements) | ||
|
||
class PrimitiveArrayDump(BaseHeapDumpBlock): | ||
|
||
def __init__(self, id, stack_trace_serial_number, element_type, size): | ||
self.id = id | ||
self.stack_trace_serial_number = stack_trace_serial_number | ||
self.element_type = element_type | ||
self.size = size | ||
|
||
@classmethod | ||
def parse(cls, p): | ||
id = p.read_id() | ||
stack_trace_serial_number = p.i4() | ||
size = p.i4() | ||
element_type = p.read_value_type() | ||
p.seek(p.type_size(element_type) * size) | ||
return cls(id, stack_trace_serial_number, element_type, size) | ||
|
||
HEAP_BLOCK_CLASSES_BY_TAG = { | ||
'ROOT_UNKNOWN' : RootUnkown, | ||
'ROOT_JNI_GLOBAL' : RootJniGlobal, | ||
'ROOT_JNI_LOCAL' : RootJniLocal, | ||
'ROOT_JAVA_FRAME' : RootJavaFrame, | ||
'ROOT_NATIVE_STACK' : RootNativeStack, | ||
'ROOT_STICKY_CLASS' : RootStickyClass, | ||
'ROOT_THREAD_BLOCK' : RootThreadBlock, | ||
'ROOT_MONITOR_USED' : RootMonitorUsed, | ||
'ROOT_THREAD_OBJECT' : RootThreadObject, | ||
'CLASS_DUMP' : ClassDump, | ||
'INSTANCE_DUMP' : InstanceDump, | ||
'OBJECT_ARRAY_DUMP' : ObjectArrayDump, | ||
'PRIMITIVE_ARRAY_DUMP' : PrimitiveArrayDump | ||
} |
Oops, something went wrong.