1// Copyright 2014, 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 "vixl/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
80struct CounterDescriptor {
81  const char* name;
82  CounterType type;
83};
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  {"NEON", Gauge},
115  {"Crypto", Gauge}
116};
117
118
119Instrument::Instrument(const char* datafile, uint64_t sample_period)
120    : output_stream_(stdout), sample_period_(sample_period) {
121
122  // Set up the output stream. If datafile is non-NULL, use that file. If it
123  // can't be opened, or datafile is NULL, use stdout.
124  if (datafile != NULL) {
125    output_stream_ = fopen(datafile, "w");
126    if (output_stream_ == NULL) {
127      printf("Can't open output file %s. Using stdout.\n", datafile);
128      output_stream_ = stdout;
129    }
130  }
131
132  static const int num_counters =
133    sizeof(kCounterList) / sizeof(CounterDescriptor);
134
135  // Dump an instrumentation description comment at the top of the file.
136  fprintf(output_stream_, "# counters=%d\n", num_counters);
137  fprintf(output_stream_, "# sample_period=%" PRIu64 "\n", sample_period_);
138
139  // Construct Counter objects from counter description array.
140  for (int i = 0; i < num_counters; i++) {
141    Counter* counter = new Counter(kCounterList[i].name, kCounterList[i].type);
142    counters_.push_back(counter);
143  }
144
145  DumpCounterNames();
146}
147
148
149Instrument::~Instrument() {
150  // Dump any remaining instruction data to the output file.
151  DumpCounters();
152
153  // Free all the counter objects.
154  std::list<Counter*>::iterator it;
155  for (it = counters_.begin(); it != counters_.end(); it++) {
156    delete *it;
157  }
158
159  if (output_stream_ != stdout) {
160    fclose(output_stream_);
161  }
162}
163
164
165void Instrument::Update() {
166  // Increment the instruction counter, and dump all counters if a sample period
167  // has elapsed.
168  static Counter* counter = GetCounter("Instruction");
169  VIXL_ASSERT(counter->type() == Cumulative);
170  counter->Increment();
171
172  if ((sample_period_ != 0) && counter->IsEnabled()
173      && (counter->count() % sample_period_) == 0) {
174    DumpCounters();
175  }
176}
177
178
179void Instrument::DumpCounters() {
180  // Iterate through the counter objects, dumping their values to the output
181  // stream.
182  std::list<Counter*>::const_iterator it;
183  for (it = counters_.begin(); it != counters_.end(); it++) {
184    fprintf(output_stream_, "%" PRIu64 ",", (*it)->count());
185  }
186  fprintf(output_stream_, "\n");
187  fflush(output_stream_);
188}
189
190
191void Instrument::DumpCounterNames() {
192  // Iterate through the counter objects, dumping the counter names to the
193  // output stream.
194  std::list<Counter*>::const_iterator it;
195  for (it = counters_.begin(); it != counters_.end(); it++) {
196    fprintf(output_stream_, "%s,", (*it)->name());
197  }
198  fprintf(output_stream_, "\n");
199  fflush(output_stream_);
200}
201
202
203void Instrument::HandleInstrumentationEvent(unsigned event) {
204  switch (event) {
205    case InstrumentStateEnable: Enable(); break;
206    case InstrumentStateDisable: Disable(); break;
207    default: DumpEventMarker(event);
208  }
209}
210
211
212void Instrument::DumpEventMarker(unsigned marker) {
213  // Dumpan event marker to the output stream as a specially formatted comment
214  // line.
215  static Counter* counter = GetCounter("Instruction");
216
217  fprintf(output_stream_, "# %c%c @ %" PRId64 "\n", marker & 0xff,
218          (marker >> 8) & 0xff, counter->count());
219}
220
221
222Counter* Instrument::GetCounter(const char* name) {
223  // Get a Counter object by name from the counter list.
224  std::list<Counter*>::const_iterator it;
225  for (it = counters_.begin(); it != counters_.end(); it++) {
226    if (strcmp((*it)->name(), name) == 0) {
227      return *it;
228    }
229  }
230
231  // A Counter by that name does not exist: print an error message to stderr
232  // and the output file, and exit.
233  static const char* error_message =
234    "# Error: Unknown counter \"%s\". Exiting.\n";
235  fprintf(stderr, error_message, name);
236  fprintf(output_stream_, error_message, name);
237  exit(1);
238}
239
240
241void Instrument::Enable() {
242  std::list<Counter*>::iterator it;
243  for (it = counters_.begin(); it != counters_.end(); it++) {
244    (*it)->Enable();
245  }
246}
247
248
249void Instrument::Disable() {
250  std::list<Counter*>::iterator it;
251  for (it = counters_.begin(); it != counters_.end(); it++) {
252    (*it)->Disable();
253  }
254}
255
256
257void Instrument::VisitPCRelAddressing(const Instruction* instr) {
258  USE(instr);
259  Update();
260  static Counter* counter = GetCounter("PC Addressing");
261  counter->Increment();
262}
263
264
265void Instrument::VisitAddSubImmediate(const Instruction* instr) {
266  USE(instr);
267  Update();
268  static Counter* counter = GetCounter("Add/Sub DP");
269  counter->Increment();
270}
271
272
273void Instrument::VisitLogicalImmediate(const Instruction* instr) {
274  USE(instr);
275  Update();
276  static Counter* counter = GetCounter("Logical DP");
277  counter->Increment();
278}
279
280
281void Instrument::VisitMoveWideImmediate(const Instruction* instr) {
282  Update();
283  static Counter* counter = GetCounter("Move Immediate");
284
285  if (instr->IsMovn() && (instr->Rd() == kZeroRegCode)) {
286    unsigned imm = instr->ImmMoveWide();
287    HandleInstrumentationEvent(imm);
288  } else {
289    counter->Increment();
290  }
291}
292
293
294void Instrument::VisitBitfield(const Instruction* instr) {
295  USE(instr);
296  Update();
297  static Counter* counter = GetCounter("Other Int DP");
298  counter->Increment();
299}
300
301
302void Instrument::VisitExtract(const Instruction* instr) {
303  USE(instr);
304  Update();
305  static Counter* counter = GetCounter("Other Int DP");
306  counter->Increment();
307}
308
309
310void Instrument::VisitUnconditionalBranch(const Instruction* instr) {
311  USE(instr);
312  Update();
313  static Counter* counter = GetCounter("Unconditional Branch");
314  counter->Increment();
315}
316
317
318void Instrument::VisitUnconditionalBranchToRegister(const Instruction* instr) {
319  USE(instr);
320  Update();
321  static Counter* counter = GetCounter("Unconditional Branch");
322  counter->Increment();
323}
324
325
326void Instrument::VisitCompareBranch(const Instruction* instr) {
327  USE(instr);
328  Update();
329  static Counter* counter = GetCounter("Compare and Branch");
330  counter->Increment();
331}
332
333
334void Instrument::VisitTestBranch(const Instruction* instr) {
335  USE(instr);
336  Update();
337  static Counter* counter = GetCounter("Test and Branch");
338  counter->Increment();
339}
340
341
342void Instrument::VisitConditionalBranch(const Instruction* instr) {
343  USE(instr);
344  Update();
345  static Counter* counter = GetCounter("Conditional Branch");
346  counter->Increment();
347}
348
349
350void Instrument::VisitSystem(const Instruction* instr) {
351  USE(instr);
352  Update();
353  static Counter* counter = GetCounter("Other");
354  counter->Increment();
355}
356
357
358void Instrument::VisitException(const Instruction* instr) {
359  USE(instr);
360  Update();
361  static Counter* counter = GetCounter("Other");
362  counter->Increment();
363}
364
365
366void Instrument::InstrumentLoadStorePair(const Instruction* instr) {
367  static Counter* load_pair_counter = GetCounter("Load Pair");
368  static Counter* store_pair_counter = GetCounter("Store Pair");
369
370  if (instr->Mask(LoadStorePairLBit) != 0) {
371    load_pair_counter->Increment();
372  } else {
373    store_pair_counter->Increment();
374  }
375}
376
377
378void Instrument::VisitLoadStorePairPostIndex(const Instruction* instr) {
379  Update();
380  InstrumentLoadStorePair(instr);
381}
382
383
384void Instrument::VisitLoadStorePairOffset(const Instruction* instr) {
385  Update();
386  InstrumentLoadStorePair(instr);
387}
388
389
390void Instrument::VisitLoadStorePairPreIndex(const Instruction* instr) {
391  Update();
392  InstrumentLoadStorePair(instr);
393}
394
395
396void Instrument::VisitLoadStorePairNonTemporal(const Instruction* instr) {
397  Update();
398  InstrumentLoadStorePair(instr);
399}
400
401
402void Instrument::VisitLoadStoreExclusive(const Instruction* instr) {
403  USE(instr);
404  Update();
405  static Counter* counter = GetCounter("Other");
406  counter->Increment();
407}
408
409
410void Instrument::VisitLoadLiteral(const Instruction* instr) {
411  USE(instr);
412  Update();
413  static Counter* counter = GetCounter("Load Literal");
414  counter->Increment();
415}
416
417
418void Instrument::InstrumentLoadStore(const Instruction* instr) {
419  static Counter* load_int_counter = GetCounter("Load Integer");
420  static Counter* store_int_counter = GetCounter("Store Integer");
421  static Counter* load_fp_counter = GetCounter("Load FP");
422  static Counter* store_fp_counter = GetCounter("Store FP");
423
424  switch (instr->Mask(LoadStoreMask)) {
425    case STRB_w:
426    case STRH_w:
427    case STR_w:
428      VIXL_FALLTHROUGH();
429    case STR_x:     store_int_counter->Increment(); break;
430    case STR_s:
431      VIXL_FALLTHROUGH();
432    case STR_d:     store_fp_counter->Increment(); break;
433    case LDRB_w:
434    case LDRH_w:
435    case LDR_w:
436    case LDR_x:
437    case LDRSB_x:
438    case LDRSH_x:
439    case LDRSW_x:
440    case LDRSB_w:
441      VIXL_FALLTHROUGH();
442    case LDRSH_w:   load_int_counter->Increment(); break;
443    case LDR_s:
444      VIXL_FALLTHROUGH();
445    case LDR_d:     load_fp_counter->Increment(); break;
446  }
447}
448
449
450void Instrument::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
451  Update();
452  InstrumentLoadStore(instr);
453}
454
455
456void Instrument::VisitLoadStorePostIndex(const Instruction* instr) {
457  USE(instr);
458  Update();
459  InstrumentLoadStore(instr);
460}
461
462
463void Instrument::VisitLoadStorePreIndex(const Instruction* instr) {
464  Update();
465  InstrumentLoadStore(instr);
466}
467
468
469void Instrument::VisitLoadStoreRegisterOffset(const Instruction* instr) {
470  Update();
471  InstrumentLoadStore(instr);
472}
473
474
475void Instrument::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
476  Update();
477  InstrumentLoadStore(instr);
478}
479
480
481void Instrument::VisitLogicalShifted(const Instruction* instr) {
482  USE(instr);
483  Update();
484  static Counter* counter = GetCounter("Logical DP");
485  counter->Increment();
486}
487
488
489void Instrument::VisitAddSubShifted(const Instruction* instr) {
490  USE(instr);
491  Update();
492  static Counter* counter = GetCounter("Add/Sub DP");
493  counter->Increment();
494}
495
496
497void Instrument::VisitAddSubExtended(const Instruction* instr) {
498  USE(instr);
499  Update();
500  static Counter* counter = GetCounter("Add/Sub DP");
501  counter->Increment();
502}
503
504
505void Instrument::VisitAddSubWithCarry(const Instruction* instr) {
506  USE(instr);
507  Update();
508  static Counter* counter = GetCounter("Add/Sub DP");
509  counter->Increment();
510}
511
512
513void Instrument::VisitConditionalCompareRegister(const Instruction* instr) {
514  USE(instr);
515  Update();
516  static Counter* counter = GetCounter("Conditional Compare");
517  counter->Increment();
518}
519
520
521void Instrument::VisitConditionalCompareImmediate(const Instruction* instr) {
522  USE(instr);
523  Update();
524  static Counter* counter = GetCounter("Conditional Compare");
525  counter->Increment();
526}
527
528
529void Instrument::VisitConditionalSelect(const Instruction* instr) {
530  USE(instr);
531  Update();
532  static Counter* counter = GetCounter("Conditional Select");
533  counter->Increment();
534}
535
536
537void Instrument::VisitDataProcessing1Source(const Instruction* instr) {
538  USE(instr);
539  Update();
540  static Counter* counter = GetCounter("Other Int DP");
541  counter->Increment();
542}
543
544
545void Instrument::VisitDataProcessing2Source(const Instruction* instr) {
546  USE(instr);
547  Update();
548  static Counter* counter = GetCounter("Other Int DP");
549  counter->Increment();
550}
551
552
553void Instrument::VisitDataProcessing3Source(const Instruction* instr) {
554  USE(instr);
555  Update();
556  static Counter* counter = GetCounter("Other Int DP");
557  counter->Increment();
558}
559
560
561void Instrument::VisitFPCompare(const Instruction* instr) {
562  USE(instr);
563  Update();
564  static Counter* counter = GetCounter("FP DP");
565  counter->Increment();
566}
567
568
569void Instrument::VisitFPConditionalCompare(const Instruction* instr) {
570  USE(instr);
571  Update();
572  static Counter* counter = GetCounter("Conditional Compare");
573  counter->Increment();
574}
575
576
577void Instrument::VisitFPConditionalSelect(const Instruction* instr) {
578  USE(instr);
579  Update();
580  static Counter* counter = GetCounter("Conditional Select");
581  counter->Increment();
582}
583
584
585void Instrument::VisitFPImmediate(const Instruction* instr) {
586  USE(instr);
587  Update();
588  static Counter* counter = GetCounter("FP DP");
589  counter->Increment();
590}
591
592
593void Instrument::VisitFPDataProcessing1Source(const Instruction* instr) {
594  USE(instr);
595  Update();
596  static Counter* counter = GetCounter("FP DP");
597  counter->Increment();
598}
599
600
601void Instrument::VisitFPDataProcessing2Source(const Instruction* instr) {
602  USE(instr);
603  Update();
604  static Counter* counter = GetCounter("FP DP");
605  counter->Increment();
606}
607
608
609void Instrument::VisitFPDataProcessing3Source(const Instruction* instr) {
610  USE(instr);
611  Update();
612  static Counter* counter = GetCounter("FP DP");
613  counter->Increment();
614}
615
616
617void Instrument::VisitFPIntegerConvert(const Instruction* instr) {
618  USE(instr);
619  Update();
620  static Counter* counter = GetCounter("FP DP");
621  counter->Increment();
622}
623
624
625void Instrument::VisitFPFixedPointConvert(const Instruction* instr) {
626  USE(instr);
627  Update();
628  static Counter* counter = GetCounter("FP DP");
629  counter->Increment();
630}
631
632
633void Instrument::VisitCrypto2RegSHA(const Instruction* instr) {
634  USE(instr);
635  Update();
636  static Counter* counter = GetCounter("Crypto");
637  counter->Increment();
638}
639
640
641void Instrument::VisitCrypto3RegSHA(const Instruction* instr) {
642  USE(instr);
643  Update();
644  static Counter* counter = GetCounter("Crypto");
645  counter->Increment();
646}
647
648
649void Instrument::VisitCryptoAES(const Instruction* instr) {
650  USE(instr);
651  Update();
652  static Counter* counter = GetCounter("Crypto");
653  counter->Increment();
654}
655
656
657void Instrument::VisitNEON2RegMisc(const Instruction* instr) {
658  USE(instr);
659  Update();
660  static Counter* counter = GetCounter("NEON");
661  counter->Increment();
662}
663
664
665void Instrument::VisitNEON3Same(const Instruction* instr) {
666  USE(instr);
667  Update();
668  static Counter* counter = GetCounter("NEON");
669  counter->Increment();
670}
671
672
673void Instrument::VisitNEON3Different(const Instruction* instr) {
674  USE(instr);
675  Update();
676  static Counter* counter = GetCounter("NEON");
677  counter->Increment();
678}
679
680
681void Instrument::VisitNEONAcrossLanes(const Instruction* instr) {
682  USE(instr);
683  Update();
684  static Counter* counter = GetCounter("NEON");
685  counter->Increment();
686}
687
688
689void Instrument::VisitNEONByIndexedElement(const Instruction* instr) {
690  USE(instr);
691  Update();
692  static Counter* counter = GetCounter("NEON");
693  counter->Increment();
694}
695
696
697void Instrument::VisitNEONCopy(const Instruction* instr) {
698  USE(instr);
699  Update();
700  static Counter* counter = GetCounter("NEON");
701  counter->Increment();
702}
703
704
705void Instrument::VisitNEONExtract(const Instruction* instr) {
706  USE(instr);
707  Update();
708  static Counter* counter = GetCounter("NEON");
709  counter->Increment();
710}
711
712
713void Instrument::VisitNEONLoadStoreMultiStruct(const Instruction* instr) {
714  USE(instr);
715  Update();
716  static Counter* counter = GetCounter("NEON");
717  counter->Increment();
718}
719
720
721void Instrument::VisitNEONLoadStoreMultiStructPostIndex(
722    const Instruction* instr) {
723  USE(instr);
724  Update();
725  static Counter* counter = GetCounter("NEON");
726  counter->Increment();
727}
728
729
730void Instrument::VisitNEONLoadStoreSingleStruct(const Instruction* instr) {
731  USE(instr);
732  Update();
733  static Counter* counter = GetCounter("NEON");
734  counter->Increment();
735}
736
737
738void Instrument::VisitNEONLoadStoreSingleStructPostIndex(
739    const Instruction* instr) {
740  USE(instr);
741  Update();
742  static Counter* counter = GetCounter("NEON");
743  counter->Increment();
744}
745
746
747void Instrument::VisitNEONModifiedImmediate(const Instruction* instr) {
748  USE(instr);
749  Update();
750  static Counter* counter = GetCounter("NEON");
751  counter->Increment();
752}
753
754
755void Instrument::VisitNEONScalar2RegMisc(const Instruction* instr) {
756  USE(instr);
757  Update();
758  static Counter* counter = GetCounter("NEON");
759  counter->Increment();
760}
761
762
763void Instrument::VisitNEONScalar3Diff(const Instruction* instr) {
764  USE(instr);
765  Update();
766  static Counter* counter = GetCounter("NEON");
767  counter->Increment();
768}
769
770
771void Instrument::VisitNEONScalar3Same(const Instruction* instr) {
772  USE(instr);
773  Update();
774  static Counter* counter = GetCounter("NEON");
775  counter->Increment();
776}
777
778
779void Instrument::VisitNEONScalarByIndexedElement(const Instruction* instr) {
780  USE(instr);
781  Update();
782  static Counter* counter = GetCounter("NEON");
783  counter->Increment();
784}
785
786
787void Instrument::VisitNEONScalarCopy(const Instruction* instr) {
788  USE(instr);
789  Update();
790  static Counter* counter = GetCounter("NEON");
791  counter->Increment();
792}
793
794
795void Instrument::VisitNEONScalarPairwise(const Instruction* instr) {
796  USE(instr);
797  Update();
798  static Counter* counter = GetCounter("NEON");
799  counter->Increment();
800}
801
802
803void Instrument::VisitNEONScalarShiftImmediate(const Instruction* instr) {
804  USE(instr);
805  Update();
806  static Counter* counter = GetCounter("NEON");
807  counter->Increment();
808}
809
810
811void Instrument::VisitNEONShiftImmediate(const Instruction* instr) {
812  USE(instr);
813  Update();
814  static Counter* counter = GetCounter("NEON");
815  counter->Increment();
816}
817
818
819void Instrument::VisitNEONTable(const Instruction* instr) {
820  USE(instr);
821  Update();
822  static Counter* counter = GetCounter("NEON");
823  counter->Increment();
824}
825
826
827void Instrument::VisitNEONPerm(const Instruction* instr) {
828  USE(instr);
829  Update();
830  static Counter* counter = GetCounter("NEON");
831  counter->Increment();
832}
833
834
835void Instrument::VisitUnallocated(const Instruction* instr) {
836  USE(instr);
837  Update();
838  static Counter* counter = GetCounter("Other");
839  counter->Increment();
840}
841
842
843void Instrument::VisitUnimplemented(const Instruction* instr) {
844  USE(instr);
845  Update();
846  static Counter* counter = GetCounter("Other");
847  counter->Increment();
848}
849
850
851}  // namespace vixl
852