OLD | NEW |
| (Empty) |
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 "a64/instrument-a64.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 | |
40 void Counter::Enable() { | |
41 enabled_ = true; | |
42 } | |
43 | |
44 | |
45 void Counter::Disable() { | |
46 enabled_ = false; | |
47 } | |
48 | |
49 | |
50 bool Counter::IsEnabled() { | |
51 return enabled_; | |
52 } | |
53 | |
54 | |
55 void Counter::Increment() { | |
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 | |
77 CounterType Counter::type() { | |
78 return type_; | |
79 } | |
80 | |
81 | |
82 typedef struct { | |
83 const char* name; | |
84 CounterType type; | |
85 } CounterDescriptor; | |
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 | |
150 Instrument::~Instrument() { | |
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 | |
OLD | NEW |