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 : // This file declares the HeatMapSimulation class.
16 :
17 :
18 : #ifndef SYZYGY_SIMULATE_HEAT_MAP_SIMULATION_H_
19 : #define SYZYGY_SIMULATE_HEAT_MAP_SIMULATION_H_
20 :
21 : #include <map>
22 :
23 : #include "base/strings/string_piece.h"
24 : #include "syzygy/core/json_file_writer.h"
25 : #include "syzygy/simulate/simulation_event_handler.h"
26 : #include "syzygy/trace/parse/parser.h"
27 :
28 : namespace simulate {
29 :
30 : // An implementation of SimulationEventHandler.
31 : // HeatMapSimulation parses trace events, gathers the code blocks from them,
32 : // and organizes those by the number of times each memory slice of a given
33 : // size, in bytes, was called during a time slice of a given size,
34 : // in microseconds.
35 : //
36 : // HeatMapSimulation simulation;
37 : //
38 : // simulation.set_time_slice_usecs(5);
39 : // simulation.set_memory_slice_bytes(0x4000);
40 : // simulation.OnProcessStarted(time, 0);
41 : // simulation.OnFunctionEntry(times[0], 0, 5);
42 : // simulation.OnFunctionEntry(times[1], 3, 200);
43 : // simulation.SerializeToJSON(file, pretty_print);
44 : //
45 : // If the time slice size or the memory slice size are not set, the default
46 : // values of 1 and 0x8000, respectively, are used.
47 : class HeatMapSimulation : public SimulationEventHandler {
48 : public:
49 : class TimeSlice;
50 :
51 : typedef block_graph::BlockGraph::Block Block;
52 : typedef time_t TimeSliceId;
53 : typedef std::map<TimeSliceId, TimeSlice> TimeMemoryMap;
54 : typedef uint32 MemorySliceId;
55 :
56 : // The default time and memory slice sizes.
57 : static const uint32 kDefaultTimeSliceSize = 1;
58 : static const uint32 kDefaultMemorySliceSize = 0x8000;
59 :
60 : // Construct a new HeatMapSimulation instance.
61 : HeatMapSimulation();
62 :
63 : // @name Accessors.
64 : // @{
65 E : const TimeMemoryMap& time_memory_map() const { return time_memory_map_; }
66 : uint32 time_slice_usecs() const { return time_slice_usecs_; }
67 : uint32 memory_slice_bytes() const { return memory_slice_bytes_; }
68 E : TimeSliceId max_time_slice_usecs() const { return max_time_slice_usecs_; }
69 E : MemorySliceId max_memory_slice_bytes() const {
70 E : return max_memory_slice_bytes_;
71 E : }
72 : // @}
73 :
74 : // @name Mutators.
75 : // @{
76 : // Set the size of time slices used in the heat map.
77 : // @param time_slice_usecs The size used, in microseconds.
78 E : void set_time_slice_usecs(uint32 time_slice_usecs) {
79 E : DCHECK_LT(0u, time_slice_usecs);
80 E : time_slice_usecs_ = time_slice_usecs;
81 E : }
82 : // Set the size of the memory slices used in the heat map.
83 : // @param memory_slice_bytes The size used, in bytes.
84 E : void set_memory_slice_bytes(uint32 memory_slice_bytes) {
85 E : DCHECK_LT(0u, memory_slice_bytes);
86 E : memory_slice_bytes_ = memory_slice_bytes;
87 E : }
88 : // Set whether SerializeToJSON outputs information about each individual
89 : // function in each time/memory block.
90 : // @param print_output_individual_functions true for saving the names of each
91 : // function, false otherwise.
92 E : void set_output_individual_functions(bool output_individual_functions) {
93 E : output_individual_functions_ = output_individual_functions;
94 E : }
95 : // @}
96 :
97 : // @name SimulationEventHandler implementation
98 : // @{
99 : // Sets the entry time of the trace file.
100 : // @param time The startup time of the execution.
101 : void OnProcessStarted(base::Time time, size_t default_page_size) override;
102 :
103 : // Adds a group of code blocks corresponding to one function
104 : // to time_memory_map_.
105 : // @param time The entry time of the function.
106 : // @param block_start The start start of the function.
107 : // @param size The size of the function.
108 : void OnFunctionEntry(base::Time time, const Block* block) override;
109 :
110 : // Serializes the data to JSON.
111 : // The serialization consists of a list containing a dictionary of each
112 : // timestamp, and the total number of memory slices used, during that
113 : // time slice, and of another list with dictionaries containing each
114 : // separate memory slice, the number of times it was used, and a list
115 : // of all the used functions and the number of times they were used in that
116 : // memory slice in descending order. If output_individual_functions is true,
117 : // then the list of function for each memory slice isn't printed. Example:
118 : // {
119 : // "time_slice_usecs": 1,
120 : // "memory_slice_bytes": 32768,
121 : // "time_slice_list": [
122 : // {
123 : // "timestamp": 31,
124 : // "total_memory_slices": 1052,
125 : // "memory_slice_list": [
126 : // {
127 : // "memory_slice": 4,
128 : // "quantity": 978,
129 : // "functions": [
130 : // {
131 : // "name": "_flush",
132 : // "quantity": 561
133 : // },
134 : // {
135 : // "name": "flsall",
136 : // "quantity": 417
137 : // }
138 : // ]
139 : // },
140 : // {
141 : // "memory_slice": 13,
142 : // "quantity": 74,
143 : // "functions": [
144 : // {
145 : // "name": "_RTC_Terminate",
146 : // "quantity": 38
147 : // },
148 : // {
149 : // "name": "_CrtDefaultAllocHook",
150 : // "quantity": 36
151 : // }
152 : // ]
153 : // }
154 : // ]
155 : // },
156 : // {
157 : // "timestamp": 33,
158 : // "total_memory_slices": 105,
159 : // "memory_slice_list": [
160 : // {
161 : // "memory_slice": 0,
162 : // "quantity": 105,
163 : // "functions": [
164 : // {
165 : // "name": "rand",
166 : // "quantity": 105
167 : // }
168 : // ]
169 : // }
170 : // ]
171 : // }
172 : // ]
173 : // }
174 : // @param output the file to be written to.
175 : // @param pretty_print enables or disables pretty printing.
176 : // @returns true on success, false on failure.
177 : bool SerializeToJSON(FILE* output, bool pretty_print);
178 : // @}
179 :
180 : protected:
181 : // The size of each time block on the heat map, in microseconds.
182 : uint32 time_slice_usecs_;
183 :
184 : // The size of each memory block on the heat map, in bytes.
185 : uint32 memory_slice_bytes_;
186 :
187 : // A map which contains the density of each pair of time and memory slices.
188 : // TODO(fixman): If there aren't many possible relative times,
189 : // this will probably be better off as a vector.
190 : TimeMemoryMap time_memory_map_;
191 :
192 : // The time when the process was started. Used to convert absolute function
193 : // entry times to relative times since start of process.
194 : base::Time process_start_time_;
195 :
196 : // The number of the last time and memory slice, respectively.
197 : TimeSliceId max_time_slice_usecs_;
198 : MemorySliceId max_memory_slice_bytes_;
199 :
200 : // If set to true, SerializeToJSON outputs information about each function
201 : // in each time/memory block. This gives more information and is useful
202 : // for analysis, but may make the output files excessively big.
203 : bool output_individual_functions_;
204 : };
205 :
206 : // Stores the respective memory slices of a particular time slice in a map.
207 : class HeatMapSimulation::TimeSlice {
208 : public:
209 : typedef std::map<std::string, uint32> FunctionMap;
210 :
211 : struct MemorySlice {
212 : FunctionMap functions;
213 : uint32 total;
214 :
215 E : MemorySlice() : total(0) {
216 E : }
217 : };
218 : typedef std::map<MemorySliceId, MemorySlice> MemorySliceMap;
219 :
220 E : TimeSlice() : total_(0) {
221 E : }
222 :
223 : // Add a quantity of bytes to a memory slice to the counter.
224 : // @param slice The relative code block number.
225 : // @param name The name of the function which uses the memory slice.
226 : // @param num_bytes The value to be added, in bytes.
227 : void AddSlice(MemorySliceId slice,
228 : const base::StringPiece& name,
229 E : uint32 num_bytes) {
230 E : slices_[slice].functions[name.as_string()] += num_bytes;
231 E : slices_[slice].total += num_bytes;
232 E : total_ += num_bytes;
233 E : }
234 :
235 : // @name Accessors.
236 : // @{
237 E : const MemorySliceMap& slices() const { return slices_; }
238 E : uint32 total() const { return total_; }
239 : // @}
240 :
241 : // Serialize a FunctionMap to a JSON file, sorted by bytes occupied by
242 : // each function.
243 : // @param json_file The file where the functions will be serialized.
244 : // @param functions The given functions.
245 : // @returns true on success, false on failure.
246 : static bool PrintJSONFunctions(core::JSONFileWriter& json_file,
247 : const FunctionMap& functions);
248 :
249 : protected:
250 : // The slices that were accumulated at this time, and how many times
251 : // they were called.
252 : MemorySliceMap slices_;
253 :
254 : // The total number of blocks that were called at this time.
255 : uint32 total_;
256 : };
257 :
258 : } // namespace simulate
259 :
260 : #endif // SYZYGY_SIMULATE_HEAT_MAP_SIMULATION_H_
|