Chromium Code Reviews| 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 |