1// Copyright 2013, ARM Limited
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7//   * Redistributions of source code must retain the above copyright notice,
8//     this list of conditions and the following disclaimer.
9//   * Redistributions in binary form must reproduce the above copyright notice,
10//     this list of conditions and the following disclaimer in the documentation
11//     and/or other materials provided with the distribution.
12//   * Neither the name of ARM Limited nor the names of its contributors may be
13//     used to endorse or promote products derived from this software without
14//     specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#include "a64/instrument-a64.h"
28
29namespace vixl {
30
31Counter::Counter(const char* name, CounterType type)
32    : count_(0), enabled_(false), type_(type) {
33  VIXL_ASSERT(name != NULL);
34  strncpy(name_, name, kCounterNameMaxLength);
35}
36
37
38void Counter::Enable() {
39  enabled_ = true;
40}
41
42
43void Counter::Disable() {
44  enabled_ = false;
45}
46
47
48bool Counter::IsEnabled() {
49  return enabled_;
50}
51
52
53void Counter::Increment() {
54  if (enabled_) {
55    count_++;
56  }
57}
58
59
60uint64_t Counter::count() {
61  uint64_t result = count_;
62  if (type_ == Gauge) {
63    // If the counter is a Gauge, reset the count after reading.
64    count_ = 0;
65  }
66  return result;
67}
68
69
70const char* Counter::name() {
71  return name_;
72}
73
74
75CounterType Counter::type() {
76  return type_;
77}
78
79
80typedef struct {
81  const char* name;
82  CounterType type;
83} CounterDescriptor;
84
85
86static const CounterDescriptor kCounterList[] = {
87  {"Instruction", Cumulative},
88
89  {"Move Immediate", Gauge},
90  {"Add/Sub DP", Gauge},
91  {"Logical DP", Gauge},
92  {"Other Int DP", Gauge},
93  {"FP DP", Gauge},
94
95  {"Conditional Select", Gauge},
96  {"Conditional Compare", Gauge},
97
98  {"Unconditional Branch", Gauge},
99  {"Compare and Branch", Gauge},
100  {"Test and Branch", Gauge},
101  {"Conditional Branch", Gauge},
102
103  {"Load Integer", Gauge},
104  {"Load FP", Gauge},
105  {"Load Pair", Gauge},
106  {"Load Literal", Gauge},
107
108  {"Store Integer", Gauge},
109  {"Store FP", Gauge},
110  {"Store Pair", Gauge},
111
112  {"PC Addressing", Gauge},
113  {"Other", Gauge},
114};
115
116
117Instrument::Instrument(const char* datafile, uint64_t sample_period)
118    : output_stream_(stdout), sample_period_(sample_period) {
119
120  // Set up the output stream. If datafile is non-NULL, use that file. If it
121  // can't be opened, or datafile is NULL, use stdout.
122  if (datafile != NULL) {
123    output_stream_ = fopen(datafile, "w");
124    if (output_stream_ == NULL) {
125      printf("Can't open output file %s. Using stdout.\n", datafile);
126      output_stream_ = stdout;
127    }
128  }
129
130  static const int num_counters =
131    sizeof(kCounterList) / sizeof(CounterDescriptor);
132
133  // Dump an instrumentation description comment at the top of the file.
134  fprintf(output_stream_, "# counters=%d\n", num_counters);
135  fprintf(output_stream_, "# sample_period=%" PRIu64 "\n", sample_period_);
136
137  // Construct Counter objects from counter description array.
138  for (int i = 0; i < num_counters; i++) {
139    Counter* counter = new Counter(kCounterList[i].name, kCounterList[i].type);
140    counters_.push_back(counter);
141  }
142
143  DumpCounterNames();
144}
145
146
147Instrument::~Instrument() {
148  // Dump any remaining instruction data to the output file.
149  DumpCounters();
150
151  // Free all the counter objects.
152  std::list<Counter*>::iterator it;
153  for (it = counters_.begin(); it != counters_.end(); it++) {
154    delete *it;
155  }
156
157  if (output_stream_ != stdout) {
158    fclose(output_stream_);
159  }
160}
161
162
163void Instrument::Update() {
164  // Increment the instruction counter, and dump all counters if a sample period
165  // has elapsed.
166  static Counter* counter = GetCounter("Instruction");
167  VIXL_ASSERT(counter->type() == Cumulative);
168  counter->Increment();
169
170  if (counter->IsEnabled() && (counter->count() % sample_period_) == 0) {
171    DumpCounters();
172  }
173}
174
175
176void Instrument::DumpCounters() {
177  // Iterate through the counter objects, dumping their values to the output
178  // stream.
179  std::list<Counter*>::const_iterator it;
180  for (it = counters_.begin(); it != counters_.end(); it++) {
181    fprintf(output_stream_, "%" PRIu64 ",", (*it)->count());
182  }
183  fprintf(output_stream_, "\n");
184  fflush(output_stream_);
185}
186
187
188void Instrument::DumpCounterNames() {
189  // Iterate through the counter objects, dumping the counter names to the
190  // output stream.
191  std::list<Counter*>::const_iterator it;
192  for (it = counters_.begin(); it != counters_.end(); it++) {
193    fprintf(output_stream_, "%s,", (*it)->name());
194  }
195  fprintf(output_stream_, "\n");
196  fflush(output_stream_);
197}
198
199
200void Instrument::HandleInstrumentationEvent(unsigned event) {
201  switch (event) {
202    case InstrumentStateEnable: Enable(); break;
203    case InstrumentStateDisable: Disable(); break;
204    default: DumpEventMarker(event);
205  }
206}
207
208
209void Instrument::DumpEventMarker(unsigned marker) {
210  // Dumpan event marker to the output stream as a specially formatted comment
211  // line.
212  static Counter* counter = GetCounter("Instruction");
213
214  fprintf(output_stream_, "# %c%c @ %" PRId64 "\n", marker & 0xff,
215          (marker >> 8) & 0xff, counter->count());
216}
217
218
219Counter* Instrument::GetCounter(const char* name) {
220  // Get a Counter object by name from the counter list.
221  std::list<Counter*>::const_iterator it;
222  for (it = counters_.begin(); it != counters_.end(); it++) {
223    if (strcmp((*it)->name(), name) == 0) {
224      return *it;
225    }
226  }
227
228  // A Counter by that name does not exist: print an error message to stderr
229  // and the output file, and exit.
230  static const char* error_message =
231    "# Error: Unknown counter \"%s\". Exiting.\n";
232  fprintf(stderr, error_message, name);
233  fprintf(output_stream_, error_message, name);
234  exit(1);
235}
236
237
238void Instrument::Enable() {
239  std::list<Counter*>::iterator it;
240  for (it = counters_.begin(); it != counters_.end(); it++) {
241    (*it)->Enable();
242  }
243}
244
245
246void Instrument::Disable() {
247  std::list<Counter*>::iterator it;
248  for (it = counters_.begin(); it != counters_.end(); it++) {
249    (*it)->Disable();
250  }
251}
252
253
254void Instrument::VisitPCRelAddressing(Instruction* instr) {
255  USE(instr);
256  Update();
257  static Counter* counter = GetCounter("PC Addressing");
258  counter->Increment();
259}
260
261
262void Instrument::VisitAddSubImmediate(Instruction* instr) {
263  USE(instr);
264  Update();
265  static Counter* counter = GetCounter("Add/Sub DP");
266  counter->Increment();
267}
268
269
270void Instrument::VisitLogicalImmediate(Instruction* instr) {
271  USE(instr);
272  Update();
273  static Counter* counter = GetCounter("Logical DP");
274  counter->Increment();
275}
276
277
278void Instrument::VisitMoveWideImmediate(Instruction* instr) {
279  Update();
280  static Counter* counter = GetCounter("Move Immediate");
281
282  if (instr->IsMovn() && (instr->Rd() == kZeroRegCode)) {
283    unsigned imm = instr->ImmMoveWide();
284    HandleInstrumentationEvent(imm);
285  } else {
286    counter->Increment();
287  }
288}
289
290
291void Instrument::VisitBitfield(Instruction* instr) {
292  USE(instr);
293  Update();
294  static Counter* counter = GetCounter("Other Int DP");
295  counter->Increment();
296}
297
298
299void Instrument::VisitExtract(Instruction* instr) {
300  USE(instr);
301  Update();
302  static Counter* counter = GetCounter("Other Int DP");
303  counter->Increment();
304}
305
306
307void Instrument::VisitUnconditionalBranch(Instruction* instr) {
308  USE(instr);
309  Update();
310  static Counter* counter = GetCounter("Unconditional Branch");
311  counter->Increment();
312}
313
314
315void Instrument::VisitUnconditionalBranchToRegister(Instruction* instr) {
316  USE(instr);
317  Update();
318  static Counter* counter = GetCounter("Unconditional Branch");
319  counter->Increment();
320}
321
322
323void Instrument::VisitCompareBranch(Instruction* instr) {
324  USE(instr);
325  Update();
326  static Counter* counter = GetCounter("Compare and Branch");
327  counter->Increment();
328}
329
330
331void Instrument::VisitTestBranch(Instruction* instr) {
332  USE(instr);
333  Update();
334  static Counter* counter = GetCounter("Test and Branch");
335  counter->Increment();
336}
337
338
339void Instrument::VisitConditionalBranch(Instruction* instr) {
340  USE(instr);
341  Update();
342  static Counter* counter = GetCounter("Conditional Branch");
343  counter->Increment();
344}
345
346
347void Instrument::VisitSystem(Instruction* instr) {
348  USE(instr);
349  Update();
350  static Counter* counter = GetCounter("Other");
351  counter->Increment();
352}
353
354
355void Instrument::VisitException(Instruction* instr) {
356  USE(instr);
357  Update();
358  static Counter* counter = GetCounter("Other");
359  counter->Increment();
360}
361
362
363void Instrument::InstrumentLoadStorePair(Instruction* instr) {
364  static Counter* load_pair_counter = GetCounter("Load Pair");
365  static Counter* store_pair_counter = GetCounter("Store Pair");
366
367  if (instr->Mask(LoadStorePairLBit) != 0) {
368    load_pair_counter->Increment();
369  } else {
370    store_pair_counter->Increment();
371  }
372}
373
374
375void Instrument::VisitLoadStorePairPostIndex(Instruction* instr) {
376  USE(instr);
377  Update();
378  InstrumentLoadStorePair(instr);
379}
380
381
382void Instrument::VisitLoadStorePairOffset(Instruction* instr) {
383  USE(instr);
384  Update();
385  InstrumentLoadStorePair(instr);
386}
387
388
389void Instrument::VisitLoadStorePairPreIndex(Instruction* instr) {
390  USE(instr);
391  Update();
392  InstrumentLoadStorePair(instr);
393}
394
395
396void Instrument::VisitLoadStorePairNonTemporal(Instruction* instr) {
397  USE(instr);
398  Update();
399  InstrumentLoadStorePair(instr);
400}
401
402
403void Instrument::VisitLoadLiteral(Instruction* instr) {
404  USE(instr);
405  Update();
406  static Counter* counter = GetCounter("Load Literal");
407  counter->Increment();
408}
409
410
411void Instrument::InstrumentLoadStore(Instruction* instr) {
412  static Counter* load_int_counter = GetCounter("Load Integer");
413  static Counter* store_int_counter = GetCounter("Store Integer");
414  static Counter* load_fp_counter = GetCounter("Load FP");
415  static Counter* store_fp_counter = GetCounter("Store FP");
416
417  switch (instr->Mask(LoadStoreOpMask)) {
418    case STRB_w:    // Fall through.
419    case STRH_w:    // Fall through.
420    case STR_w:     // Fall through.
421    case STR_x:     store_int_counter->Increment(); break;
422    case STR_s:     // Fall through.
423    case STR_d:     store_fp_counter->Increment(); break;
424    case LDRB_w:    // Fall through.
425    case LDRH_w:    // Fall through.
426    case LDR_w:     // Fall through.
427    case LDR_x:     // Fall through.
428    case LDRSB_x:   // Fall through.
429    case LDRSH_x:   // Fall through.
430    case LDRSW_x:   // Fall through.
431    case LDRSB_w:   // Fall through.
432    case LDRSH_w:   load_int_counter->Increment(); break;
433    case LDR_s:     // Fall through.
434    case LDR_d:     load_fp_counter->Increment(); break;
435  }
436}
437
438
439void Instrument::VisitLoadStoreUnscaledOffset(Instruction* instr) {
440  Update();
441  InstrumentLoadStore(instr);
442}
443
444
445void Instrument::VisitLoadStorePostIndex(Instruction* instr) {
446  USE(instr);
447  Update();
448  InstrumentLoadStore(instr);
449}
450
451
452void Instrument::VisitLoadStorePreIndex(Instruction* instr) {
453  Update();
454  InstrumentLoadStore(instr);
455}
456
457
458void Instrument::VisitLoadStoreRegisterOffset(Instruction* instr) {
459  Update();
460  InstrumentLoadStore(instr);
461}
462
463
464void Instrument::VisitLoadStoreUnsignedOffset(Instruction* instr) {
465  Update();
466  InstrumentLoadStore(instr);
467}
468
469
470void Instrument::VisitLogicalShifted(Instruction* instr) {
471  USE(instr);
472  Update();
473  static Counter* counter = GetCounter("Logical DP");
474  counter->Increment();
475}
476
477
478void Instrument::VisitAddSubShifted(Instruction* instr) {
479  USE(instr);
480  Update();
481  static Counter* counter = GetCounter("Add/Sub DP");
482  counter->Increment();
483}
484
485
486void Instrument::VisitAddSubExtended(Instruction* instr) {
487  USE(instr);
488  Update();
489  static Counter* counter = GetCounter("Add/Sub DP");
490  counter->Increment();
491}
492
493
494void Instrument::VisitAddSubWithCarry(Instruction* instr) {
495  USE(instr);
496  Update();
497  static Counter* counter = GetCounter("Add/Sub DP");
498  counter->Increment();
499}
500
501
502void Instrument::VisitConditionalCompareRegister(Instruction* instr) {
503  USE(instr);
504  Update();
505  static Counter* counter = GetCounter("Conditional Compare");
506  counter->Increment();
507}
508
509
510void Instrument::VisitConditionalCompareImmediate(Instruction* instr) {
511  USE(instr);
512  Update();
513  static Counter* counter = GetCounter("Conditional Compare");
514  counter->Increment();
515}
516
517
518void Instrument::VisitConditionalSelect(Instruction* instr) {
519  USE(instr);
520  Update();
521  static Counter* counter = GetCounter("Conditional Select");
522  counter->Increment();
523}
524
525
526void Instrument::VisitDataProcessing1Source(Instruction* instr) {
527  USE(instr);
528  Update();
529  static Counter* counter = GetCounter("Other Int DP");
530  counter->Increment();
531}
532
533
534void Instrument::VisitDataProcessing2Source(Instruction* instr) {
535  USE(instr);
536  Update();
537  static Counter* counter = GetCounter("Other Int DP");
538  counter->Increment();
539}
540
541
542void Instrument::VisitDataProcessing3Source(Instruction* instr) {
543  USE(instr);
544  Update();
545  static Counter* counter = GetCounter("Other Int DP");
546  counter->Increment();
547}
548
549
550void Instrument::VisitFPCompare(Instruction* instr) {
551  USE(instr);
552  Update();
553  static Counter* counter = GetCounter("FP DP");
554  counter->Increment();
555}
556
557
558void Instrument::VisitFPConditionalCompare(Instruction* instr) {
559  USE(instr);
560  Update();
561  static Counter* counter = GetCounter("Conditional Compare");
562  counter->Increment();
563}
564
565
566void Instrument::VisitFPConditionalSelect(Instruction* instr) {
567  USE(instr);
568  Update();
569  static Counter* counter = GetCounter("Conditional Select");
570  counter->Increment();
571}
572
573
574void Instrument::VisitFPImmediate(Instruction* instr) {
575  USE(instr);
576  Update();
577  static Counter* counter = GetCounter("FP DP");
578  counter->Increment();
579}
580
581
582void Instrument::VisitFPDataProcessing1Source(Instruction* instr) {
583  USE(instr);
584  Update();
585  static Counter* counter = GetCounter("FP DP");
586  counter->Increment();
587}
588
589
590void Instrument::VisitFPDataProcessing2Source(Instruction* instr) {
591  USE(instr);
592  Update();
593  static Counter* counter = GetCounter("FP DP");
594  counter->Increment();
595}
596
597
598void Instrument::VisitFPDataProcessing3Source(Instruction* instr) {
599  USE(instr);
600  Update();
601  static Counter* counter = GetCounter("FP DP");
602  counter->Increment();
603}
604
605
606void Instrument::VisitFPIntegerConvert(Instruction* instr) {
607  USE(instr);
608  Update();
609  static Counter* counter = GetCounter("FP DP");
610  counter->Increment();
611}
612
613
614void Instrument::VisitFPFixedPointConvert(Instruction* instr) {
615  USE(instr);
616  Update();
617  static Counter* counter = GetCounter("FP DP");
618  counter->Increment();
619}
620
621
622void Instrument::VisitUnallocated(Instruction* instr) {
623  USE(instr);
624  Update();
625  static Counter* counter = GetCounter("Other");
626  counter->Increment();
627}
628
629
630void Instrument::VisitUnimplemented(Instruction* instr) {
631  USE(instr);
632  Update();
633  static Counter* counter = GetCounter("Other");
634  counter->Increment();
635}
636
637
638}  // namespace v8::internal
639