OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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/compiler/basic-block-profiler.h" | |
6 #include "src/compiler/common-operator.h" | |
7 #include "src/compiler/graph.h" | |
8 #include "src/compiler/machine-operator.h" | |
9 #include "src/compiler/operator-properties-inl.h" | |
10 #include "src/compiler/schedule.h" | |
11 #include "src/global-handles.h" | |
12 | |
13 namespace v8 { | |
14 namespace internal { | |
15 namespace compiler { | |
16 | |
17 BasicBlockProfiler::Data::Data(int n_blocks, int* block_ids, uint32_t* counts, | |
titzer
2014/09/23 14:14:09
Can you make the constructor allocate the block_id
| |
18 OStringStream* function_name, | |
19 OStringStream* schedule_stream) | |
20 : n_blocks_(n_blocks), | |
21 block_ids_(block_ids), | |
22 counts_(counts), | |
23 function_name_(function_name), | |
24 schedule_stream_(schedule_stream), | |
25 code_stream_(NULL) {} | |
26 | |
27 | |
28 BasicBlockProfiler::Data::~Data() { | |
29 delete[] block_ids_; | |
30 delete[] counts_; | |
31 delete function_name_; | |
32 delete schedule_stream_; | |
33 delete code_stream_; | |
34 } | |
35 | |
36 | |
37 void BasicBlockProfiler::Data::SetCode(Handle<Code> code) { | |
38 DCHECK_EQ(NULL, code_stream_); | |
39 #if ENABLE_DISASSEMBLER | |
40 // TODO(dcarney): reenable this once code printing is fixed. | |
titzer
2014/09/23 14:14:09
What's broken with code printing?
| |
41 // code_stream_ = new OStringStream(); | |
42 // code->Disassemble(NULL, *code_stream_); | |
43 #endif | |
44 } | |
45 | |
46 | |
47 void BasicBlockProfiler::Data::DumpProfilingData() { | |
titzer
2014/09/23 14:14:09
Can you use OFStream here? It seems to be the way
| |
48 const char* name = "unknown function"; | |
49 if (function_name_ != NULL) { | |
50 name = function_name_->c_str(); | |
51 } | |
52 fprintf(stderr, "schedule for %s:\n", name); | |
53 if (schedule_stream_ != NULL) { | |
54 fprintf(stderr, "%s\n", schedule_stream_->c_str()); | |
55 } | |
56 fprintf(stderr, "block counts for %s:\n", name); | |
57 for (int i = 0; i < n_blocks_; ++i) { | |
58 fprintf(stderr, "block %d : %u\n", block_ids_[i], counts_[i]); | |
59 } | |
60 fprintf(stderr, "\n"); | |
61 if (code_stream_ != NULL) { | |
62 fprintf(stderr, "%s\n", code_stream_->c_str()); | |
63 } | |
64 } | |
65 | |
66 | |
67 void BasicBlockProfiler::Data::ResetCounts() { | |
68 for (int i = 0; i < n_blocks_; ++i) { | |
69 counts_[i] = 0; | |
70 } | |
71 } | |
72 | |
73 | |
74 BasicBlockProfiler::BasicBlockProfiler() {} | |
75 | |
76 | |
77 BasicBlockProfiler::~BasicBlockProfiler() { | |
78 DumpProfilingData(); | |
79 TearDown(); | |
80 } | |
81 | |
82 | |
83 void BasicBlockProfiler::TearDown() { | |
84 for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) { | |
85 delete (*i); | |
86 } | |
87 data_list_.clear(); | |
88 } | |
89 | |
90 | |
91 void BasicBlockProfiler::ResetCounts() { | |
92 for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) { | |
93 (*i)->ResetCounts(); | |
94 } | |
95 } | |
96 | |
97 | |
98 void BasicBlockProfiler::DumpProfilingData() { | |
99 fprintf(stderr, "---- Start Profiling Data ----\n"); | |
100 for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) { | |
101 (*i)->DumpProfilingData(); | |
102 } | |
103 fprintf(stderr, "---- End Profiling Data ----\n"); | |
104 } | |
105 | |
106 | |
107 BasicBlockProfiler::Data* BasicBlockProfiler::Profile(CompilationInfo* info, | |
108 Graph* graph, | |
109 Schedule* schedule) { | |
110 OStringStream* schedule_stream = new OStringStream(); | |
111 (*schedule_stream) << *schedule; | |
112 int n_blocks = schedule->RpoBlockCount(); | |
113 // Create a backing store for the count data. | |
114 uint32_t* counts = new uint32_t[n_blocks]; | |
115 for (int i = 0; i < n_blocks; ++i) { | |
116 counts[i] = 0; | |
117 } | |
118 // Add the increment instructions to the start of every block. | |
119 CommonOperatorBuilder common(graph->zone()); | |
120 intptr_t base_address = reinterpret_cast<intptr_t>(counts); | |
121 // TODO(dcarney): need to mark code as non-serializable. | |
122 const Operator* base_op = | |
123 kPointerSize == 8 ? common.Int64Constant(base_address) | |
124 : common.Int32Constant(static_cast<int>(base_address)); | |
125 Node* base = graph->NewNode(base_op); | |
126 Node* one = graph->NewNode(common.Int32Constant(1)); | |
127 MachineOperatorBuilder machine; | |
128 StoreRepresentation representation(kMachUint32, kNoWriteBarrier); | |
129 const Operator* load_op = machine.Load(kMachUint32); | |
130 const Operator* store_op = machine.Store(representation); | |
131 const Operator* add_op = machine.Int32Add(); | |
132 BasicBlockVector* blocks = schedule->rpo_order(); | |
133 int block_number = 0; | |
134 int* block_ids = new int[n_blocks]; | |
135 for (BasicBlockVector::iterator it = blocks->begin(); it != blocks->end(); | |
136 ++it, ++block_number) { | |
137 BasicBlock* block = (*it); | |
138 block_ids[block_number] = block->id(); | |
titzer
2014/09/23 14:14:09
Pull the body of this loop out into its own functi
| |
139 // Construct increment operation. | |
140 int index_value = sizeof(counts[0]) * block_number; | |
141 Node* index = graph->NewNode(common.Int32Constant(index_value)); | |
142 // TODO(dcarney): wire effect and control deps for load and store. | |
143 Node* load = graph->NewNode(load_op, base, index); | |
144 Node* inc = graph->NewNode(add_op, load, one); | |
145 Node* store = graph->NewNode(store_op, base, index, inc); | |
146 // skip parameters and phis when inserting. | |
147 NodeVector& nodes = block->nodes_; | |
148 NodeVector::iterator j = nodes.begin(); | |
149 for (; j != nodes.end(); ++j) { | |
150 const Operator* op = (*j)->op(); | |
151 if (OperatorProperties::IsBasicBlockBegin(op)) continue; | |
152 switch (op->opcode()) { | |
153 case IrOpcode::kParameter: | |
154 case IrOpcode::kPhi: | |
155 case IrOpcode::kEffectPhi: | |
156 continue; | |
157 } | |
158 break; | |
159 } | |
160 static const int kArraySize = 6; | |
161 Node* to_insert[kArraySize] = {base, one, index, load, inc, store}; | |
162 int insertion_start = block_number == 0 ? 0 : 2; | |
163 nodes.insert(j, &to_insert[insertion_start], &to_insert[kArraySize]); | |
164 for (int j = insertion_start; j < kArraySize; ++j) { | |
165 schedule->SetBlockForNode(block, to_insert[j]); | |
166 } | |
167 } | |
168 OStringStream* function_name = NULL; | |
169 if (!info->shared_info().is_null() && | |
170 info->shared_info()->name()->IsString()) { | |
171 function_name = new OStringStream(); | |
172 String::cast(info->shared_info()->name())->PrintUC16(*function_name); | |
173 } | |
174 Data* data = | |
175 new Data(n_blocks, block_ids, counts, function_name, schedule_stream); | |
176 data_list_.push_back(data); | |
177 return data; | |
178 } | |
179 | |
180 } // namespace compiler | |
181 } // namespace internal | |
182 } // namespace v8 | |
OLD | NEW |