Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: src/profile-generator.cc

Issue 3311028: Implement heap snapshots serialization into JSON. API is designed (Closed)
Patch Set: Comments addressed Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/profile-generator.h ('k') | src/unicode.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 13 matching lines...) Expand all
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #ifdef ENABLE_LOGGING_AND_PROFILING 28 #ifdef ENABLE_LOGGING_AND_PROFILING
29 29
30 #include "v8.h" 30 #include "v8.h"
31 #include "global-handles.h" 31 #include "global-handles.h"
32 #include "scopeinfo.h" 32 #include "scopeinfo.h"
33 #include "top.h" 33 #include "top.h"
34 #include "unicode.h"
34 #include "zone-inl.h" 35 #include "zone-inl.h"
35 36
36 #include "profile-generator-inl.h" 37 #include "profile-generator-inl.h"
37 38
38 namespace v8 { 39 namespace v8 {
39 namespace internal { 40 namespace internal {
40 41
41 42
42 TokenEnumerator::TokenEnumerator() 43 TokenEnumerator::TokenEnumerator()
43 : token_locations_(4), 44 : token_locations_(4),
(...skipping 2081 matching lines...) Expand 10 before | Expand all | Expand 10 after
2125 } 2126 }
2126 int add_child_index = 0, added_entry_index = 1; 2127 int add_child_index = 0, added_entry_index = 1;
2127 for (int i = 0; i < added_entries.length(); ++i) { 2128 for (int i = 0; i < added_entries.length(); ++i) {
2128 HeapEntry* entry = added_entries[i]; 2129 HeapEntry* entry = added_entries[i];
2129 if (entry->painted_reachable()) 2130 if (entry->painted_reachable())
2130 diff->AddAddedEntry(add_child_index++, added_entry_index++, entry); 2131 diff->AddAddedEntry(add_child_index++, added_entry_index++, entry);
2131 } 2132 }
2132 return diff; 2133 return diff;
2133 } 2134 }
2134 2135
2136
2137 class OutputStreamWriter {
2138 public:
2139 explicit OutputStreamWriter(v8::OutputStream* stream)
2140 : stream_(stream),
2141 chunk_size_(stream->GetChunkSize()),
2142 chunk_(chunk_size_),
2143 chunk_pos_(0) {
2144 ASSERT(chunk_size_ > 0);
2145 }
2146 void AddCharacter(char c) {
2147 ASSERT(c != '\0');
2148 ASSERT(chunk_pos_ < chunk_size_);
2149 chunk_[chunk_pos_++] = c;
2150 MaybeWriteChunk();
2151 }
2152 void AddString(const char* s) {
2153 AddSubstring(s, StrLength(s));
2154 }
2155 void AddSubstring(const char* s, int n) {
2156 if (n <= 0) return;
2157 ASSERT(static_cast<size_t>(n) <= strlen(s));
2158 const char* s_end = s + n;
2159 while (s < s_end) {
2160 int s_chunk_size = Min(
2161 chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
2162 ASSERT(s_chunk_size > 0);
2163 memcpy(chunk_.start() + chunk_pos_, s, s_chunk_size);
2164 s += s_chunk_size;
2165 chunk_pos_ += s_chunk_size;
2166 MaybeWriteChunk();
2167 }
2168 }
2169 void AddNumber(int n) { AddNumberImpl<int>(n, "%d"); }
2170 void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
2171 void AddNumber(uint64_t n) { AddNumberImpl<uint64_t>(n, "%llu"); }
2172 void Finalize() {
2173 ASSERT(chunk_pos_ < chunk_size_);
2174 if (chunk_pos_ != 0) {
2175 WriteChunk();
2176 }
2177 stream_->EndOfStream();
2178 }
2179
2180 private:
2181 template<typename T>
2182 void AddNumberImpl(T n, const char* format) {
2183 ScopedVector<char> buffer(32);
2184 int result = OS::SNPrintF(buffer, format, n);
2185 USE(result);
2186 ASSERT(result != -1);
2187 AddString(buffer.start());
2188 }
2189 void MaybeWriteChunk() {
2190 ASSERT(chunk_pos_ <= chunk_size_);
2191 if (chunk_pos_ == chunk_size_) {
2192 WriteChunk();
2193 chunk_pos_ = 0;
2194 }
2195 }
2196 void WriteChunk() {
2197 stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_);
2198 }
2199
2200 v8::OutputStream* stream_;
2201 int chunk_size_;
2202 ScopedVector<char> chunk_;
2203 int chunk_pos_;
2204 };
2205
2206 void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
2207 ASSERT(writer_ == NULL);
2208 writer_ = new OutputStreamWriter(stream);
2209
2210 // Since nodes graph is cyclic, we need the first pass to enumerate
2211 // them. Strings can be serialized in one pass.
2212 EnumerateNodes();
2213
2214 writer_->AddCharacter('{');
2215 writer_->AddString("\"snapshot\":{");
2216 SerializeSnapshot();
2217 writer_->AddString("},\n");
2218 writer_->AddString("\"nodes\":[");
2219 SerializeNodes();
2220 writer_->AddString("],\n");
2221 writer_->AddString("\"strings\":[");
2222 SerializeStrings();
2223 writer_->AddCharacter(']');
2224 writer_->AddCharacter('}');
2225 writer_->Finalize();
2226
2227 delete writer_;
2228 writer_ = NULL;
2229 }
2230
2231
2232 class HeapSnapshotJSONSerializerEnumerator {
2233 public:
2234 explicit HeapSnapshotJSONSerializerEnumerator(HeapSnapshotJSONSerializer* s)
2235 : s_(s) {
2236 }
2237 void Apply(HeapEntry** entry) {
2238 s_->GetNodeId(*entry);
2239 }
2240 private:
2241 HeapSnapshotJSONSerializer* s_;
2242 };
2243
2244 void HeapSnapshotJSONSerializer::EnumerateNodes() {
2245 GetNodeId(snapshot_->root()); // Make sure root gets the first id.
2246 HeapSnapshotJSONSerializerEnumerator iter(this);
2247 snapshot_->IterateEntries(&iter);
2248 }
2249
2250
2251 int HeapSnapshotJSONSerializer::GetNodeId(HeapEntry* entry) {
2252 HashMap::Entry* cache_entry = nodes_.Lookup(entry, ObjectHash(entry), true);
2253 if (cache_entry->value == NULL) {
2254 cache_entry->value = reinterpret_cast<void*>(next_node_id_++);
2255 }
2256 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
2257 }
2258
2259
2260 int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
2261 HashMap::Entry* cache_entry = strings_.Lookup(
2262 const_cast<char*>(s), ObjectHash(s), true);
2263 if (cache_entry->value == NULL) {
2264 cache_entry->value = reinterpret_cast<void*>(next_string_id_++);
2265 }
2266 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
2267 }
2268
2269
2270 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) {
2271 writer_->AddCharacter(',');
2272 writer_->AddNumber(edge->type());
2273 writer_->AddCharacter(',');
2274 if (edge->type() == HeapGraphEdge::kElement) {
2275 writer_->AddNumber(edge->index());
2276 } else {
2277 writer_->AddNumber(GetStringId(edge->name()));
2278 }
2279 writer_->AddCharacter(',');
2280 writer_->AddNumber(GetNodeId(edge->to()));
2281 }
2282
2283
2284 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
2285 writer_->AddCharacter('\n');
2286 writer_->AddCharacter(',');
2287 writer_->AddNumber(entry->type());
2288 writer_->AddCharacter(',');
2289 writer_->AddNumber(GetStringId(entry->name()));
2290 writer_->AddCharacter(',');
2291 writer_->AddNumber(entry->id());
2292 writer_->AddCharacter(',');
2293 writer_->AddNumber(entry->self_size());
2294 Vector<HeapGraphEdge> children = entry->children();
2295 writer_->AddCharacter(',');
2296 writer_->AddNumber(children.length());
2297 for (int i = 0; i < children.length(); ++i) {
2298 SerializeEdge(&children[i]);
2299 }
2300 }
2301
2302
2303 void HeapSnapshotJSONSerializer::SerializeNodes() {
2304 // The first (zero) item of nodes array is a JSON-ified object
2305 // describing node serialization layout.
2306 // We use a set of macros to improve readability.
2307 #define JSON_A(s) "["s"]"
2308 #define JSON_O(s) "{"s"}"
2309 #define JSON_S(s) "\\\""s"\\\""
2310 writer_->AddString("\"" JSON_O(
2311 JSON_S("fields") ":" JSON_A(
2312 JSON_S("type")
2313 "," JSON_S("name")
2314 "," JSON_S("id")
2315 "," JSON_S("self_size")
2316 "," JSON_S("children_count")
2317 "," JSON_S("children"))
2318 "," JSON_S("types") ":" JSON_A(
2319 JSON_A(
2320 JSON_S("internal")
2321 "," JSON_S("array")
2322 "," JSON_S("string")
2323 "," JSON_S("object")
2324 "," JSON_S("code")
2325 "," JSON_S("closure"))
2326 "," JSON_S("string")
2327 "," JSON_S("number")
2328 "," JSON_S("number")
2329 "," JSON_S("number")
2330 "," JSON_O(
2331 JSON_S("fields") ":" JSON_A(
2332 JSON_S("type")
2333 "," JSON_S("name_or_index")
2334 "," JSON_S("to_node"))
2335 "," JSON_S("types") ":" JSON_A(
2336 JSON_A(
2337 JSON_S("context")
2338 "," JSON_S("element")
2339 "," JSON_S("property")
2340 "," JSON_S("internal"))
2341 "," JSON_S("string_or_number")
2342 "," JSON_S("node"))))) "\"");
2343 #undef JSON_S
2344 #undef JSON_O
2345 #undef JSON_A
2346
2347 const int node_fields_count = 5; // type,name,id,self_size,children_count.
2348 const int edge_fields_count = 3; // type,name|index,to_node.
2349 List<HashMap::Entry*> sorted_nodes;
2350 SortHashMap(&nodes_, &sorted_nodes);
2351 // Rewrite node ids, so they refer to actual array positions.
2352 if (sorted_nodes.length() > 1) {
2353 // Nodes start from array index 1.
2354 int prev_value = 1;
2355 sorted_nodes[0]->value = reinterpret_cast<void*>(prev_value);
2356 for (int i = 1; i < sorted_nodes.length(); ++i) {
2357 HeapEntry* prev_heap_entry =
2358 reinterpret_cast<HeapEntry*>(sorted_nodes[i-1]->key);
2359 prev_value += node_fields_count +
2360 prev_heap_entry->children().length() * edge_fields_count;
2361 sorted_nodes[i]->value = reinterpret_cast<void*>(prev_value);
2362 }
2363 }
2364 for (int i = 0; i < sorted_nodes.length(); ++i) {
2365 SerializeNode(reinterpret_cast<HeapEntry*>(sorted_nodes[i]->key));
2366 }
2367 }
2368
2369
2370 void HeapSnapshotJSONSerializer::SerializeSnapshot() {
2371 writer_->AddString("\"title\":\"");
2372 writer_->AddString(snapshot_->title());
2373 writer_->AddString("\"");
2374 writer_->AddString(",\"uid\":");
2375 writer_->AddNumber(snapshot_->uid());
2376 }
2377
2378
2379 static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) {
2380 static const char hex_chars[] = "0123456789ABCDEF";
2381 w->AddString("\\u");
2382 w->AddCharacter(hex_chars[(u >> 12) & 0xf]);
2383 w->AddCharacter(hex_chars[(u >> 8) & 0xf]);
2384 w->AddCharacter(hex_chars[(u >> 4) & 0xf]);
2385 w->AddCharacter(hex_chars[u & 0xf]);
2386 }
2387
2388 void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
2389 writer_->AddCharacter('\n');
2390 writer_->AddCharacter('\"');
2391 for ( ; *s != '\0'; ++s) {
2392 switch (*s) {
2393 case '\b':
2394 writer_->AddString("\\b");
2395 continue;
2396 case '\f':
2397 writer_->AddString("\\f");
2398 continue;
2399 case '\n':
2400 writer_->AddString("\\n");
2401 continue;
2402 case '\r':
2403 writer_->AddString("\\r");
2404 continue;
2405 case '\t':
2406 writer_->AddString("\\t");
2407 continue;
2408 case '\"':
2409 case '\\':
2410 writer_->AddCharacter('\\');
2411 writer_->AddCharacter(*s);
2412 continue;
2413 default:
2414 if (*s > 31 && *s < 128) {
2415 writer_->AddCharacter(*s);
2416 } else if (*s <= 31) {
2417 // Special character with no dedicated literal.
2418 WriteUChar(writer_, *s);
2419 } else {
2420 // Convert UTF-8 into \u UTF-16 literal.
2421 unsigned length = 1, cursor = 0;
2422 for ( ; length <= 4 && *(s + length) != '\0'; ++length) { }
2423 unibrow::uchar c = unibrow::Utf8::CalculateValue(s, length, &cursor);
2424 if (c != unibrow::Utf8::kBadChar) {
2425 WriteUChar(writer_, c);
2426 ASSERT(cursor != 0);
2427 s += cursor - 1;
2428 } else {
2429 writer_->AddCharacter('?');
2430 }
2431 }
2432 }
2433 }
2434 writer_->AddCharacter('\"');
2435 }
2436
2437
2438 void HeapSnapshotJSONSerializer::SerializeStrings() {
2439 List<HashMap::Entry*> sorted_strings;
2440 SortHashMap(&strings_, &sorted_strings);
2441 writer_->AddString("\"<dummy>\"");
2442 for (int i = 0; i < sorted_strings.length(); ++i) {
2443 writer_->AddCharacter(',');
2444 SerializeString(
2445 reinterpret_cast<const unsigned char*>(sorted_strings[i]->key));
2446 }
2447 }
2448
2449
2450 template<typename T>
2451 inline static int SortUsingEntryValue(const T* x, const T* y) {
2452 return reinterpret_cast<intptr_t>((*x)->value) -
2453 reinterpret_cast<intptr_t>((*y)->value);
2454 }
2455
2456 void HeapSnapshotJSONSerializer::SortHashMap(
2457 HashMap* map, List<HashMap::Entry*>* sorted_entries) {
2458 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p))
2459 sorted_entries->Add(p);
2460 sorted_entries->Sort(SortUsingEntryValue);
2461 }
2462
2135 } } // namespace v8::internal 2463 } } // namespace v8::internal
2136 2464
2137 #endif // ENABLE_LOGGING_AND_PROFILING 2465 #endif // ENABLE_LOGGING_AND_PROFILING
OLDNEW
« no previous file with comments | « src/profile-generator.h ('k') | src/unicode.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698