OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 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. |
| 27 |
| 28 #include "a64/instrument-a64.h" |
| 29 |
| 30 namespace v8 { |
| 31 namespace internal { |
| 32 |
| 33 Counter::Counter(const char* name, CounterType type) |
| 34 : count_(0), enabled_(false), type_(type) { |
| 35 ASSERT(name != NULL); |
| 36 strncpy(name_, name, kCounterNameMaxLength); |
| 37 } |
| 38 |
| 39 |
| 40 void Counter::Enable() { |
| 41 enabled_ = true; |
| 42 } |
| 43 |
| 44 |
| 45 void Counter::Disable() { |
| 46 enabled_ = false; |
| 47 } |
| 48 |
| 49 |
| 50 bool Counter::IsEnabled() { |
| 51 return enabled_; |
| 52 } |
| 53 |
| 54 |
| 55 void Counter::Increment() { |
| 56 if (enabled_) { |
| 57 count_++; |
| 58 } |
| 59 } |
| 60 |
| 61 |
| 62 uint64_t Counter::count() { |
| 63 uint64_t result = count_; |
| 64 if (type_ == Gauge) { |
| 65 // If the counter is a Gauge, reset the count after reading. |
| 66 count_ = 0; |
| 67 } |
| 68 return result; |
| 69 } |
| 70 |
| 71 |
| 72 const char* Counter::name() { |
| 73 return name_; |
| 74 } |
| 75 |
| 76 |
| 77 CounterType Counter::type() { |
| 78 return type_; |
| 79 } |
| 80 |
| 81 |
| 82 typedef struct { |
| 83 const char* name; |
| 84 CounterType type; |
| 85 } CounterDescriptor; |
| 86 |
| 87 |
| 88 static const CounterDescriptor kCounterList[] = { |
| 89 {"Instruction", Cumulative}, |
| 90 |
| 91 {"Move Immediate", Gauge}, |
| 92 {"Add/Sub DP", Gauge}, |
| 93 {"Logical DP", Gauge}, |
| 94 {"Other Int DP", Gauge}, |
| 95 {"FP DP", Gauge}, |
| 96 |
| 97 {"Conditional Select", Gauge}, |
| 98 {"Conditional Compare", Gauge}, |
| 99 |
| 100 {"Unconditional Branch", Gauge}, |
| 101 {"Compare and Branch", Gauge}, |
| 102 {"Test and Branch", Gauge}, |
| 103 {"Conditional Branch", Gauge}, |
| 104 |
| 105 {"Load Integer", Gauge}, |
| 106 {"Load FP", Gauge}, |
| 107 {"Load Pair", Gauge}, |
| 108 {"Load Literal", Gauge}, |
| 109 |
| 110 {"Store Integer", Gauge}, |
| 111 {"Store FP", Gauge}, |
| 112 {"Store Pair", Gauge}, |
| 113 |
| 114 {"PC Addressing", Gauge}, |
| 115 {"Other", Gauge}, |
| 116 {"SP Adjust", Gauge}, |
| 117 }; |
| 118 |
| 119 |
| 120 Instrument::Instrument(const char* datafile, uint64_t sample_period) |
| 121 : output_stream_(stderr), sample_period_(sample_period) { |
| 122 |
| 123 // Set up the output stream. If datafile is non-NULL, use that file. If it |
| 124 // can't be opened, or datafile is NULL, use stderr. |
| 125 if (datafile != NULL) { |
| 126 output_stream_ = fopen(datafile, "w"); |
| 127 if (output_stream_ == NULL) { |
| 128 fprintf(stderr, "Can't open output file %s. Using stderr.\n", datafile); |
| 129 output_stream_ = stderr; |
| 130 } |
| 131 } |
| 132 |
| 133 static const int num_counters = |
| 134 sizeof(kCounterList) / sizeof(CounterDescriptor); |
| 135 |
| 136 // Dump an instrumentation description comment at the top of the file. |
| 137 fprintf(output_stream_, "# counters=%d\n", num_counters); |
| 138 fprintf(output_stream_, "# sample_period=%" PRIu64 "\n", sample_period_); |
| 139 |
| 140 // Construct Counter objects from counter description array. |
| 141 for (int i = 0; i < num_counters; i++) { |
| 142 Counter* counter = new Counter(kCounterList[i].name, kCounterList[i].type); |
| 143 counters_.push_back(counter); |
| 144 } |
| 145 |
| 146 DumpCounterNames(); |
| 147 } |
| 148 |
| 149 |
| 150 Instrument::~Instrument() { |
| 151 // Dump any remaining instruction data to the output file. |
| 152 DumpCounters(); |
| 153 |
| 154 // Free all the counter objects. |
| 155 std::list<Counter*>::iterator it; |
| 156 for (it = counters_.begin(); it != counters_.end(); it++) { |
| 157 delete *it; |
| 158 } |
| 159 |
| 160 if (output_stream_ != stderr) { |
| 161 fclose(output_stream_); |
| 162 } |
| 163 } |
| 164 |
| 165 |
| 166 void Instrument::Update() { |
| 167 // Increment the instruction counter, and dump all counters if a sample period |
| 168 // has elapsed. |
| 169 static Counter* counter = GetCounter("Instruction"); |
| 170 ASSERT(counter->type() == Cumulative); |
| 171 counter->Increment(); |
| 172 |
| 173 if (counter->IsEnabled() && (counter->count() % sample_period_) == 0) { |
| 174 DumpCounters(); |
| 175 } |
| 176 } |
| 177 |
| 178 |
| 179 void Instrument::DumpCounters() { |
| 180 // Iterate through the counter objects, dumping their values to the output |
| 181 // stream. |
| 182 std::list<Counter*>::const_iterator it; |
| 183 for (it = counters_.begin(); it != counters_.end(); it++) { |
| 184 fprintf(output_stream_, "%" PRIu64 ",", (*it)->count()); |
| 185 } |
| 186 fprintf(output_stream_, "\n"); |
| 187 fflush(output_stream_); |
| 188 } |
| 189 |
| 190 |
| 191 void Instrument::DumpCounterNames() { |
| 192 // Iterate through the counter objects, dumping the counter names to the |
| 193 // output stream. |
| 194 std::list<Counter*>::const_iterator it; |
| 195 for (it = counters_.begin(); it != counters_.end(); it++) { |
| 196 fprintf(output_stream_, "%s,", (*it)->name()); |
| 197 } |
| 198 fprintf(output_stream_, "\n"); |
| 199 fflush(output_stream_); |
| 200 } |
| 201 |
| 202 |
| 203 void Instrument::HandleInstrumentationEvent(unsigned event) { |
| 204 switch (event) { |
| 205 case InstrumentStateEnable: Enable(); break; |
| 206 case InstrumentStateDisable: Disable(); break; |
| 207 default: DumpEventMarker(event); |
| 208 } |
| 209 } |
| 210 |
| 211 |
| 212 void Instrument::DumpEventMarker(unsigned marker) { |
| 213 // Dumpan event marker to the output stream as a specially formatted comment |
| 214 // line. |
| 215 static Counter* counter = GetCounter("Instruction"); |
| 216 |
| 217 fprintf(output_stream_, "# %c%c @ %" PRId64 "\n", marker & 0xff, |
| 218 (marker >> 8) & 0xff, counter->count()); |
| 219 } |
| 220 |
| 221 |
| 222 Counter* Instrument::GetCounter(const char* name) { |
| 223 // Get a Counter object by name from the counter list. |
| 224 std::list<Counter*>::const_iterator it; |
| 225 for (it = counters_.begin(); it != counters_.end(); it++) { |
| 226 if (strcmp((*it)->name(), name) == 0) { |
| 227 return *it; |
| 228 } |
| 229 } |
| 230 |
| 231 // A Counter by that name does not exist: print an error message to stderr |
| 232 // and the output file, and exit. |
| 233 static const char* error_message = |
| 234 "# Error: Unknown counter \"%s\". Exiting.\n"; |
| 235 fprintf(stderr, error_message, name); |
| 236 fprintf(output_stream_, error_message, name); |
| 237 exit(1); |
| 238 } |
| 239 |
| 240 |
| 241 void Instrument::Enable() { |
| 242 std::list<Counter*>::iterator it; |
| 243 for (it = counters_.begin(); it != counters_.end(); it++) { |
| 244 (*it)->Enable(); |
| 245 } |
| 246 } |
| 247 |
| 248 |
| 249 void Instrument::Disable() { |
| 250 std::list<Counter*>::iterator it; |
| 251 for (it = counters_.begin(); it != counters_.end(); it++) { |
| 252 (*it)->Disable(); |
| 253 } |
| 254 } |
| 255 |
| 256 |
| 257 void Instrument::VisitPCRelAddressing(Instruction* instr) { |
| 258 Update(); |
| 259 static Counter* counter = GetCounter("PC Addressing"); |
| 260 counter->Increment(); |
| 261 } |
| 262 |
| 263 |
| 264 void Instrument::VisitAddSubImmediate(Instruction* instr) { |
| 265 Update(); |
| 266 static Counter* sp_counter = GetCounter("SP Adjust"); |
| 267 static Counter* add_sub_counter = GetCounter("Add/Sub DP"); |
| 268 if (((instr->Mask(AddSubOpMask) == SUB) || |
| 269 (instr->Mask(AddSubOpMask) == ADD)) && |
| 270 (instr->Rd() == 31) && (instr->Rn() == 31)) { |
| 271 // Count adjustments to the C stack pointer caused by V8 needing two SPs. |
| 272 sp_counter->Increment(); |
| 273 } else { |
| 274 add_sub_counter->Increment(); |
| 275 } |
| 276 } |
| 277 |
| 278 |
| 279 void Instrument::VisitLogicalImmediate(Instruction* instr) { |
| 280 Update(); |
| 281 static Counter* counter = GetCounter("Logical DP"); |
| 282 counter->Increment(); |
| 283 } |
| 284 |
| 285 |
| 286 void Instrument::VisitMoveWideImmediate(Instruction* instr) { |
| 287 Update(); |
| 288 static Counter* counter = GetCounter("Move Immediate"); |
| 289 |
| 290 if (instr->IsMovn() && (instr->Rd() == kZeroRegCode)) { |
| 291 unsigned imm = instr->ImmMoveWide(); |
| 292 HandleInstrumentationEvent(imm); |
| 293 } else { |
| 294 counter->Increment(); |
| 295 } |
| 296 } |
| 297 |
| 298 |
| 299 void Instrument::VisitBitfield(Instruction* instr) { |
| 300 Update(); |
| 301 static Counter* counter = GetCounter("Other Int DP"); |
| 302 counter->Increment(); |
| 303 } |
| 304 |
| 305 |
| 306 void Instrument::VisitExtract(Instruction* instr) { |
| 307 Update(); |
| 308 static Counter* counter = GetCounter("Other Int DP"); |
| 309 counter->Increment(); |
| 310 } |
| 311 |
| 312 |
| 313 void Instrument::VisitUnconditionalBranch(Instruction* instr) { |
| 314 Update(); |
| 315 static Counter* counter = GetCounter("Unconditional Branch"); |
| 316 counter->Increment(); |
| 317 } |
| 318 |
| 319 |
| 320 void Instrument::VisitUnconditionalBranchToRegister(Instruction* instr) { |
| 321 Update(); |
| 322 static Counter* counter = GetCounter("Unconditional Branch"); |
| 323 counter->Increment(); |
| 324 } |
| 325 |
| 326 |
| 327 void Instrument::VisitCompareBranch(Instruction* instr) { |
| 328 Update(); |
| 329 static Counter* counter = GetCounter("Compare and Branch"); |
| 330 counter->Increment(); |
| 331 } |
| 332 |
| 333 |
| 334 void Instrument::VisitTestBranch(Instruction* instr) { |
| 335 Update(); |
| 336 static Counter* counter = GetCounter("Test and Branch"); |
| 337 counter->Increment(); |
| 338 } |
| 339 |
| 340 |
| 341 void Instrument::VisitConditionalBranch(Instruction* instr) { |
| 342 Update(); |
| 343 static Counter* counter = GetCounter("Conditional Branch"); |
| 344 counter->Increment(); |
| 345 } |
| 346 |
| 347 |
| 348 void Instrument::VisitSystem(Instruction* instr) { |
| 349 Update(); |
| 350 static Counter* counter = GetCounter("Other"); |
| 351 counter->Increment(); |
| 352 } |
| 353 |
| 354 |
| 355 void Instrument::VisitException(Instruction* instr) { |
| 356 Update(); |
| 357 static Counter* counter = GetCounter("Other"); |
| 358 counter->Increment(); |
| 359 } |
| 360 |
| 361 |
| 362 void Instrument::InstrumentLoadStorePair(Instruction* instr) { |
| 363 static Counter* load_pair_counter = GetCounter("Load Pair"); |
| 364 static Counter* store_pair_counter = GetCounter("Store Pair"); |
| 365 if (instr->Mask(LoadStorePairLBit) != 0) { |
| 366 load_pair_counter->Increment(); |
| 367 } else { |
| 368 store_pair_counter->Increment(); |
| 369 } |
| 370 } |
| 371 |
| 372 |
| 373 void Instrument::VisitLoadStorePairPostIndex(Instruction* instr) { |
| 374 Update(); |
| 375 InstrumentLoadStorePair(instr); |
| 376 } |
| 377 |
| 378 |
| 379 void Instrument::VisitLoadStorePairOffset(Instruction* instr) { |
| 380 Update(); |
| 381 InstrumentLoadStorePair(instr); |
| 382 } |
| 383 |
| 384 |
| 385 void Instrument::VisitLoadStorePairPreIndex(Instruction* instr) { |
| 386 Update(); |
| 387 InstrumentLoadStorePair(instr); |
| 388 } |
| 389 |
| 390 |
| 391 void Instrument::VisitLoadStorePairNonTemporal(Instruction* instr) { |
| 392 Update(); |
| 393 InstrumentLoadStorePair(instr); |
| 394 } |
| 395 |
| 396 |
| 397 void Instrument::VisitLoadLiteral(Instruction* instr) { |
| 398 Update(); |
| 399 static Counter* counter = GetCounter("Load Literal"); |
| 400 counter->Increment(); |
| 401 } |
| 402 |
| 403 |
| 404 void Instrument::InstrumentLoadStore(Instruction* instr) { |
| 405 static Counter* load_int_counter = GetCounter("Load Integer"); |
| 406 static Counter* store_int_counter = GetCounter("Store Integer"); |
| 407 static Counter* load_fp_counter = GetCounter("Load FP"); |
| 408 static Counter* store_fp_counter = GetCounter("Store FP"); |
| 409 |
| 410 switch (instr->Mask(LoadStoreOpMask)) { |
| 411 case STRB_w: // Fall through. |
| 412 case STRH_w: // Fall through. |
| 413 case STR_w: // Fall through. |
| 414 case STR_x: store_int_counter->Increment(); break; |
| 415 case STR_s: // Fall through. |
| 416 case STR_d: store_fp_counter->Increment(); break; |
| 417 case LDRB_w: // Fall through. |
| 418 case LDRH_w: // Fall through. |
| 419 case LDR_w: // Fall through. |
| 420 case LDR_x: // Fall through. |
| 421 case LDRSB_x: // Fall through. |
| 422 case LDRSH_x: // Fall through. |
| 423 case LDRSW_x: // Fall through. |
| 424 case LDRSB_w: // Fall through. |
| 425 case LDRSH_w: load_int_counter->Increment(); break; |
| 426 case LDR_s: // Fall through. |
| 427 case LDR_d: load_fp_counter->Increment(); break; |
| 428 default: UNREACHABLE(); |
| 429 } |
| 430 } |
| 431 |
| 432 |
| 433 void Instrument::VisitLoadStoreUnscaledOffset(Instruction* instr) { |
| 434 Update(); |
| 435 InstrumentLoadStore(instr); |
| 436 } |
| 437 |
| 438 |
| 439 void Instrument::VisitLoadStorePostIndex(Instruction* instr) { |
| 440 Update(); |
| 441 InstrumentLoadStore(instr); |
| 442 } |
| 443 |
| 444 |
| 445 void Instrument::VisitLoadStorePreIndex(Instruction* instr) { |
| 446 Update(); |
| 447 InstrumentLoadStore(instr); |
| 448 } |
| 449 |
| 450 |
| 451 void Instrument::VisitLoadStoreRegisterOffset(Instruction* instr) { |
| 452 Update(); |
| 453 InstrumentLoadStore(instr); |
| 454 } |
| 455 |
| 456 |
| 457 void Instrument::VisitLoadStoreUnsignedOffset(Instruction* instr) { |
| 458 Update(); |
| 459 InstrumentLoadStore(instr); |
| 460 } |
| 461 |
| 462 |
| 463 void Instrument::VisitLogicalShifted(Instruction* instr) { |
| 464 Update(); |
| 465 static Counter* counter = GetCounter("Logical DP"); |
| 466 counter->Increment(); |
| 467 } |
| 468 |
| 469 |
| 470 void Instrument::VisitAddSubShifted(Instruction* instr) { |
| 471 Update(); |
| 472 static Counter* counter = GetCounter("Add/Sub DP"); |
| 473 counter->Increment(); |
| 474 } |
| 475 |
| 476 |
| 477 void Instrument::VisitAddSubExtended(Instruction* instr) { |
| 478 Update(); |
| 479 static Counter* sp_counter = GetCounter("SP Adjust"); |
| 480 static Counter* add_sub_counter = GetCounter("Add/Sub DP"); |
| 481 if (((instr->Mask(AddSubOpMask) == SUB) || |
| 482 (instr->Mask(AddSubOpMask) == ADD)) && |
| 483 (instr->Rd() == 31) && (instr->Rn() == 31)) { |
| 484 // Count adjustments to the C stack pointer caused by V8 needing two SPs. |
| 485 sp_counter->Increment(); |
| 486 } else { |
| 487 add_sub_counter->Increment(); |
| 488 } |
| 489 } |
| 490 |
| 491 |
| 492 void Instrument::VisitAddSubWithCarry(Instruction* instr) { |
| 493 Update(); |
| 494 static Counter* counter = GetCounter("Add/Sub DP"); |
| 495 counter->Increment(); |
| 496 } |
| 497 |
| 498 |
| 499 void Instrument::VisitConditionalCompareRegister(Instruction* instr) { |
| 500 Update(); |
| 501 static Counter* counter = GetCounter("Conditional Compare"); |
| 502 counter->Increment(); |
| 503 } |
| 504 |
| 505 |
| 506 void Instrument::VisitConditionalCompareImmediate(Instruction* instr) { |
| 507 Update(); |
| 508 static Counter* counter = GetCounter("Conditional Compare"); |
| 509 counter->Increment(); |
| 510 } |
| 511 |
| 512 |
| 513 void Instrument::VisitConditionalSelect(Instruction* instr) { |
| 514 Update(); |
| 515 static Counter* counter = GetCounter("Conditional Select"); |
| 516 counter->Increment(); |
| 517 } |
| 518 |
| 519 |
| 520 void Instrument::VisitDataProcessing1Source(Instruction* instr) { |
| 521 Update(); |
| 522 static Counter* counter = GetCounter("Other Int DP"); |
| 523 counter->Increment(); |
| 524 } |
| 525 |
| 526 |
| 527 void Instrument::VisitDataProcessing2Source(Instruction* instr) { |
| 528 Update(); |
| 529 static Counter* counter = GetCounter("Other Int DP"); |
| 530 counter->Increment(); |
| 531 } |
| 532 |
| 533 |
| 534 void Instrument::VisitDataProcessing3Source(Instruction* instr) { |
| 535 Update(); |
| 536 static Counter* counter = GetCounter("Other Int DP"); |
| 537 counter->Increment(); |
| 538 } |
| 539 |
| 540 |
| 541 void Instrument::VisitFPCompare(Instruction* instr) { |
| 542 Update(); |
| 543 static Counter* counter = GetCounter("FP DP"); |
| 544 counter->Increment(); |
| 545 } |
| 546 |
| 547 |
| 548 void Instrument::VisitFPConditionalCompare(Instruction* instr) { |
| 549 Update(); |
| 550 static Counter* counter = GetCounter("Conditional Compare"); |
| 551 counter->Increment(); |
| 552 } |
| 553 |
| 554 |
| 555 void Instrument::VisitFPConditionalSelect(Instruction* instr) { |
| 556 Update(); |
| 557 static Counter* counter = GetCounter("Conditional Select"); |
| 558 counter->Increment(); |
| 559 } |
| 560 |
| 561 |
| 562 void Instrument::VisitFPImmediate(Instruction* instr) { |
| 563 Update(); |
| 564 static Counter* counter = GetCounter("FP DP"); |
| 565 counter->Increment(); |
| 566 } |
| 567 |
| 568 |
| 569 void Instrument::VisitFPDataProcessing1Source(Instruction* instr) { |
| 570 Update(); |
| 571 static Counter* counter = GetCounter("FP DP"); |
| 572 counter->Increment(); |
| 573 } |
| 574 |
| 575 |
| 576 void Instrument::VisitFPDataProcessing2Source(Instruction* instr) { |
| 577 Update(); |
| 578 static Counter* counter = GetCounter("FP DP"); |
| 579 counter->Increment(); |
| 580 } |
| 581 |
| 582 |
| 583 void Instrument::VisitFPDataProcessing3Source(Instruction* instr) { |
| 584 Update(); |
| 585 static Counter* counter = GetCounter("FP DP"); |
| 586 counter->Increment(); |
| 587 } |
| 588 |
| 589 |
| 590 void Instrument::VisitFPIntegerConvert(Instruction* instr) { |
| 591 Update(); |
| 592 static Counter* counter = GetCounter("FP DP"); |
| 593 counter->Increment(); |
| 594 } |
| 595 |
| 596 |
| 597 void Instrument::VisitFPFixedPointConvert(Instruction* instr) { |
| 598 Update(); |
| 599 static Counter* counter = GetCounter("FP DP"); |
| 600 counter->Increment(); |
| 601 } |
| 602 |
| 603 |
| 604 void Instrument::VisitUnallocated(Instruction* instr) { |
| 605 Update(); |
| 606 static Counter* counter = GetCounter("Other"); |
| 607 counter->Increment(); |
| 608 } |
| 609 |
| 610 |
| 611 void Instrument::VisitUnimplemented(Instruction* instr) { |
| 612 Update(); |
| 613 static Counter* counter = GetCounter("Other"); |
| 614 counter->Increment(); |
| 615 } |
| 616 |
| 617 |
| 618 } } // namespace v8::internal |
OLD | NEW |