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