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::VisitLoadStorePairNonTemporal(Instruction* instr) { 368 Update(); 369 InstrumentLoadStorePair(instr); 370 } 371 372 373 void Instrument::VisitLoadLiteral(Instruction* instr) { 374 Update(); 375 static Counter* counter = GetCounter("Load Literal"); 376 counter->Increment(); 377 } 378 379 380 void Instrument::InstrumentLoadStore(Instruction* instr) { 381 static Counter* load_int_counter = GetCounter("Load Integer"); 382 static Counter* store_int_counter = GetCounter("Store Integer"); 383 static Counter* load_fp_counter = GetCounter("Load FP"); 384 static Counter* store_fp_counter = GetCounter("Store FP"); 385 386 switch (instr->Mask(LoadStoreOpMask)) { 387 case STRB_w: // Fall through. 388 case STRH_w: // Fall through. 389 case STR_w: // Fall through. 390 case STR_x: store_int_counter->Increment(); break; 391 case STR_s: // Fall through. 392 case STR_d: store_fp_counter->Increment(); break; 393 case LDRB_w: // Fall through. 394 case LDRH_w: // Fall through. 395 case LDR_w: // Fall through. 396 case LDR_x: // Fall through. 397 case LDRSB_x: // Fall through. 398 case LDRSH_x: // Fall through. 399 case LDRSW_x: // Fall through. 400 case LDRSB_w: // Fall through. 401 case LDRSH_w: load_int_counter->Increment(); break; 402 case LDR_s: // Fall through. 403 case LDR_d: load_fp_counter->Increment(); break; 404 default: UNREACHABLE(); 405 } 406 } 407 408 409 void Instrument::VisitLoadStoreUnscaledOffset(Instruction* instr) { 410 Update(); 411 InstrumentLoadStore(instr); 412 } 413 414 415 void Instrument::VisitLoadStorePostIndex(Instruction* instr) { 416 Update(); 417 InstrumentLoadStore(instr); 418 } 419 420 421 void Instrument::VisitLoadStorePreIndex(Instruction* instr) { 422 Update(); 423 InstrumentLoadStore(instr); 424 } 425 426 427 void Instrument::VisitLoadStoreRegisterOffset(Instruction* instr) { 428 Update(); 429 InstrumentLoadStore(instr); 430 } 431 432 433 void Instrument::VisitLoadStoreUnsignedOffset(Instruction* instr) { 434 Update(); 435 InstrumentLoadStore(instr); 436 } 437 438 439 void Instrument::VisitLogicalShifted(Instruction* instr) { 440 Update(); 441 static Counter* counter = GetCounter("Logical DP"); 442 counter->Increment(); 443 } 444 445 446 void Instrument::VisitAddSubShifted(Instruction* instr) { 447 Update(); 448 static Counter* counter = GetCounter("Add/Sub DP"); 449 counter->Increment(); 450 } 451 452 453 void Instrument::VisitAddSubExtended(Instruction* instr) { 454 Update(); 455 static Counter* sp_counter = GetCounter("SP Adjust"); 456 static Counter* add_sub_counter = GetCounter("Add/Sub DP"); 457 if (((instr->Mask(AddSubOpMask) == SUB) || 458 (instr->Mask(AddSubOpMask) == ADD)) && 459 (instr->Rd() == 31) && (instr->Rn() == 31)) { 460 // Count adjustments to the C stack pointer caused by V8 needing two SPs. 461 sp_counter->Increment(); 462 } else { 463 add_sub_counter->Increment(); 464 } 465 } 466 467 468 void Instrument::VisitAddSubWithCarry(Instruction* instr) { 469 Update(); 470 static Counter* counter = GetCounter("Add/Sub DP"); 471 counter->Increment(); 472 } 473 474 475 void Instrument::VisitConditionalCompareRegister(Instruction* instr) { 476 Update(); 477 static Counter* counter = GetCounter("Conditional Compare"); 478 counter->Increment(); 479 } 480 481 482 void Instrument::VisitConditionalCompareImmediate(Instruction* instr) { 483 Update(); 484 static Counter* counter = GetCounter("Conditional Compare"); 485 counter->Increment(); 486 } 487 488 489 void Instrument::VisitConditionalSelect(Instruction* instr) { 490 Update(); 491 static Counter* counter = GetCounter("Conditional Select"); 492 counter->Increment(); 493 } 494 495 496 void Instrument::VisitDataProcessing1Source(Instruction* instr) { 497 Update(); 498 static Counter* counter = GetCounter("Other Int DP"); 499 counter->Increment(); 500 } 501 502 503 void Instrument::VisitDataProcessing2Source(Instruction* instr) { 504 Update(); 505 static Counter* counter = GetCounter("Other Int DP"); 506 counter->Increment(); 507 } 508 509 510 void Instrument::VisitDataProcessing3Source(Instruction* instr) { 511 Update(); 512 static Counter* counter = GetCounter("Other Int DP"); 513 counter->Increment(); 514 } 515 516 517 void Instrument::VisitFPCompare(Instruction* instr) { 518 Update(); 519 static Counter* counter = GetCounter("FP DP"); 520 counter->Increment(); 521 } 522 523 524 void Instrument::VisitFPConditionalCompare(Instruction* instr) { 525 Update(); 526 static Counter* counter = GetCounter("Conditional Compare"); 527 counter->Increment(); 528 } 529 530 531 void Instrument::VisitFPConditionalSelect(Instruction* instr) { 532 Update(); 533 static Counter* counter = GetCounter("Conditional Select"); 534 counter->Increment(); 535 } 536 537 538 void Instrument::VisitFPImmediate(Instruction* instr) { 539 Update(); 540 static Counter* counter = GetCounter("FP DP"); 541 counter->Increment(); 542 } 543 544 545 void Instrument::VisitFPDataProcessing1Source(Instruction* instr) { 546 Update(); 547 static Counter* counter = GetCounter("FP DP"); 548 counter->Increment(); 549 } 550 551 552 void Instrument::VisitFPDataProcessing2Source(Instruction* instr) { 553 Update(); 554 static Counter* counter = GetCounter("FP DP"); 555 counter->Increment(); 556 } 557 558 559 void Instrument::VisitFPDataProcessing3Source(Instruction* instr) { 560 Update(); 561 static Counter* counter = GetCounter("FP DP"); 562 counter->Increment(); 563 } 564 565 566 void Instrument::VisitFPIntegerConvert(Instruction* instr) { 567 Update(); 568 static Counter* counter = GetCounter("FP DP"); 569 counter->Increment(); 570 } 571 572 573 void Instrument::VisitFPFixedPointConvert(Instruction* instr) { 574 Update(); 575 static Counter* counter = GetCounter("FP DP"); 576 counter->Increment(); 577 } 578 579 580 void Instrument::VisitUnallocated(Instruction* instr) { 581 Update(); 582 static Counter* counter = GetCounter("Other"); 583 counter->Increment(); 584 } 585 586 587 void Instrument::VisitUnimplemented(Instruction* instr) { 588 Update(); 589 static Counter* counter = GetCounter("Other"); 590 counter->Increment(); 591 } 592 593 594 } } // namespace v8::internal 595