1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/simulate/heat_map_simulation.h"
16 :
17 : namespace simulate {
18 :
19 : HeatMapSimulation::HeatMapSimulation()
20 : : time_slice_usecs_(kDefaultTimeSliceSize),
21 : memory_slice_bytes_(kDefaultMemorySliceSize),
22 : max_time_slice_usecs_(0),
23 : max_memory_slice_bytes_(0),
24 E : output_individual_functions_(false) {
25 E : }
26 :
27 : bool HeatMapSimulation::TimeSlice::PrintJSONFunctions(
28 : core::JSONFileWriter& json_file,
29 i : const HeatMapSimulation::TimeSlice::FunctionMap& functions) {
30 : typedef std::pair<uint32, base::StringPiece> QtyNamePair;
31 i : std::vector<QtyNamePair> ordered_functions(functions.size());
32 :
33 i : FunctionMap::const_iterator functions_iter = functions.begin();
34 i : uint32 i = 0;
35 i : for (; functions_iter != functions.end(); ++functions_iter, ++i) {
36 : ordered_functions[i] = QtyNamePair(functions_iter->second,
37 i : functions_iter->first);
38 i : }
39 : std::sort(ordered_functions.begin(),
40 : ordered_functions.end(),
41 i : std::greater<QtyNamePair>());
42 :
43 : if (!json_file.OutputKey("functions") ||
44 i : !json_file.OpenList())
45 i : return false;
46 :
47 i : for (uint32 i = 0; i < ordered_functions.size(); ++i) {
48 : if (!json_file.OpenDict() ||
49 : !json_file.OutputKey("name") ||
50 : !json_file.OutputString(ordered_functions[i].second.data()) ||
51 : !json_file.OutputKey("quantity") ||
52 : !json_file.OutputInteger(ordered_functions[i].first) ||
53 i : !json_file.CloseDict())
54 i : return false;
55 i : }
56 :
57 i : if (!json_file.CloseList())
58 i : return false;
59 :
60 i : return true;
61 i : }
62 :
63 i : bool HeatMapSimulation::SerializeToJSON(FILE* output, bool pretty_print) {
64 : typedef TimeSlice::FunctionMap FunctionMap;
65 :
66 i : DCHECK(output != NULL);
67 :
68 i : core::JSONFileWriter json_file(output, pretty_print);
69 :
70 : if (!json_file.OpenDict() ||
71 : !json_file.OutputKey("time_slice_usecs") ||
72 : !json_file.OutputInteger(time_slice_usecs_) ||
73 : !json_file.OutputKey("memory_slice_bytes") ||
74 : !json_file.OutputInteger(memory_slice_bytes_) ||
75 : !json_file.OutputKey("max_time_slice_usecs") ||
76 : !json_file.OutputInteger(max_time_slice_usecs_) ||
77 : !json_file.OutputKey("max_memory_slice_bytes") ||
78 : !json_file.OutputInteger(max_memory_slice_bytes_) ||
79 : !json_file.OutputKey("time_slice_list") ||
80 i : !json_file.OpenList()) {
81 i : return false;
82 : }
83 :
84 i : TimeMemoryMap::const_iterator time_memory_iter = time_memory_map_.begin();
85 i : for (; time_memory_iter != time_memory_map_.end(); ++time_memory_iter) {
86 i : time_t time = time_memory_iter->first;
87 i : uint32 total = time_memory_iter->second.total();
88 i : const TimeSlice& time_slice = time_memory_iter->second;
89 :
90 : if (!json_file.OpenDict() ||
91 : !json_file.OutputKey("timestamp") ||
92 : !json_file.OutputInteger(time) ||
93 : !json_file.OutputKey("total_memory_slices") ||
94 : !json_file.OutputInteger(total) ||
95 : !json_file.OutputKey("memory_slice_list") ||
96 i : !json_file.OpenList()) {
97 i : return false;
98 : }
99 :
100 : TimeSlice::MemorySliceMap::const_iterator slices_iter =
101 i : time_slice.slices().begin();
102 :
103 i : for (; slices_iter != time_slice.slices().end(); ++slices_iter) {
104 : if (!json_file.OpenDict() ||
105 : !json_file.OutputKey("memory_slice") ||
106 : !json_file.OutputInteger(slices_iter->first) ||
107 : !json_file.OutputKey("quantity") ||
108 i : !json_file.OutputInteger(slices_iter->second.total))
109 i : return false;
110 :
111 i : if (output_individual_functions_) {
112 : if (!TimeSlice::PrintJSONFunctions(json_file,
113 i : slices_iter->second.functions))
114 i : return false;
115 : }
116 :
117 i : if (!json_file.CloseDict())
118 i : return false;
119 i : }
120 :
121 : if (!json_file.CloseList() ||
122 i : !json_file.CloseDict())
123 i : return false;
124 i : }
125 :
126 : if (!json_file.CloseList() ||
127 i : !json_file.CloseDict())
128 i : return false;
129 :
130 i : return json_file.Finished();
131 i : }
132 :
133 : void HeatMapSimulation::OnProcessStarted(base::Time time,
134 E : size_t /*default_page_size*/) {
135 : // Set the entry time of this process.
136 E : process_start_time_ = time;
137 E : }
138 :
139 : void HeatMapSimulation::OnFunctionEntry(base::Time time,
140 E : const Block* block) {
141 : // Get the time when this function was called since the process start.
142 E : time_t relative_time = (time - process_start_time_).InMicroseconds();
143 :
144 : // Since we will insert to a map many TimeSlices with the same entry time,
145 : // we can pass RegisterFunction a reference to the TimeSlice in the map.
146 : // This way, RegisterFunction doesn't have to search for that position
147 : // every time it gets called and the time complexity gets reduced
148 : // in a logarithmic scale.
149 E : TimeSliceId time_slice = relative_time / time_slice_usecs_;
150 E : TimeSlice& slice = time_memory_map_[time_slice];
151 :
152 E : max_time_slice_usecs_ = std::max(max_time_slice_usecs_, time_slice);
153 :
154 E : DCHECK(block != NULL);
155 E : DCHECK(memory_slice_bytes_ != 0);
156 E : const uint32 block_start = block->addr().value();
157 E : const uint32 size = block->size();
158 E : const std::string& name = block->name();
159 :
160 E : const uint32 first_slice = block_start / memory_slice_bytes_;
161 E : const uint32 last_slice = (block_start + size - 1) / memory_slice_bytes_;
162 E : if (first_slice == last_slice) {
163 : // This function fits in a single memory slice. Add it to our time slice.
164 E : slice.AddSlice(first_slice, name, size);
165 E : } else {
166 : // This function takes several memory slices. Add the first and last
167 : // slices to our time slice only with the part of the slice they use,
168 : // and then loop through the rest and add the whole slices.
169 : const uint32 leading_bytes =
170 E : memory_slice_bytes_ - block_start % memory_slice_bytes_;
171 :
172 : const uint32 trailing_bytes =
173 : ((block_start + size - 1 + memory_slice_bytes_) %
174 E : memory_slice_bytes_) + 1;
175 :
176 E : slice.AddSlice(first_slice, name, leading_bytes);
177 E : slice.AddSlice(last_slice, name, trailing_bytes);
178 :
179 E : const uint32 kStartIndex = block_start / memory_slice_bytes_ + 1;
180 E : const uint32 kEndIndex = (block_start + size - 1) / memory_slice_bytes_;
181 :
182 E : for (uint32 i = kStartIndex; i < kEndIndex; i++)
183 E : slice.AddSlice(i, name, memory_slice_bytes_);
184 : }
185 :
186 E : max_memory_slice_bytes_ = std::max(max_memory_slice_bytes_, last_slice);
187 E : }
188 :
189 : } // namespace simulate
|