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