Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Tests of logging functions from log.h | 3 // Tests of logging functions from log.h |
| 4 | 4 |
| 5 #ifdef ENABLE_LOGGING_AND_PROFILING | 5 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 6 | 6 |
| 7 #include "v8.h" | 7 #include "v8.h" |
| 8 | 8 |
| 9 #include "log.h" | 9 #include "log.h" |
| 10 #include "cctest.h" | 10 #include "cctest.h" |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 | 123 |
| 124 static bool Consume(const char* str, char** buf) { | 124 static bool Consume(const char* str, char** buf) { |
| 125 if (IsStringEqualTo(str, *buf)) { | 125 if (IsStringEqualTo(str, *buf)) { |
| 126 *buf += strlen(str); | 126 *buf += strlen(str); |
| 127 return true; | 127 return true; |
| 128 } | 128 } |
| 129 return false; | 129 return false; |
| 130 } | 130 } |
| 131 | 131 |
| 132 | 132 |
| 133 static void ParseAddress(char* start, Address* min_addr, Address* max_addr) { | |
| 134 Address addr = reinterpret_cast<Address>(strtoul(start, NULL, 16)); // NOLINT | |
| 135 if (addr < *min_addr) *min_addr = addr; | |
| 136 if (addr > *max_addr) *max_addr = addr; | |
| 137 } | |
| 138 | |
| 139 | |
| 140 static Address ConsumeAddress( | |
| 141 char** start, Address min_addr, Address max_addr) { | |
| 142 char* end_ptr; | |
| 143 Address addr = | |
| 144 reinterpret_cast<Address>(strtoul(*start, &end_ptr, 16)); // NOLINT | |
| 145 CHECK_GE(addr, min_addr); | |
| 146 CHECK_GE(max_addr, addr); | |
| 147 *start = end_ptr; | |
| 148 return addr; | |
| 149 } | |
| 150 | |
| 151 | |
| 152 namespace { | 133 namespace { |
| 153 | 134 |
| 154 // A code entity is a pointer to a position of code-creation event in buffer log | 135 // A code entity is a pointer to a position of code-creation event in buffer log |
| 155 // offset to a point where entity size begins, i.e.: '255,"func"\n'. This makes | 136 // offset to a point where entity size begins, i.e.: '255,"func"\n'. This makes |
| 156 // comparing code entities pretty easy. | 137 // comparing code entities pretty easy. |
| 157 typedef char* CodeEntityInfo; | 138 typedef char* CodeEntityInfo; |
| 158 | 139 |
| 140 class Interval { | |
| 141 public: | |
| 142 Interval() | |
| 143 : min_addr(reinterpret_cast<Address>(-1)), | |
| 144 max_addr(reinterpret_cast<Address>(0)), next(NULL) {} | |
| 145 | |
| 146 ~Interval() { delete next; } | |
| 147 | |
| 148 size_t Length() { | |
| 149 size_t result = max_addr - min_addr + 1; | |
| 150 if (next != NULL) result += next->Length(); | |
| 151 return result; | |
| 152 } | |
| 153 | |
| 154 void CloneFrom(Interval* src) { | |
| 155 while (src != NULL) { | |
| 156 RegisterAddress(src->min_addr); | |
| 157 RegisterAddress(src->max_addr); | |
| 158 src = src->next; | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 bool Contains(Address addr) { | |
| 163 if (min_addr <= addr && addr <= max_addr) { | |
| 164 return true; | |
| 165 } | |
| 166 if (next != NULL) return next->Contains(addr); | |
|
Søren Thygesen Gjesse
2009/05/25 08:45:53
Please add {}'s for one statement if. Maybe use an
Mikhail Naganov
2009/05/25 09:32:10
Usually, there is no 'next' at all. 'next' appears
| |
| 167 return false; | |
| 168 } | |
| 169 | |
| 170 size_t GetIndex(Address addr) { | |
| 171 if (min_addr <= addr && addr <= max_addr) { | |
| 172 return addr - min_addr; | |
| 173 } | |
| 174 CHECK_NE(NULL, next); | |
| 175 return (max_addr - min_addr + 1) + next->GetIndex(addr); | |
| 176 } | |
| 177 | |
| 178 Address GetMinAddr() { | |
| 179 return next == NULL ? min_addr : i::Min(min_addr, next->GetMinAddr()); | |
| 180 } | |
| 181 | |
| 182 Address GetMaxAddr() { | |
| 183 return next == NULL ? max_addr : i::Max(max_addr, next->GetMaxAddr()); | |
| 184 } | |
| 185 | |
| 186 void RegisterAddress(Address addr) { | |
| 187 if (min_addr == reinterpret_cast<Address>(-1) | |
| 188 || (size_t)(addr > min_addr ? | |
| 189 addr - min_addr : min_addr - addr) < MAX_DELTA) { | |
| 190 if (addr < min_addr) min_addr = addr; | |
| 191 if (addr > max_addr) max_addr = addr; | |
| 192 } else { | |
| 193 if (next == NULL) next = new Interval(); | |
| 194 next->RegisterAddress(addr); | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 Address raw_min_addr() { return min_addr; } | |
| 199 | |
| 200 Address raw_max_addr() { return max_addr; } | |
| 201 | |
| 202 Interval* get_next() { return next; } | |
| 203 | |
| 204 private: | |
| 205 static const size_t MAX_DELTA = 0x100000; | |
| 206 Address min_addr; | |
|
Søren Thygesen Gjesse
2009/05/25 08:45:53
Missing trailing underscores?
Mikhail Naganov
2009/05/25 09:32:10
Done.
| |
| 207 Address max_addr; | |
| 208 Interval* next; | |
| 209 }; | |
| 210 | |
| 211 | |
| 159 // A structure used to return log parsing results. | 212 // A structure used to return log parsing results. |
| 160 class ParseLogResult { | 213 class ParseLogResult { |
| 161 public: | 214 public: |
| 162 ParseLogResult() | 215 ParseLogResult() |
| 163 : min_addr(reinterpret_cast<Address>(-1)), | 216 : entities_map(NULL), entities(NULL), |
| 164 max_addr(reinterpret_cast<Address>(0)), | |
| 165 entities_map(NULL), entities(NULL), | |
| 166 max_entities(0) {} | 217 max_entities(0) {} |
| 167 | 218 |
| 168 ~ParseLogResult() { | 219 ~ParseLogResult() { |
| 169 // See allocation code below. | 220 i::DeleteArray(entities_map); |
| 170 if (entities_map != NULL) { | |
| 171 i::DeleteArray(entities_map - 1); | |
| 172 } | |
| 173 i::DeleteArray(entities); | 221 i::DeleteArray(entities); |
| 174 } | 222 } |
| 175 | 223 |
| 176 void AllocateEntities() { | 224 void AllocateEntities() { |
| 177 // Make sure that the test doesn't operate on a bogus log. | 225 // Make sure that the test doesn't operate on a bogus log. |
| 178 CHECK_GT(max_entities, 0); | 226 CHECK_GT(max_entities, 0); |
| 179 CHECK_GT(min_addr, 0); | 227 CHECK_GT(bounds.GetMinAddr(), 0); |
| 180 CHECK_GT(max_addr, min_addr); | 228 CHECK_GT(bounds.GetMaxAddr(), bounds.GetMinAddr()); |
| 181 | 229 |
| 182 entities = i::NewArray<CodeEntityInfo>(max_entities); | 230 entities = i::NewArray<CodeEntityInfo>(max_entities); |
| 183 for (int i = 0; i < max_entities; ++i) { | 231 for (int i = 0; i < max_entities; ++i) { |
| 184 entities[i] = NULL; | 232 entities[i] = NULL; |
| 185 } | 233 } |
| 186 // We're adding fake items at [-1] and [size + 1] to simplify | 234 const size_t map_length = bounds.Length(); |
| 187 // comparison code. | |
| 188 const int map_length = max_addr - min_addr + 1 + 2; // 2 fakes. | |
| 189 entities_map = i::NewArray<int>(map_length); | 235 entities_map = i::NewArray<int>(map_length); |
| 190 for (int i = 0; i < map_length; ++i) { | 236 for (size_t i = 0; i < map_length; ++i) { |
| 191 entities_map[i] = -1; | 237 entities_map[i] = -1; |
| 192 } | 238 } |
| 193 entities_map += 1; // Hide the -1 item, this is compensated on delete. | |
| 194 } | 239 } |
| 195 | 240 |
| 196 // Minimal code entity address. | 241 bool HasIndexForAddress(Address addr) { |
| 197 Address min_addr; | 242 return bounds.Contains(addr); |
| 198 // Maximal code entity address. | 243 } |
| 199 Address max_addr; | 244 |
| 200 // Memory map of entities start addresses. Biased by min_addr. | 245 size_t GetIndexForAddress(Address addr) { |
| 246 CHECK(HasIndexForAddress(addr)); | |
| 247 return bounds.GetIndex(addr); | |
| 248 } | |
| 249 | |
| 250 CodeEntityInfo GetEntity(Address addr) { | |
| 251 if (HasIndexForAddress(addr)) { | |
| 252 size_t idx = GetIndexForAddress(addr); | |
| 253 int item = entities_map[idx]; | |
| 254 return item != -1 ? entities[item] : NULL; | |
| 255 } | |
| 256 return NULL; | |
| 257 } | |
| 258 | |
| 259 void ParseAddress(char* start) { | |
| 260 Address addr = | |
| 261 reinterpret_cast<Address>(strtoul(start, NULL, 16)); // NOLINT | |
| 262 bounds.RegisterAddress(addr); | |
| 263 } | |
| 264 | |
| 265 Address ConsumeAddress(char** start) { | |
| 266 char* end_ptr; | |
| 267 Address addr = | |
| 268 reinterpret_cast<Address>(strtoul(*start, &end_ptr, 16)); // NOLINT | |
| 269 CHECK(HasIndexForAddress(addr)); | |
| 270 *start = end_ptr; | |
| 271 return addr; | |
| 272 } | |
| 273 | |
| 274 Interval bounds; | |
|
Søren Thygesen Gjesse
2009/05/25 08:45:53
Missing trailing underscores?
Mikhail Naganov
2009/05/25 09:32:10
Um, actually encapsulation is sort of leaking here
| |
| 275 // Memory map of entities start addresses. Biased by bounds.min_addr. | |
| 201 int* entities_map; | 276 int* entities_map; |
| 202 // An array of code entities. | 277 // An array of code entities. |
| 203 CodeEntityInfo* entities; | 278 CodeEntityInfo* entities; |
| 204 // Maximal entities count. Actual entities count can be lower, | 279 // Maximal entities count. Actual entities count can be lower, |
| 205 // empty entity slots are pointing to NULL. | 280 // empty entity slots are pointing to NULL. |
| 206 int max_entities; | 281 int max_entities; |
| 207 }; | 282 }; |
| 208 | 283 |
| 209 } // namespace | 284 } // namespace |
| 210 | 285 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 236 } else if (Consume(code_move, &start)) { | 311 } else if (Consume(code_move, &start)) { |
| 237 block_move(start, end, result); | 312 block_move(start, end, result); |
| 238 } | 313 } |
| 239 while (start < end && *start != '\n') ++start; | 314 while (start < end && *start != '\n') ++start; |
| 240 ++start; | 315 ++start; |
| 241 } | 316 } |
| 242 } | 317 } |
| 243 | 318 |
| 244 | 319 |
| 245 static void Pass1CodeCreation(char* start, char* end, ParseLogResult* result) { | 320 static void Pass1CodeCreation(char* start, char* end, ParseLogResult* result) { |
| 246 ParseAddress(start, &result->min_addr, &result->max_addr); | 321 result->ParseAddress(start); |
| 247 ++result->max_entities; | 322 ++result->max_entities; |
| 248 } | 323 } |
| 249 | 324 |
| 250 | 325 |
| 251 static void Pass1CodeDelete(char* start, char* end, ParseLogResult* result) { | 326 static void Pass1CodeDelete(char* start, char* end, ParseLogResult* result) { |
| 252 ParseAddress(start, &result->min_addr, &result->max_addr); | 327 result->ParseAddress(start); |
| 253 } | 328 } |
| 254 | 329 |
| 255 | 330 |
| 256 static void Pass1CodeMove(char* start, char* end, ParseLogResult* result) { | 331 static void Pass1CodeMove(char* start, char* end, ParseLogResult* result) { |
| 332 result->ParseAddress(start); | |
| 257 // Skip old address. | 333 // Skip old address. |
| 258 while (start < end && *start != ',') ++start; | 334 while (start < end && *start != ',') ++start; |
| 259 CHECK_GT(end, start); | 335 CHECK_GT(end, start); |
| 260 ++start; // Skip ','. | 336 ++start; // Skip ','. |
| 261 ParseAddress(start, &result->min_addr, &result->max_addr); | 337 result->ParseAddress(start); |
| 262 } | 338 } |
| 263 | 339 |
| 264 | 340 |
| 265 static void Pass2CodeCreation(char* start, char* end, ParseLogResult* result) { | 341 static void Pass2CodeCreation(char* start, char* end, ParseLogResult* result) { |
| 266 Address addr = ConsumeAddress(&start, result->min_addr, result->max_addr); | 342 Address addr = result->ConsumeAddress(&start); |
| 267 CHECK_GT(end, start); | 343 CHECK_GT(end, start); |
| 268 ++start; // Skip ','. | 344 ++start; // Skip ','. |
| 269 | 345 |
| 270 int idx = addr - result->min_addr; | 346 size_t idx = result->GetIndexForAddress(addr); |
| 271 result->entities_map[idx] = -1; | 347 result->entities_map[idx] = -1; |
| 272 for (int i = 0; i < result->max_entities; ++i) { | 348 for (int i = 0; i < result->max_entities; ++i) { |
| 273 // Find an empty slot and fill it. | 349 // Find an empty slot and fill it. |
| 274 if (result->entities[i] == NULL) { | 350 if (result->entities[i] == NULL) { |
| 275 result->entities[i] = start; | 351 result->entities[i] = start; |
| 276 result->entities_map[idx] = i; | 352 result->entities_map[idx] = i; |
| 277 break; | 353 break; |
| 278 } | 354 } |
| 279 } | 355 } |
| 280 // Make sure that a slot was found. | 356 // Make sure that a slot was found. |
| 281 CHECK_GE(result->entities_map[idx], 0); | 357 CHECK_GE(result->entities_map[idx], 0); |
| 282 } | 358 } |
| 283 | 359 |
| 284 | 360 |
| 285 static void Pass2CodeDelete(char* start, char* end, ParseLogResult* result) { | 361 static void Pass2CodeDelete(char* start, char* end, ParseLogResult* result) { |
| 286 Address addr = ConsumeAddress(&start, result->min_addr, result->max_addr); | 362 Address addr = result->ConsumeAddress(&start); |
| 287 int idx = addr - result->min_addr; | 363 size_t idx = result->GetIndexForAddress(addr); |
| 288 // There can be code deletes that are not related to JS code. | 364 // There can be code deletes that are not related to JS code. |
| 289 if (result->entities_map[idx] >= 0) { | 365 if (result->entities_map[idx] >= 0) { |
| 290 result->entities[result->entities_map[idx]] = NULL; | 366 result->entities[result->entities_map[idx]] = NULL; |
| 291 result->entities_map[idx] = -1; | 367 result->entities_map[idx] = -1; |
| 292 } | 368 } |
| 293 } | 369 } |
| 294 | 370 |
| 295 | 371 |
| 296 static void Pass2CodeMove(char* start, char* end, ParseLogResult* result) { | 372 static void Pass2CodeMove(char* start, char* end, ParseLogResult* result) { |
| 297 Address from_addr = ConsumeAddress( | 373 Address from_addr = result->ConsumeAddress(&start); |
| 298 &start, result->min_addr, result->max_addr); | |
| 299 CHECK_GT(end, start); | 374 CHECK_GT(end, start); |
| 300 ++start; // Skip ','. | 375 ++start; // Skip ','. |
| 301 Address to_addr = ConsumeAddress(&start, result->min_addr, result->max_addr); | 376 Address to_addr = result->ConsumeAddress(&start); |
| 302 CHECK_GT(end, start); | 377 CHECK_GT(end, start); |
| 303 | 378 |
| 304 int from_idx = from_addr - result->min_addr; | 379 size_t from_idx = result->GetIndexForAddress(from_addr); |
| 305 int to_idx = to_addr - result->min_addr; | 380 size_t to_idx = result->GetIndexForAddress(to_addr); |
| 306 // There can be code moves that are not related to JS code. | 381 // There can be code moves that are not related to JS code. |
| 307 if (from_idx != to_idx && result->entities_map[from_idx] >= 0) { | 382 if (from_idx != to_idx && result->entities_map[from_idx] >= 0) { |
| 308 CHECK_EQ(-1, result->entities_map[to_idx]); | 383 CHECK_EQ(-1, result->entities_map[to_idx]); |
| 309 result->entities_map[to_idx] = result->entities_map[from_idx]; | 384 result->entities_map[to_idx] = result->entities_map[from_idx]; |
| 310 result->entities_map[from_idx] = -1; | 385 result->entities_map[from_idx] = -1; |
| 311 }; | 386 }; |
| 312 } | 387 } |
| 313 | 388 |
| 314 | 389 |
| 315 static void ParseLog(char* start, char* end, ParseLogResult* result) { | 390 static void ParseLog(char* start, char* end, ParseLogResult* result) { |
| 316 // Pass 1: Calculate boundaries of addresses and entities count. | 391 // Pass 1: Calculate boundaries of addresses and entities count. |
| 317 ParserCycle(start, end, result, | 392 ParserCycle(start, end, result, |
| 318 Pass1CodeCreation, Pass1CodeDelete, Pass1CodeMove); | 393 Pass1CodeCreation, Pass1CodeDelete, Pass1CodeMove); |
| 319 | 394 |
| 320 printf("min_addr: %p, max_addr: %p, entities: %d\n", | 395 printf("min_addr: %p, max_addr: %p, entities: %d\n", |
| 321 result->min_addr, result->max_addr, result->max_entities); | 396 result->bounds.GetMinAddr(), result->bounds.GetMaxAddr(), |
| 397 result->max_entities); | |
| 322 | 398 |
| 323 result->AllocateEntities(); | 399 result->AllocateEntities(); |
| 324 | 400 |
| 325 // Pass 2: Fill in code entries data. | 401 // Pass 2: Fill in code entries data. |
| 326 ParserCycle(start, end, result, | 402 ParserCycle(start, end, result, |
| 327 Pass2CodeCreation, Pass2CodeDelete, Pass2CodeMove); | 403 Pass2CodeCreation, Pass2CodeDelete, Pass2CodeMove); |
| 328 } | 404 } |
| 329 | 405 |
| 330 | 406 |
| 331 static inline void PrintCodeEntityInfo(CodeEntityInfo entity) { | 407 static inline void PrintCodeEntityInfo(CodeEntityInfo entity) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 459 const int new_log_size = Logger::GetLogLines( | 535 const int new_log_size = Logger::GetLogLines( |
| 460 log_size, new_log_start, buffer.length() - log_size); | 536 log_size, new_log_start, buffer.length() - log_size); |
| 461 CHECK_GT(new_log_size, 0); | 537 CHECK_GT(new_log_size, 0); |
| 462 CHECK_GT(buffer.length(), log_size + new_log_size); | 538 CHECK_GT(buffer.length(), log_size + new_log_size); |
| 463 | 539 |
| 464 // Fill an equivalent map of compiled code objects. | 540 // Fill an equivalent map of compiled code objects. |
| 465 ParseLogResult new_result; | 541 ParseLogResult new_result; |
| 466 ParseLog(new_log_start, new_log_start + new_log_size, &new_result); | 542 ParseLog(new_log_start, new_log_start + new_log_size, &new_result); |
| 467 | 543 |
| 468 // Test their actual equivalence. | 544 // Test their actual equivalence. |
| 545 Interval combined; | |
| 546 combined.CloneFrom(&ref_result.bounds); | |
| 547 combined.CloneFrom(&new_result.bounds); | |
| 548 Interval* iter = &combined; | |
| 469 bool results_equal = true; | 549 bool results_equal = true; |
| 470 int ref_idx = -1, new_idx = -1, ref_inc = 1, new_inc = 1; | 550 |
| 471 while (ref_inc > 0 || new_inc > 0) { | 551 while (iter != NULL) { |
| 472 const Address ref_addr = ref_result.min_addr + ref_idx; | 552 for (Address addr = iter->raw_min_addr(); |
| 473 const Address new_addr = new_result.min_addr + new_idx; | 553 addr <= iter->raw_max_addr(); ++addr) { |
| 474 ref_inc = ref_addr <= ref_result.max_addr && ref_addr <= new_addr ? 1 : 0; | 554 CodeEntityInfo ref_entity = ref_result.GetEntity(addr); |
| 475 new_inc = new_addr <= new_result.max_addr && new_addr <= ref_addr ? 1 : 0; | 555 CodeEntityInfo new_entity = new_result.GetEntity(addr); |
| 476 const int ref_item = ref_result.entities_map[ref_idx]; | 556 if (ref_entity != NULL || new_entity != NULL) { |
| 477 const int new_item = new_result.entities_map[new_idx]; | 557 const bool equal = AreEntitiesEqual(ref_entity, new_entity); |
| 478 if (ref_item != -1 || new_item != -1) { | 558 if (!equal) results_equal = false; |
| 479 CodeEntityInfo ref_entity = | 559 PrintCodeEntitiesInfo(equal, addr, ref_entity, new_entity); |
| 480 ref_item != -1 ? ref_result.entities[ref_item] : NULL; | 560 } |
| 481 CodeEntityInfo new_entity = | |
| 482 new_item != -1 ? new_result.entities[new_item] : NULL; | |
| 483 const bool equal = AreEntitiesEqual(ref_entity, new_entity); | |
| 484 if (!equal) results_equal = false; | |
| 485 PrintCodeEntitiesInfo( | |
| 486 equal, ref_inc != 0 ? ref_addr : new_addr, | |
| 487 ref_entity, new_entity); | |
| 488 } | 561 } |
| 489 ref_idx += ref_inc; | 562 iter = iter->get_next(); |
| 490 new_idx += new_inc; | |
| 491 } | 563 } |
| 492 // Make sure that all log data is written prior crash due to CHECK failure. | 564 // Make sure that all log data is written prior crash due to CHECK failure. |
| 493 fflush(stdout); | 565 fflush(stdout); |
| 494 CHECK(results_equal); | 566 CHECK(results_equal); |
| 495 | 567 |
| 496 env->Exit(); | 568 env->Exit(); |
| 497 v8::V8::Dispose(); | 569 v8::V8::Dispose(); |
| 498 i::FLAG_always_compact = saved_always_compact; | 570 i::FLAG_always_compact = saved_always_compact; |
| 499 } | 571 } |
| 500 | 572 |
| 501 | 573 |
| 502 #endif // ENABLE_LOGGING_AND_PROFILING | 574 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |