serialization.py revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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.core import backends 18from memory_inspector.core import memory_map 19from memory_inspector.core import native_heap 20from memory_inspector.core import stacktrace 21from memory_inspector.core import symbol 22 23 24class Encoder(json.JSONEncoder): 25 def default(self, obj): # pylint: disable=E0202 26 if isinstance(obj, memory_map.Map): 27 return [entry.__dict__ for entry in obj.entries] 28 29 if isinstance(obj, symbol.Symbols): 30 return obj.symbols 31 32 if isinstance(obj, (symbol.Symbol, symbol.SourceInfo)): 33 return obj.__dict__ 34 35 if isinstance(obj, native_heap.NativeHeap): 36 # Just keep the list of (distinct) stack frames from the index. Encoding 37 # it as a JSON dictionary would be redundant. 38 return {'stack_frames': obj.stack_frames.values(), 39 'allocations': obj.allocations} 40 41 if isinstance(obj, native_heap.Allocation): 42 return obj.__dict__ 43 44 if isinstance(obj, stacktrace.Stacktrace): 45 # Keep just absolute addrs of stack frames. The full frame details will be 46 # kept in (and rebuilt from) |native_heap.NativeHeap.stack_frames|. See 47 # NativeHeapDecoder below. 48 return [frame.address for frame in obj.frames] 49 50 if isinstance(obj, stacktrace.Frame): 51 # Strip out the symbol information from stack frames. Symbols are stored 52 # (and will be loaded) separately. Rationale: different heap snapshots can 53 # share the same symbol db. Serializing the symbol information for each 54 # stack frame for each heap snapshot is a waste. 55 return {'address': obj.address, 56 'exec_file_rel_path': obj.exec_file_rel_path, 57 'offset': obj.offset} 58 59 if isinstance(obj, (backends.DeviceStats, backends.ProcessStats)): 60 return obj.__dict__ 61 62 return json.JSONEncoder.default(self, obj) 63 64 65class MmapDecoder(json.JSONDecoder): 66 def decode(self, json_str): # pylint: disable=W0221 67 d = super(MmapDecoder, self).decode(json_str) 68 mmap = memory_map.Map() 69 for entry_dict in d: 70 entry = memory_map.MapEntry(**entry_dict) 71 mmap.Add(entry) 72 return mmap 73 74 75class SymbolsDecoder(json.JSONDecoder): 76 def decode(self, json_str): # pylint: disable=W0221 77 d = super(SymbolsDecoder, self).decode(json_str) 78 symbols = symbol.Symbols() 79 for sym_key, sym_dict in d.iteritems(): 80 sym = symbol.Symbol(sym_dict['name']) 81 for source_info in sym_dict['source_info']: 82 sym.AddSourceLineInfo(**source_info) 83 symbols.symbols[sym_key] = sym 84 return symbols 85 86 87class NativeHeapDecoder(json.JSONDecoder): 88 def decode(self, json_str): # pylint: disable=W0221 89 d = super(NativeHeapDecoder, self).decode(json_str) 90 nh = native_heap.NativeHeap() 91 # First load and rebuild the stack_frame index. 92 for frame_dict in d['stack_frames']: 93 frame = nh.GetStackFrame(frame_dict['address']) 94 frame.SetExecFileInfo(frame_dict['exec_file_rel_path'], 95 frame_dict['offset']) 96 # Then load backtraces (reusing stack frames from the index above). 97 for alloc_dict in d['allocations']: 98 stack_trace = stacktrace.Stacktrace() 99 for absolute_addr in alloc_dict['stack_trace']: 100 stack_trace.Add(nh.GetStackFrame(absolute_addr)) 101 allocation = native_heap.Allocation(alloc_dict['size'], 102 alloc_dict['count'], 103 stack_trace) 104 nh.Add(allocation) 105 return nh