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