Skip to content

Commit

Permalink
Copied in initial version of code from oneoff script
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Hagy committed Oct 28, 2015
1 parent 5f2de01 commit e7cf59c
Show file tree
Hide file tree
Showing 5 changed files with 528 additions and 0 deletions.
3 changes: 3 additions & 0 deletions pyhprof/__init__.py
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__
97 changes: 97 additions & 0 deletions pyhprof/blocks.py
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
}
56 changes: 56 additions & 0 deletions pyhprof/constants.py
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
}
202 changes: 202 additions & 0 deletions pyhprof/heap_blocks.py
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
}
Loading

0 comments on commit e7cf59c

Please sign in to comment.