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 |