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 432 433void Instrument::VisitLogicalShifted(Instruction* instr) { 434 Update(); 435 static Counter* counter = GetCounter("Logical DP"); 436 counter->Increment(); 437} 438 439 440void Instrument::VisitAddSubShifted(Instruction* instr) { 441 Update(); 442 static Counter* counter = GetCounter("Add/Sub DP"); 443 counter->Increment(); 444} 445 446 447void Instrument::VisitAddSubExtended(Instruction* instr) { 448 Update(); 449 static Counter* sp_counter = GetCounter("SP Adjust"); 450 static Counter* add_sub_counter = GetCounter("Add/Sub DP"); 451 if (((instr->Mask(AddSubOpMask) == SUB) || 452 (instr->Mask(AddSubOpMask) == ADD)) && 453 (instr->Rd() == 31) && (instr->Rn() == 31)) { 454 // Count adjustments to the C stack pointer caused by V8 needing two SPs. 455 sp_counter->Increment(); 456 } else { 457 add_sub_counter->Increment(); 458 } 459} 460 461 462void Instrument::VisitAddSubWithCarry(Instruction* instr) { 463 Update(); 464 static Counter* counter = GetCounter("Add/Sub DP"); 465 counter->Increment(); 466} 467 468 469void Instrument::VisitConditionalCompareRegister(Instruction* instr) { 470 Update(); 471 static Counter* counter = GetCounter("Conditional Compare"); 472 counter->Increment(); 473} 474 475 476void Instrument::VisitConditionalCompareImmediate(Instruction* instr) { 477 Update(); 478 static Counter* counter = GetCounter("Conditional Compare"); 479 counter->Increment(); 480} 481 482 483void Instrument::VisitConditionalSelect(Instruction* instr) { 484 Update(); 485 static Counter* counter = GetCounter("Conditional Select"); 486 counter->Increment(); 487} 488 489 490void Instrument::VisitDataProcessing1Source(Instruction* instr) { 491 Update(); 492 static Counter* counter = GetCounter("Other Int DP"); 493 counter->Increment(); 494} 495 496 497void Instrument::VisitDataProcessing2Source(Instruction* instr) { 498 Update(); 499 static Counter* counter = GetCounter("Other Int DP"); 500 counter->Increment(); 501} 502 503 504void Instrument::VisitDataProcessing3Source(Instruction* instr) { 505 Update(); 506 static Counter* counter = GetCounter("Other Int DP"); 507 counter->Increment(); 508} 509 510 511void Instrument::VisitFPCompare(Instruction* instr) { 512 Update(); 513 static Counter* counter = GetCounter("FP DP"); 514 counter->Increment(); 515} 516 517 518void Instrument::VisitFPConditionalCompare(Instruction* instr) { 519 Update(); 520 static Counter* counter = GetCounter("Conditional Compare"); 521 counter->Increment(); 522} 523 524 525void Instrument::VisitFPConditionalSelect(Instruction* instr) { 526 Update(); 527 static Counter* counter = GetCounter("Conditional Select"); 528 counter->Increment(); 529} 530 531 532void Instrument::VisitFPImmediate(Instruction* instr) { 533 Update(); 534 static Counter* counter = GetCounter("FP DP"); 535 counter->Increment(); 536} 537 538 539void Instrument::VisitFPDataProcessing1Source(Instruction* instr) { 540 Update(); 541 static Counter* counter = GetCounter("FP DP"); 542 counter->Increment(); 543} 544 545 546void Instrument::VisitFPDataProcessing2Source(Instruction* instr) { 547 Update(); 548 static Counter* counter = GetCounter("FP DP"); 549 counter->Increment(); 550} 551 552 553void Instrument::VisitFPDataProcessing3Source(Instruction* instr) { 554 Update(); 555 static Counter* counter = GetCounter("FP DP"); 556 counter->Increment(); 557} 558 559 560void Instrument::VisitFPIntegerConvert(Instruction* instr) { 561 Update(); 562 static Counter* counter = GetCounter("FP DP"); 563 counter->Increment(); 564} 565 566 567void Instrument::VisitFPFixedPointConvert(Instruction* instr) { 568 Update(); 569 static Counter* counter = GetCounter("FP DP"); 570 counter->Increment(); 571} 572 573 574void Instrument::VisitUnallocated(Instruction* instr) { 575 Update(); 576 static Counter* counter = GetCounter("Other"); 577 counter->Increment(); 578} 579 580 581void Instrument::VisitUnimplemented(Instruction* instr) { 582 Update(); 583 static Counter* counter = GetCounter("Other"); 584 counter->Increment(); 585} 586 587 588} // namespace internal 589} // namespace v8 590