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