v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
instrument-arm64.cc
Go to the documentation of this file.
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "arm64/instrument-arm64.h"
29 
30 namespace v8 {
31 namespace internal {
32 
33 Counter::Counter(const char* name, CounterType type)
34  : count_(0), enabled_(false), type_(type) {
35  ASSERT(name != NULL);
36  strncpy(name_, name, kCounterNameMaxLength);
37 }
38 
39 
41  enabled_ = true;
42 }
43 
44 
46  enabled_ = false;
47 }
48 
49 
51  return enabled_;
52 }
53 
54 
56  if (enabled_) {
57  count_++;
58  }
59 }
60 
61 
62 uint64_t Counter::count() {
63  uint64_t result = count_;
64  if (type_ == Gauge) {
65  // If the counter is a Gauge, reset the count after reading.
66  count_ = 0;
67  }
68  return result;
69 }
70 
71 
72 const char* Counter::name() {
73  return name_;
74 }
75 
76 
78  return type_;
79 }
80 
81 
82 typedef struct {
83  const char* name;
86 
87 
88 static const CounterDescriptor kCounterList[] = {
89  {"Instruction", Cumulative},
90 
91  {"Move Immediate", Gauge},
92  {"Add/Sub DP", Gauge},
93  {"Logical DP", Gauge},
94  {"Other Int DP", Gauge},
95  {"FP DP", Gauge},
96 
97  {"Conditional Select", Gauge},
98  {"Conditional Compare", Gauge},
99 
100  {"Unconditional Branch", Gauge},
101  {"Compare and Branch", Gauge},
102  {"Test and Branch", Gauge},
103  {"Conditional Branch", Gauge},
104 
105  {"Load Integer", Gauge},
106  {"Load FP", Gauge},
107  {"Load Pair", Gauge},
108  {"Load Literal", Gauge},
109 
110  {"Store Integer", Gauge},
111  {"Store FP", Gauge},
112  {"Store Pair", Gauge},
113 
114  {"PC Addressing", Gauge},
115  {"Other", Gauge},
116  {"SP Adjust", Gauge},
117 };
118 
119 
120 Instrument::Instrument(const char* datafile, uint64_t sample_period)
121  : output_stream_(stderr), sample_period_(sample_period) {
122 
123  // Set up the output stream. If datafile is non-NULL, use that file. If it
124  // can't be opened, or datafile is NULL, use stderr.
125  if (datafile != NULL) {
126  output_stream_ = fopen(datafile, "w");
127  if (output_stream_ == NULL) {
128  fprintf(stderr, "Can't open output file %s. Using stderr.\n", datafile);
129  output_stream_ = stderr;
130  }
131  }
132 
133  static const int num_counters =
134  sizeof(kCounterList) / sizeof(CounterDescriptor);
135 
136  // Dump an instrumentation description comment at the top of the file.
137  fprintf(output_stream_, "# counters=%d\n", num_counters);
138  fprintf(output_stream_, "# sample_period=%" PRIu64 "\n", sample_period_);
139 
140  // Construct Counter objects from counter description array.
141  for (int i = 0; i < num_counters; i++) {
142  Counter* counter = new Counter(kCounterList[i].name, kCounterList[i].type);
143  counters_.push_back(counter);
144  }
145 
146  DumpCounterNames();
147 }
148 
149 
151  // Dump any remaining instruction data to the output file.
152  DumpCounters();
153 
154  // Free all the counter objects.
155  std::list<Counter*>::iterator it;
156  for (it = counters_.begin(); it != counters_.end(); it++) {
157  delete *it;
158  }
159 
160  if (output_stream_ != stderr) {
161  fclose(output_stream_);
162  }
163 }
164 
165 
166 void Instrument::Update() {
167  // Increment the instruction counter, and dump all counters if a sample period
168  // has elapsed.
169  static Counter* counter = GetCounter("Instruction");
170  ASSERT(counter->type() == Cumulative);
171  counter->Increment();
172 
173  if (counter->IsEnabled() && (counter->count() % sample_period_) == 0) {
174  DumpCounters();
175  }
176 }
177 
178 
179 void 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 
191 void 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 
203 void 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 
212 void 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 
222 Counter* 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 
241 void Instrument::Enable() {
242  std::list<Counter*>::iterator it;
243  for (it = counters_.begin(); it != counters_.end(); it++) {
244  (*it)->Enable();
245  }
246 }
247 
248 
249 void Instrument::Disable() {
250  std::list<Counter*>::iterator it;
251  for (it = counters_.begin(); it != counters_.end(); it++) {
252  (*it)->Disable();
253  }
254 }
255 
256 
257 void Instrument::VisitPCRelAddressing(Instruction* instr) {
258  Update();
259  static Counter* counter = GetCounter("PC Addressing");
260  counter->Increment();
261 }
262 
263 
264 void Instrument::VisitAddSubImmediate(Instruction* instr) {
265  Update();
266  static Counter* sp_counter = GetCounter("SP Adjust");
267  static Counter* add_sub_counter = GetCounter("Add/Sub DP");
268  if (((instr->Mask(AddSubOpMask) == SUB) ||
269  (instr->Mask(AddSubOpMask) == ADD)) &&
270  (instr->Rd() == 31) && (instr->Rn() == 31)) {
271  // Count adjustments to the C stack pointer caused by V8 needing two SPs.
272  sp_counter->Increment();
273  } else {
274  add_sub_counter->Increment();
275  }
276 }
277 
278 
279 void Instrument::VisitLogicalImmediate(Instruction* instr) {
280  Update();
281  static Counter* counter = GetCounter("Logical DP");
282  counter->Increment();
283 }
284 
285 
286 void Instrument::VisitMoveWideImmediate(Instruction* instr) {
287  Update();
288  static Counter* counter = GetCounter("Move Immediate");
289 
290  if (instr->IsMovn() && (instr->Rd() == kZeroRegCode)) {
291  unsigned imm = instr->ImmMoveWide();
292  HandleInstrumentationEvent(imm);
293  } else {
294  counter->Increment();
295  }
296 }
297 
298 
299 void Instrument::VisitBitfield(Instruction* instr) {
300  Update();
301  static Counter* counter = GetCounter("Other Int DP");
302  counter->Increment();
303 }
304 
305 
306 void Instrument::VisitExtract(Instruction* instr) {
307  Update();
308  static Counter* counter = GetCounter("Other Int DP");
309  counter->Increment();
310 }
311 
312 
313 void Instrument::VisitUnconditionalBranch(Instruction* instr) {
314  Update();
315  static Counter* counter = GetCounter("Unconditional Branch");
316  counter->Increment();
317 }
318 
319 
320 void Instrument::VisitUnconditionalBranchToRegister(Instruction* instr) {
321  Update();
322  static Counter* counter = GetCounter("Unconditional Branch");
323  counter->Increment();
324 }
325 
326 
327 void Instrument::VisitCompareBranch(Instruction* instr) {
328  Update();
329  static Counter* counter = GetCounter("Compare and Branch");
330  counter->Increment();
331 }
332 
333 
334 void Instrument::VisitTestBranch(Instruction* instr) {
335  Update();
336  static Counter* counter = GetCounter("Test and Branch");
337  counter->Increment();
338 }
339 
340 
341 void Instrument::VisitConditionalBranch(Instruction* instr) {
342  Update();
343  static Counter* counter = GetCounter("Conditional Branch");
344  counter->Increment();
345 }
346 
347 
348 void Instrument::VisitSystem(Instruction* instr) {
349  Update();
350  static Counter* counter = GetCounter("Other");
351  counter->Increment();
352 }
353 
354 
355 void Instrument::VisitException(Instruction* instr) {
356  Update();
357  static Counter* counter = GetCounter("Other");
358  counter->Increment();
359 }
360 
361 
362 void Instrument::InstrumentLoadStorePair(Instruction* instr) {
363  static Counter* load_pair_counter = GetCounter("Load Pair");
364  static Counter* store_pair_counter = GetCounter("Store Pair");
365  if (instr->Mask(LoadStorePairLBit) != 0) {
366  load_pair_counter->Increment();
367  } else {
368  store_pair_counter->Increment();
369  }
370 }
371 
372 
373 void Instrument::VisitLoadStorePairPostIndex(Instruction* instr) {
374  Update();
375  InstrumentLoadStorePair(instr);
376 }
377 
378 
379 void Instrument::VisitLoadStorePairOffset(Instruction* instr) {
380  Update();
381  InstrumentLoadStorePair(instr);
382 }
383 
384 
385 void Instrument::VisitLoadStorePairPreIndex(Instruction* instr) {
386  Update();
387  InstrumentLoadStorePair(instr);
388 }
389 
390 
391 void Instrument::VisitLoadStorePairNonTemporal(Instruction* instr) {
392  Update();
393  InstrumentLoadStorePair(instr);
394 }
395 
396 
397 void Instrument::VisitLoadLiteral(Instruction* instr) {
398  Update();
399  static Counter* counter = GetCounter("Load Literal");
400  counter->Increment();
401 }
402 
403 
404 void Instrument::InstrumentLoadStore(Instruction* instr) {
405  static Counter* load_int_counter = GetCounter("Load Integer");
406  static Counter* store_int_counter = GetCounter("Store Integer");
407  static Counter* load_fp_counter = GetCounter("Load FP");
408  static Counter* store_fp_counter = GetCounter("Store FP");
409 
410  switch (instr->Mask(LoadStoreOpMask)) {
411  case STRB_w: // Fall through.
412  case STRH_w: // Fall through.
413  case STR_w: // Fall through.
414  case STR_x: store_int_counter->Increment(); break;
415  case STR_s: // Fall through.
416  case STR_d: store_fp_counter->Increment(); break;
417  case LDRB_w: // Fall through.
418  case LDRH_w: // Fall through.
419  case LDR_w: // Fall through.
420  case LDR_x: // Fall through.
421  case LDRSB_x: // Fall through.
422  case LDRSH_x: // Fall through.
423  case LDRSW_x: // Fall through.
424  case LDRSB_w: // Fall through.
425  case LDRSH_w: load_int_counter->Increment(); break;
426  case LDR_s: // Fall through.
427  case LDR_d: load_fp_counter->Increment(); break;
428  default: UNREACHABLE();
429  }
430 }
431 
432 
433 void Instrument::VisitLoadStoreUnscaledOffset(Instruction* instr) {
434  Update();
435  InstrumentLoadStore(instr);
436 }
437 
438 
439 void Instrument::VisitLoadStorePostIndex(Instruction* instr) {
440  Update();
441  InstrumentLoadStore(instr);
442 }
443 
444 
445 void Instrument::VisitLoadStorePreIndex(Instruction* instr) {
446  Update();
447  InstrumentLoadStore(instr);
448 }
449 
450 
451 void Instrument::VisitLoadStoreRegisterOffset(Instruction* instr) {
452  Update();
453  InstrumentLoadStore(instr);
454 }
455 
456 
457 void Instrument::VisitLoadStoreUnsignedOffset(Instruction* instr) {
458  Update();
459  InstrumentLoadStore(instr);
460 }
461 
462 
463 void Instrument::VisitLogicalShifted(Instruction* instr) {
464  Update();
465  static Counter* counter = GetCounter("Logical DP");
466  counter->Increment();
467 }
468 
469 
470 void Instrument::VisitAddSubShifted(Instruction* instr) {
471  Update();
472  static Counter* counter = GetCounter("Add/Sub DP");
473  counter->Increment();
474 }
475 
476 
477 void Instrument::VisitAddSubExtended(Instruction* instr) {
478  Update();
479  static Counter* sp_counter = GetCounter("SP Adjust");
480  static Counter* add_sub_counter = GetCounter("Add/Sub DP");
481  if (((instr->Mask(AddSubOpMask) == SUB) ||
482  (instr->Mask(AddSubOpMask) == ADD)) &&
483  (instr->Rd() == 31) && (instr->Rn() == 31)) {
484  // Count adjustments to the C stack pointer caused by V8 needing two SPs.
485  sp_counter->Increment();
486  } else {
487  add_sub_counter->Increment();
488  }
489 }
490 
491 
492 void Instrument::VisitAddSubWithCarry(Instruction* instr) {
493  Update();
494  static Counter* counter = GetCounter("Add/Sub DP");
495  counter->Increment();
496 }
497 
498 
499 void Instrument::VisitConditionalCompareRegister(Instruction* instr) {
500  Update();
501  static Counter* counter = GetCounter("Conditional Compare");
502  counter->Increment();
503 }
504 
505 
506 void Instrument::VisitConditionalCompareImmediate(Instruction* instr) {
507  Update();
508  static Counter* counter = GetCounter("Conditional Compare");
509  counter->Increment();
510 }
511 
512 
513 void Instrument::VisitConditionalSelect(Instruction* instr) {
514  Update();
515  static Counter* counter = GetCounter("Conditional Select");
516  counter->Increment();
517 }
518 
519 
520 void Instrument::VisitDataProcessing1Source(Instruction* instr) {
521  Update();
522  static Counter* counter = GetCounter("Other Int DP");
523  counter->Increment();
524 }
525 
526 
527 void Instrument::VisitDataProcessing2Source(Instruction* instr) {
528  Update();
529  static Counter* counter = GetCounter("Other Int DP");
530  counter->Increment();
531 }
532 
533 
534 void Instrument::VisitDataProcessing3Source(Instruction* instr) {
535  Update();
536  static Counter* counter = GetCounter("Other Int DP");
537  counter->Increment();
538 }
539 
540 
541 void Instrument::VisitFPCompare(Instruction* instr) {
542  Update();
543  static Counter* counter = GetCounter("FP DP");
544  counter->Increment();
545 }
546 
547 
548 void Instrument::VisitFPConditionalCompare(Instruction* instr) {
549  Update();
550  static Counter* counter = GetCounter("Conditional Compare");
551  counter->Increment();
552 }
553 
554 
555 void Instrument::VisitFPConditionalSelect(Instruction* instr) {
556  Update();
557  static Counter* counter = GetCounter("Conditional Select");
558  counter->Increment();
559 }
560 
561 
562 void Instrument::VisitFPImmediate(Instruction* instr) {
563  Update();
564  static Counter* counter = GetCounter("FP DP");
565  counter->Increment();
566 }
567 
568 
569 void Instrument::VisitFPDataProcessing1Source(Instruction* instr) {
570  Update();
571  static Counter* counter = GetCounter("FP DP");
572  counter->Increment();
573 }
574 
575 
576 void Instrument::VisitFPDataProcessing2Source(Instruction* instr) {
577  Update();
578  static Counter* counter = GetCounter("FP DP");
579  counter->Increment();
580 }
581 
582 
583 void Instrument::VisitFPDataProcessing3Source(Instruction* instr) {
584  Update();
585  static Counter* counter = GetCounter("FP DP");
586  counter->Increment();
587 }
588 
589 
590 void Instrument::VisitFPIntegerConvert(Instruction* instr) {
591  Update();
592  static Counter* counter = GetCounter("FP DP");
593  counter->Increment();
594 }
595 
596 
597 void Instrument::VisitFPFixedPointConvert(Instruction* instr) {
598  Update();
599  static Counter* counter = GetCounter("FP DP");
600  counter->Increment();
601 }
602 
603 
604 void Instrument::VisitUnallocated(Instruction* instr) {
605  Update();
606  static Counter* counter = GetCounter("Other");
607  counter->Increment();
608 }
609 
610 
611 void Instrument::VisitUnimplemented(Instruction* instr) {
612  Update();
613  static Counter* counter = GetCounter("Other");
614  counter->Increment();
615 }
616 
617 
618 } } // namespace v8::internal
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
Definition: flags.cc:269
const unsigned kZeroRegCode
#define ASSERT(condition)
Definition: checks.h:329
const int kCounterNameMaxLength
#define UNREACHABLE()
Definition: checks.h:52
Counter(const char *name, CounterType type=Gauge)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in name
Definition: flags.cc:505
Instrument(const char *datafile=NULL, uint64_t sample_period=kDefaultInstrumentationSamplingPeriod)