serialization.py revision effb81e5f8246d0db0270817048dc992db66e9fb
1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""This module handles the JSON de/serialization of the core classes. 6 7This is needed for both long term storage (e.g., loading/storing traces to local 8files) and for short term data exchange (AJAX with the HTML UI). 9 10The rationale of these serializers is to store data in an efficient (i.e. avoid 11to store redundant information) and intelligible (i.e. flatten the classes 12hierarchy keeping only the meaningful bits) format. 13""" 14 15import json 16 17from memory_inspector.classification import results 18from memory_inspector.core import backends 19from memory_inspector.core import memory_map 20from memory_inspector.core import native_heap 21from memory_inspector.core import stacktrace 22from memory_inspector.core import symbol 23 24 25class Encoder(json.JSONEncoder): 26 def default(self, obj): # pylint: disable=E0202 27 if isinstance(obj, memory_map.Map): 28 return [entry.__dict__ for entry in obj.entries] 29 30 if isinstance(obj, symbol.Symbols): 31 return obj.symbols 32 33 if isinstance(obj, (symbol.Symbol, symbol.SourceInfo)): 34 return obj.__dict__ 35 36 if isinstance(obj, native_heap.NativeHeap): 37 # Just keep the list of (distinct) stack frames from the index. Encoding 38 # it as a JSON dictionary would be redundant. 39 return {'stack_frames': obj.stack_frames.values(), 40 'allocations': obj.allocations} 41 42 if isinstance(obj, native_heap.Allocation): 43 return obj.__dict__ 44 45 if isinstance(obj, stacktrace.Stacktrace): 46 # Keep just absolute addrs of stack frames. The full frame details will be 47 # kept in (and rebuilt from) |native_heap.NativeHeap.stack_frames|. See 48 # NativeHeapDecoder below. 49 return [frame.address for frame in obj.frames] 50 51 if isinstance(obj, stacktrace.Frame): 52 # Strip out the symbol information from stack frames. Symbols are stored 53 # (and will be loaded) separately. Rationale: different heap snapshots can 54 # share the same symbol db. Serializing the symbol information for each 55 # stack frame for each heap snapshot is a waste. 56 return {'address': obj.address, 57 'exec_file_rel_path': obj.exec_file_rel_path, 58 'offset': obj.offset} 59 60 if isinstance(obj, (backends.DeviceStats, backends.ProcessStats)): 61 return obj.__dict__ 62 63 if isinstance(obj, results.AggreatedResults): 64 return {'keys': obj.keys, 'buckets': obj.total} 65 66 if isinstance(obj, results.Bucket): 67 return {obj.rule.name : {'values': obj.values, 'children': obj.children}} 68 69 return json.JSONEncoder.default(self, obj) 70 71 72class MmapDecoder(json.JSONDecoder): 73 def decode(self, json_str): # pylint: disable=W0221 74 d = super(MmapDecoder, self).decode(json_str) 75 mmap = memory_map.Map() 76 for entry_dict in d: 77 entry = memory_map.MapEntry(**entry_dict) 78 mmap.Add(entry) 79 return mmap 80 81 82class SymbolsDecoder(json.JSONDecoder): 83 def decode(self, json_str): # pylint: disable=W0221 84 d = super(SymbolsDecoder, self).decode(json_str) 85 symbols = symbol.Symbols() 86 for sym_key, sym_dict in d.iteritems(): 87 sym = symbol.Symbol(sym_dict['name']) 88 for source_info in sym_dict['source_info']: 89 sym.AddSourceLineInfo(**source_info) 90 symbols.symbols[sym_key] = sym 91 return symbols 92 93 94class NativeHeapDecoder(json.JSONDecoder): 95 def decode(self, json_str): # pylint: disable=W0221 96 d = super(NativeHeapDecoder, self).decode(json_str) 97 nh = native_heap.NativeHeap() 98 # First load and rebuild the stack_frame index. 99 for frame_dict in d['stack_frames']: 100 frame = nh.GetStackFrame(frame_dict['address']) 101 frame.SetExecFileInfo(frame_dict['exec_file_rel_path'], 102 frame_dict['offset']) 103 # Then load backtraces (reusing stack frames from the index above). 104 for alloc_dict in d['allocations']: 105 stack_trace = stacktrace.Stacktrace() 106 for absolute_addr in alloc_dict['stack_trace']: 107 stack_trace.Add(nh.GetStackFrame(absolute_addr)) 108 allocation = native_heap.Allocation(alloc_dict['size'], 109 alloc_dict['count'], 110 stack_trace) 111 nh.Add(allocation) 112 return nh