Home | History | Annotate | Download | only in arm64
      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