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::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