Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | #ifndef tmreader_h___ |
michael@0 | 7 | #define tmreader_h___ |
michael@0 | 8 | |
michael@0 | 9 | #include "plhash.h" |
michael@0 | 10 | #include "nsTraceMalloc.h" |
michael@0 | 11 | #include "plarena.h" |
michael@0 | 12 | |
michael@0 | 13 | #ifdef __cplusplus |
michael@0 | 14 | extern "C" { |
michael@0 | 15 | #endif |
michael@0 | 16 | |
michael@0 | 17 | typedef struct tmreader tmreader; |
michael@0 | 18 | typedef struct tmevent tmevent; |
michael@0 | 19 | typedef struct tmcounts tmcounts; |
michael@0 | 20 | typedef struct tmallcounts tmallcounts; |
michael@0 | 21 | typedef struct tmgraphlink tmgraphlink; |
michael@0 | 22 | typedef struct tmgraphedge tmgraphedge; |
michael@0 | 23 | typedef struct tmgraphnode tmgraphnode; |
michael@0 | 24 | typedef struct tmcallsite tmcallsite; |
michael@0 | 25 | typedef struct tmmethodnode tmmethodnode; |
michael@0 | 26 | |
michael@0 | 27 | struct tmevent { |
michael@0 | 28 | char type; |
michael@0 | 29 | uint32_t serial; |
michael@0 | 30 | union { |
michael@0 | 31 | char *libname; |
michael@0 | 32 | char *srcname; |
michael@0 | 33 | struct { |
michael@0 | 34 | uint32_t library; |
michael@0 | 35 | uint32_t filename; |
michael@0 | 36 | uint32_t linenumber; |
michael@0 | 37 | char *name; |
michael@0 | 38 | } method; |
michael@0 | 39 | struct { |
michael@0 | 40 | uint32_t parent; |
michael@0 | 41 | uint32_t method; |
michael@0 | 42 | uint32_t offset; |
michael@0 | 43 | } site; |
michael@0 | 44 | struct { |
michael@0 | 45 | uint32_t interval; /* in ticks */ |
michael@0 | 46 | uint32_t ptr; |
michael@0 | 47 | uint32_t size; |
michael@0 | 48 | uint32_t oldserial; |
michael@0 | 49 | uint32_t oldptr; |
michael@0 | 50 | uint32_t oldsize; |
michael@0 | 51 | uint32_t cost; /* in ticks */ |
michael@0 | 52 | } alloc; |
michael@0 | 53 | struct { |
michael@0 | 54 | nsTMStats tmstats; |
michael@0 | 55 | uint32_t calltree_maxkids_parent; |
michael@0 | 56 | uint32_t calltree_maxstack_top; |
michael@0 | 57 | } stats; |
michael@0 | 58 | } u; |
michael@0 | 59 | }; |
michael@0 | 60 | |
michael@0 | 61 | struct tmcounts { |
michael@0 | 62 | uint32_t direct; /* things allocated by this node's code */ |
michael@0 | 63 | uint32_t total; /* direct + things from all descendents */ |
michael@0 | 64 | }; |
michael@0 | 65 | |
michael@0 | 66 | struct tmallcounts { |
michael@0 | 67 | tmcounts bytes; |
michael@0 | 68 | tmcounts calls; |
michael@0 | 69 | }; |
michael@0 | 70 | |
michael@0 | 71 | struct tmgraphnode { |
michael@0 | 72 | PLHashEntry entry; /* key is serial or name, value must be name */ |
michael@0 | 73 | tmgraphlink *in; |
michael@0 | 74 | tmgraphlink *out; |
michael@0 | 75 | tmgraphnode *up; /* parent in supergraph, e.g., JS for JS_*() */ |
michael@0 | 76 | tmgraphnode *down; /* subgraph kids, declining bytes.total order */ |
michael@0 | 77 | tmgraphnode *next; /* next kid in supergraph node's down list */ |
michael@0 | 78 | int low; /* 0 or lowest current tree walk level */ |
michael@0 | 79 | tmallcounts allocs; |
michael@0 | 80 | tmallcounts frees; |
michael@0 | 81 | double sqsum; /* sum of squared bytes.direct */ |
michael@0 | 82 | int sort; /* sorted index in node table, -1 if no table */ |
michael@0 | 83 | }; |
michael@0 | 84 | |
michael@0 | 85 | struct tmmethodnode { |
michael@0 | 86 | tmgraphnode graphnode; |
michael@0 | 87 | char *sourcefile; |
michael@0 | 88 | uint32_t linenumber; |
michael@0 | 89 | }; |
michael@0 | 90 | |
michael@0 | 91 | #define tmgraphnode_name(node) ((char*) (node)->entry.value) |
michael@0 | 92 | #define tmmethodnode_name(node) ((char*) (node)->graphnode.entry.value) |
michael@0 | 93 | |
michael@0 | 94 | #define tmlibrary_serial(lib) ((uint32_t) (lib)->entry.key) |
michael@0 | 95 | #define tmcomponent_name(comp) ((const char*) (comp)->entry.key) |
michael@0 | 96 | #define filename_name(hashentry) ((char*)hashentry->value) |
michael@0 | 97 | |
michael@0 | 98 | /* Half a graphedge, not including per-edge allocation stats. */ |
michael@0 | 99 | struct tmgraphlink { |
michael@0 | 100 | tmgraphlink *next; /* next fanning out from or into a node */ |
michael@0 | 101 | tmgraphnode *node; /* the other node (to if OUT, from if IN) */ |
michael@0 | 102 | }; |
michael@0 | 103 | |
michael@0 | 104 | /* |
michael@0 | 105 | * It's safe to downcast a "from" tmgraphlink (one linked from a node's out |
michael@0 | 106 | * pointer) to tmgraphedge. To go from an "out" (linked via tmgraphedge.from) |
michael@0 | 107 | * or "in" (linked via tmgraphedge.to) list link to its containing edge, use |
michael@0 | 108 | * TM_LINK_TO_EDGE(link, which). |
michael@0 | 109 | */ |
michael@0 | 110 | struct tmgraphedge { |
michael@0 | 111 | tmgraphlink links[2]; |
michael@0 | 112 | tmallcounts allocs; |
michael@0 | 113 | tmallcounts frees; |
michael@0 | 114 | }; |
michael@0 | 115 | |
michael@0 | 116 | /* Indices into tmgraphedge.links -- out must come first. */ |
michael@0 | 117 | #define TM_EDGE_OUT_LINK 0 |
michael@0 | 118 | #define TM_EDGE_IN_LINK 1 |
michael@0 | 119 | |
michael@0 | 120 | #define TM_LINK_TO_EDGE(link,which) ((tmgraphedge*) &(link)[-(which)]) |
michael@0 | 121 | |
michael@0 | 122 | struct tmcallsite { |
michael@0 | 123 | PLHashEntry entry; /* key is site serial number */ |
michael@0 | 124 | tmcallsite *parent; /* calling site */ |
michael@0 | 125 | tmcallsite *siblings; /* other sites reached from parent */ |
michael@0 | 126 | tmcallsite *kids; /* sites reached from here */ |
michael@0 | 127 | tmmethodnode *method; /* method node in tmr->methods graph */ |
michael@0 | 128 | uint32_t offset; /* pc offset from start of method */ |
michael@0 | 129 | tmallcounts allocs; |
michael@0 | 130 | tmallcounts frees; |
michael@0 | 131 | void *data; /* tmreader clients can stick arbitrary |
michael@0 | 132 | * data onto a callsite. |
michael@0 | 133 | */ |
michael@0 | 134 | }; |
michael@0 | 135 | |
michael@0 | 136 | struct tmreader { |
michael@0 | 137 | const char *program; |
michael@0 | 138 | void *data; |
michael@0 | 139 | PLHashTable *libraries; |
michael@0 | 140 | PLHashTable *filenames; |
michael@0 | 141 | PLHashTable *components; |
michael@0 | 142 | PLHashTable *methods; |
michael@0 | 143 | PLHashTable *callsites; |
michael@0 | 144 | PLArenaPool arena; |
michael@0 | 145 | tmcallsite calltree_root; |
michael@0 | 146 | uint32_t ticksPerSec; |
michael@0 | 147 | }; |
michael@0 | 148 | |
michael@0 | 149 | typedef void (*tmeventhandler)(tmreader *tmr, tmevent *event); |
michael@0 | 150 | |
michael@0 | 151 | /* The tmreader constructor and destructor. */ |
michael@0 | 152 | extern tmreader *tmreader_new(const char *program, void *data); |
michael@0 | 153 | extern void tmreader_destroy(tmreader *tmr); |
michael@0 | 154 | |
michael@0 | 155 | /* |
michael@0 | 156 | * Return -1 on permanent fatal error, 0 if filename can't be opened or is not |
michael@0 | 157 | * a trace-malloc logfile, and 1 on success. |
michael@0 | 158 | */ |
michael@0 | 159 | extern int tmreader_eventloop(tmreader *tmr, const char *filename, |
michael@0 | 160 | tmeventhandler eventhandler); |
michael@0 | 161 | |
michael@0 | 162 | /* Map serial number or name to graphnode or callsite. */ |
michael@0 | 163 | extern tmgraphnode *tmreader_library(tmreader *tmr, uint32_t serial); |
michael@0 | 164 | extern tmgraphnode *tmreader_filename(tmreader *tmr, uint32_t serial); |
michael@0 | 165 | extern tmgraphnode *tmreader_component(tmreader *tmr, const char *name); |
michael@0 | 166 | extern tmmethodnode *tmreader_method(tmreader *tmr, uint32_t serial); |
michael@0 | 167 | extern tmcallsite *tmreader_callsite(tmreader *tmr, uint32_t serial); |
michael@0 | 168 | |
michael@0 | 169 | /* |
michael@0 | 170 | * Connect node 'from' to node 'to' with an edge, if there isn't one already |
michael@0 | 171 | * connecting the nodes. Add site's allocation stats to the edge only if we |
michael@0 | 172 | * create the edge, or if we find that it exists, but that to->low is zero or |
michael@0 | 173 | * less than from->low. |
michael@0 | 174 | * |
michael@0 | 175 | * If the callsite tree already totals allocation costs (tmcounts.total for |
michael@0 | 176 | * each site includes tmcounts.direct for that site, plus tmcounts.total for |
michael@0 | 177 | * all kid sites), then the node->low watermarks should be set from the tree |
michael@0 | 178 | * level when walking the callsite tree, and should be set to non-zero values |
michael@0 | 179 | * only if zero (the root is at level 0). A low watermark should be cleared |
michael@0 | 180 | * when the tree walk unwinds past the level at which it was set non-zero. |
michael@0 | 181 | * |
michael@0 | 182 | * Return 0 on error (malloc failure) and 1 on success. |
michael@0 | 183 | */ |
michael@0 | 184 | extern int tmgraphnode_connect(tmgraphnode *from, tmgraphnode *to, |
michael@0 | 185 | tmcallsite *site); |
michael@0 | 186 | |
michael@0 | 187 | #ifdef __cplusplus |
michael@0 | 188 | } |
michael@0 | 189 | #endif |
michael@0 | 190 | |
michael@0 | 191 | #endif /* tmreader_h___ */ |