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 7 namespace v8 { 8 namespace internal { 9 10 Counter::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 17 void Counter::Enable() { 18 enabled_ = true; 19 } 20 21 22 void Counter::Disable() { 23 enabled_ = false; 24 } 25 26 27 bool Counter::IsEnabled() { 28 return enabled_; 29 } 30 31 32 void Counter::Increment() { 33 if (enabled_) { 34 count_++; 35 } 36 } 37 38 39 uint64_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 49 const char* Counter::name() { 50 return name_; 51 } 52 53 54 CounterType Counter::type() { 55 return type_; 56 } 57 58 59 typedef struct { 60 const char* name; 61 CounterType type; 62 } CounterDescriptor; 63 64 65 static 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 97 Instrument::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 126 Instrument::~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 142 void 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 155 void 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 167 void 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 179 void 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 188 void 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 198 Counter* 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 217 void Instrument::Enable() { 218 std::list<Counter*>::iterator it; 219 for (it = counters_.begin(); it != counters_.end(); it++) { 220 (*it)->Enable(); 221 } 222 } 223 224 225 void Instrument::Disable() { 226 std::list<Counter*>::iterator it; 227 for (it = counters_.begin(); it != counters_.end(); it++) { 228 (*it)->Disable(); 229 } 230 } 231 232 233 void Instrument::VisitPCRelAddressing(Instruction* instr) { 234 Update(); 235 static Counter* counter = GetCounter("PC Addressing"); 236 counter->Increment(); 237 } 238 239 240 void 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 255 void Instrument::VisitLogicalImmediate(Instruction* instr) { 256 Update(); 257 static Counter* counter = GetCounter("Logical DP"); 258 counter->Increment(); 259 } 260 261 262 void 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 275 void Instrument::VisitBitfield(Instruction* instr) { 276 Update(); 277 static Counter* counter = GetCounter("Other Int DP"); 278 counter->Increment(); 279 } 280 281 282 void Instrument::VisitExtract(Instruction* instr) { 283 Update(); 284 static Counter* counter = GetCounter("Other Int DP"); 285 counter->Increment(); 286 } 287 288 289 void Instrument::VisitUnconditionalBranch(Instruction* instr) { 290 Update(); 291 static Counter* counter = GetCounter("Unconditional Branch"); 292 counter->Increment(); 293 } 294 295 296 void Instrument::VisitUnconditionalBranchToRegister(Instruction* instr) { 297 Update(); 298 static Counter* counter = GetCounter("Unconditional Branch"); 299 counter->Increment(); 300 } 301 302 303 void Instrument::VisitCompareBranch(Instruction* instr) { 304 Update(); 305 static Counter* counter = GetCounter("Compare and Branch"); 306 counter->Increment(); 307 } 308 309 310 void Instrument::VisitTestBranch(Instruction* instr) { 311 Update(); 312 static Counter* counter = GetCounter("Test and Branch"); 313 counter->Increment(); 314 } 315 316 317 void Instrument::VisitConditionalBranch(Instruction* instr) { 318 Update(); 319 static Counter* counter = GetCounter("Conditional Branch"); 320 counter->Increment(); 321 } 322 323 324 void Instrument::VisitSystem(Instruction* instr) { 325 Update(); 326 static Counter* counter = GetCounter("Other"); 327 counter->Increment(); 328 } 329 330 331 void Instrument::VisitException(Instruction* instr) { 332 Update(); 333 static Counter* counter = GetCounter("Other"); 334 counter->Increment(); 335 } 336 337 338 void 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 349 void Instrument::VisitLoadStorePairPostIndex(Instruction* instr) { 350 Update(); 351 InstrumentLoadStorePair(instr); 352 } 353 354 355 void Instrument::VisitLoadStorePairOffset(Instruction* instr) { 356 Update(); 357 InstrumentLoadStorePair(instr); 358 } 359 360 361 void Instrument::VisitLoadStorePairPreIndex(Instruction* instr) { 362 Update(); 363 InstrumentLoadStorePair(instr); 364 } 365 366 367 void Instrument::VisitLoadLiteral(Instruction* instr) { 368 Update(); 369 static Counter* counter = GetCounter("Load Literal"); 370 counter->Increment(); 371 } 372 373 374 void 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 403 void Instrument::VisitLoadStoreUnscaledOffset(Instruction* instr) { 404 Update(); 405 InstrumentLoadStore(instr); 406 } 407 408 409 void Instrument::VisitLoadStorePostIndex(Instruction* instr) { 410 Update(); 411 InstrumentLoadStore(instr); 412 } 413 414 415 void Instrument::VisitLoadStorePreIndex(Instruction* instr) { 416 Update(); 417 InstrumentLoadStore(instr); 418 } 419 420 421 void Instrument::VisitLoadStoreRegisterOffset(Instruction* instr) { 422 Update(); 423 InstrumentLoadStore(instr); 424 } 425 426 427 void Instrument::VisitLoadStoreUnsignedOffset(Instruction* instr) { 428 Update(); 429 InstrumentLoadStore(instr); 430 } 431 432 void 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 458 void Instrument::VisitLogicalShifted(Instruction* instr) { 459 Update(); 460 static Counter* counter = GetCounter("Logical DP"); 461 counter->Increment(); 462 } 463 464 465 void Instrument::VisitAddSubShifted(Instruction* instr) { 466 Update(); 467 static Counter* counter = GetCounter("Add/Sub DP"); 468 counter->Increment(); 469 } 470 471 472 void 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 487 void Instrument::VisitAddSubWithCarry(Instruction* instr) { 488 Update(); 489 static Counter* counter = GetCounter("Add/Sub DP"); 490 counter->Increment(); 491 } 492 493 494 void Instrument::VisitConditionalCompareRegister(Instruction* instr) { 495 Update(); 496 static Counter* counter = GetCounter("Conditional Compare"); 497 counter->Increment(); 498 } 499 500 501 void Instrument::VisitConditionalCompareImmediate(Instruction* instr) { 502 Update(); 503 static Counter* counter = GetCounter("Conditional Compare"); 504 counter->Increment(); 505 } 506 507 508 void Instrument::VisitConditionalSelect(Instruction* instr) { 509 Update(); 510 static Counter* counter = GetCounter("Conditional Select"); 511 counter->Increment(); 512 } 513 514 515 void Instrument::VisitDataProcessing1Source(Instruction* instr) { 516 Update(); 517 static Counter* counter = GetCounter("Other Int DP"); 518 counter->Increment(); 519 } 520 521 522 void Instrument::VisitDataProcessing2Source(Instruction* instr) { 523 Update(); 524 static Counter* counter = GetCounter("Other Int DP"); 525 counter->Increment(); 526 } 527 528 529 void Instrument::VisitDataProcessing3Source(Instruction* instr) { 530 Update(); 531 static Counter* counter = GetCounter("Other Int DP"); 532 counter->Increment(); 533 } 534 535 536 void Instrument::VisitFPCompare(Instruction* instr) { 537 Update(); 538 static Counter* counter = GetCounter("FP DP"); 539 counter->Increment(); 540 } 541 542 543 void Instrument::VisitFPConditionalCompare(Instruction* instr) { 544 Update(); 545 static Counter* counter = GetCounter("Conditional Compare"); 546 counter->Increment(); 547 } 548 549 550 void Instrument::VisitFPConditionalSelect(Instruction* instr) { 551 Update(); 552 static Counter* counter = GetCounter("Conditional Select"); 553 counter->Increment(); 554 } 555 556 557 void Instrument::VisitFPImmediate(Instruction* instr) { 558 Update(); 559 static Counter* counter = GetCounter("FP DP"); 560 counter->Increment(); 561 } 562 563 564 void Instrument::VisitFPDataProcessing1Source(Instruction* instr) { 565 Update(); 566 static Counter* counter = GetCounter("FP DP"); 567 counter->Increment(); 568 } 569 570 571 void Instrument::VisitFPDataProcessing2Source(Instruction* instr) { 572 Update(); 573 static Counter* counter = GetCounter("FP DP"); 574 counter->Increment(); 575 } 576 577 578 void Instrument::VisitFPDataProcessing3Source(Instruction* instr) { 579 Update(); 580 static Counter* counter = GetCounter("FP DP"); 581 counter->Increment(); 582 } 583 584 585 void Instrument::VisitFPIntegerConvert(Instruction* instr) { 586 Update(); 587 static Counter* counter = GetCounter("FP DP"); 588 counter->Increment(); 589 } 590 591 592 void Instrument::VisitFPFixedPointConvert(Instruction* instr) { 593 Update(); 594 static Counter* counter = GetCounter("FP DP"); 595 counter->Increment(); 596 } 597 598 599 void Instrument::VisitUnallocated(Instruction* instr) { 600 Update(); 601 static Counter* counter = GetCounter("Other"); 602 counter->Increment(); 603 } 604 605 606 void 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