blob: 18265f12af1b3fd789db83bc80ec5424a2b15c7c [file] [log] [blame]
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001// Copyright 2010 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_PROFILE_GENERATOR_H_
29#define V8_PROFILE_GENERATOR_H_
30
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000031#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +000032
fschneider@chromium.org086aac62010-03-17 13:18:24 +000033#include "hashmap.h"
34
35namespace v8 {
36namespace internal {
37
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000038class TokenEnumerator {
39 public:
40 TokenEnumerator();
41 ~TokenEnumerator();
42 int GetTokenId(Object* token);
43
44 private:
45 static void TokenRemovedCallback(v8::Persistent<v8::Value> handle,
46 void* parameter);
47 void TokenRemoved(Object** token_location);
48
49 List<Object**> token_locations_;
50 List<bool> token_removed_;
51
52 friend class TokenEnumeratorTester;
53};
54
55
fschneider@chromium.org086aac62010-03-17 13:18:24 +000056class CodeEntry {
57 public:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000058 explicit INLINE(CodeEntry(int security_token_id));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000059 // CodeEntry doesn't own name strings, just references them.
lrn@chromium.org25156de2010-04-06 13:10:27 +000060 INLINE(CodeEntry(Logger::LogEventsAndTags tag,
61 const char* name_prefix,
62 const char* name,
63 const char* resource_name,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000064 int line_number,
65 int security_token_id));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000066
ager@chromium.org357bf652010-04-12 11:30:10 +000067 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
lrn@chromium.org25156de2010-04-06 13:10:27 +000068 INLINE(const char* name_prefix() const) { return name_prefix_; }
69 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; }
70 INLINE(const char* name() const) { return name_; }
71 INLINE(const char* resource_name() const) { return resource_name_; }
72 INLINE(int line_number() const) { return line_number_; }
ager@chromium.org357bf652010-04-12 11:30:10 +000073 INLINE(unsigned call_uid() const) { return call_uid_; }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000074 INLINE(int security_token_id() const) { return security_token_id_; }
ager@chromium.org357bf652010-04-12 11:30:10 +000075
76 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
lrn@chromium.org25156de2010-04-06 13:10:27 +000077
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000078 void CopyData(const CodeEntry& source);
79
lrn@chromium.org25156de2010-04-06 13:10:27 +000080 static const char* kEmptyNamePrefix;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000081 static const int kNoSecurityToken = -1;
82 static const int kInheritsSecurityToken = -2;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000083
84 private:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000085 unsigned call_uid_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000086 Logger::LogEventsAndTags tag_;
lrn@chromium.org25156de2010-04-06 13:10:27 +000087 const char* name_prefix_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000088 const char* name_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000089 const char* resource_name_;
90 int line_number_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000091 int security_token_id_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000092
ager@chromium.org357bf652010-04-12 11:30:10 +000093 static unsigned next_call_uid_;
94
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000095 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000096};
97
98
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000099class ProfileTree;
100
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000101class ProfileNode {
102 public:
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000103 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000104
105 ProfileNode* FindChild(CodeEntry* entry);
106 ProfileNode* FindOrAddChild(CodeEntry* entry);
107 INLINE(void IncrementSelfTicks()) { ++self_ticks_; }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000108 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000109 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; }
110
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000111 INLINE(CodeEntry* entry() const) { return entry_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000112 INLINE(unsigned self_ticks() const) { return self_ticks_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000113 INLINE(unsigned total_ticks() const) { return total_ticks_; }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000114 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000115 double GetSelfMillis() const;
116 double GetTotalMillis() const;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000117
118 void Print(int indent);
119
120 private:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000121 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) {
122 return entry1 == entry2;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000123 }
124
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000125 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000126 return static_cast<int32_t>(reinterpret_cast<intptr_t>(entry));
127 }
128
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000129 ProfileTree* tree_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000130 CodeEntry* entry_;
131 unsigned total_ticks_;
132 unsigned self_ticks_;
133 // CodeEntry* -> ProfileNode*
134 HashMap children_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000135 List<ProfileNode*> children_list_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000136
137 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
138};
139
140
lrn@chromium.org25156de2010-04-06 13:10:27 +0000141class ProfileTree {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000142 public:
ager@chromium.org357bf652010-04-12 11:30:10 +0000143 ProfileTree();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000144 ~ProfileTree();
145
146 void AddPathFromEnd(const Vector<CodeEntry*>& path);
147 void AddPathFromStart(const Vector<CodeEntry*>& path);
148 void CalculateTotalTicks();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000149 void FilteredClone(ProfileTree* src, int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000150
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000151 double TicksToMillis(unsigned ticks) const {
152 return ticks * ms_to_ticks_scale_;
153 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000154 ProfileNode* root() const { return root_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000155 void SetTickRatePerMs(double ticks_per_ms);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000156
157 void ShortPrint();
158 void Print() {
159 root_->Print(0);
160 }
161
162 private:
163 template <typename Callback>
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000164 void TraverseDepthFirst(Callback* callback);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000165
ager@chromium.org357bf652010-04-12 11:30:10 +0000166 CodeEntry root_entry_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000167 ProfileNode* root_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000168 double ms_to_ticks_scale_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000169
170 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
171};
172
173
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000174class CpuProfile {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000175 public:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000176 CpuProfile(const char* title, unsigned uid)
177 : title_(title), uid_(uid) { }
178
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000179 // Add pc -> ... -> main() call path to the profile.
180 void AddPath(const Vector<CodeEntry*>& path);
181 void CalculateTotalTicks();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000182 void SetActualSamplingRate(double actual_sampling_rate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000183 CpuProfile* FilteredClone(int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000184
lrn@chromium.org25156de2010-04-06 13:10:27 +0000185 INLINE(const char* title() const) { return title_; }
186 INLINE(unsigned uid() const) { return uid_; }
187 INLINE(const ProfileTree* top_down() const) { return &top_down_; }
188 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000189
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000190 void UpdateTicksScale();
191
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000192 void ShortPrint();
193 void Print();
194
195 private:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000196 const char* title_;
197 unsigned uid_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000198 ProfileTree top_down_;
199 ProfileTree bottom_up_;
200
201 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
202};
203
204
lrn@chromium.org25156de2010-04-06 13:10:27 +0000205class CodeMap {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000206 public:
207 CodeMap() { }
208 INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
209 INLINE(void MoveCode(Address from, Address to));
210 INLINE(void DeleteCode(Address addr));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000211 void AddAlias(Address start, CodeEntry* entry, Address code_start);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000212 CodeEntry* FindEntry(Address addr);
213
lrn@chromium.org25156de2010-04-06 13:10:27 +0000214 void Print();
215
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000216 private:
217 struct CodeEntryInfo {
218 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
219 : entry(an_entry), size(a_size) { }
220 CodeEntry* entry;
221 unsigned size;
222 };
223
224 struct CodeTreeConfig {
225 typedef Address Key;
226 typedef CodeEntryInfo Value;
227 static const Key kNoKey;
228 static const Value kNoValue;
229 static int Compare(const Key& a, const Key& b) {
230 return a < b ? -1 : (a > b ? 1 : 0);
231 }
232 };
233 typedef SplayTree<CodeTreeConfig> CodeTree;
234
lrn@chromium.org25156de2010-04-06 13:10:27 +0000235 class CodeTreePrinter {
236 public:
237 void Call(const Address& key, const CodeEntryInfo& value);
238 };
239
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000240 CodeTree tree_;
241
242 DISALLOW_COPY_AND_ASSIGN(CodeMap);
243};
244
245
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000246class CpuProfilesCollection {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000247 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000248 CpuProfilesCollection();
249 ~CpuProfilesCollection();
250
lrn@chromium.org25156de2010-04-06 13:10:27 +0000251 bool StartProfiling(const char* title, unsigned uid);
252 bool StartProfiling(String* title, unsigned uid);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000253 CpuProfile* StopProfiling(int security_token_id,
254 const char* title,
255 double actual_sampling_rate);
256 CpuProfile* StopProfiling(int security_token_id,
257 String* title,
258 double actual_sampling_rate);
259 List<CpuProfile*>* Profiles(int security_token_id);
260 CpuProfile* GetProfile(int security_token_id, unsigned uid);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000261 inline bool is_last_profile();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000262
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000263 const char* GetName(String* name);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000264 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
265 String* name, String* resource_name, int line_number);
266 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000267 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
268 const char* name_prefix, String* name);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000269 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000270 CodeEntry* NewCodeEntry(int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000271
lrn@chromium.org25156de2010-04-06 13:10:27 +0000272 // Called from profile generator thread.
273 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000274
275 private:
ager@chromium.org357bf652010-04-12 11:30:10 +0000276 INLINE(const char* GetFunctionName(String* name));
277 INLINE(const char* GetFunctionName(const char* name));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000278 const char* GetName(int args_count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000279 List<CpuProfile*>* GetProfilesList(int security_token_id);
280 int TokenToIndex(int security_token_id);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000281
282 INLINE(static bool StringsMatch(void* key1, void* key2)) {
283 return strcmp(reinterpret_cast<char*>(key1),
284 reinterpret_cast<char*>(key2)) == 0;
285 }
286
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000287 INLINE(static bool UidsMatch(void* key1, void* key2)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000288 return key1 == key2;
289 }
290
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000291 // String::Hash -> const char*
292 HashMap function_and_resource_names_;
293 // args_count -> char*
294 List<char*> args_count_names_;
295 List<CodeEntry*> code_entries_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000296 List<List<CpuProfile*>* > profiles_by_token_;
297 // uid -> index
lrn@chromium.org25156de2010-04-06 13:10:27 +0000298 HashMap profiles_uids_;
299
300 // Accessed by VM thread and profile generator thread.
301 List<CpuProfile*> current_profiles_;
302 Semaphore* current_profiles_semaphore_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000303
304 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
305};
306
307
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000308class SampleRateCalculator {
309 public:
310 SampleRateCalculator()
311 : result_(Logger::kSamplingIntervalMs * kResultScale),
312 ticks_per_ms_(Logger::kSamplingIntervalMs),
313 measurements_count_(0),
314 wall_time_query_countdown_(1) {
315 }
316
317 double ticks_per_ms() {
318 return result_ / static_cast<double>(kResultScale);
319 }
320 void Tick();
321 void UpdateMeasurements(double current_time);
322
323 // Instead of querying current wall time each tick,
324 // we use this constant to control query intervals.
325 static const unsigned kWallTimeQueryIntervalMs = 100;
326
327 private:
328 // As the result needs to be accessed from a different thread, we
329 // use type that guarantees atomic writes to memory. There should
330 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5
331 // order should provide enough precision while keeping away from a
332 // potential overflow.
333 static const int kResultScale = 100000;
334
335 AtomicWord result_;
336 // All other fields are accessed only from the sampler thread.
337 double ticks_per_ms_;
338 unsigned measurements_count_;
339 unsigned wall_time_query_countdown_;
340 double last_wall_time_;
341};
342
343
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000344class ProfileGenerator {
345 public:
346 explicit ProfileGenerator(CpuProfilesCollection* profiles);
347
348 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
349 String* name,
350 String* resource_name,
351 int line_number)) {
352 return profiles_->NewCodeEntry(tag, name, resource_name, line_number);
353 }
354
355 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
356 const char* name)) {
357 return profiles_->NewCodeEntry(tag, name);
358 }
359
360 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000361 const char* name_prefix,
362 String* name)) {
363 return profiles_->NewCodeEntry(tag, name_prefix, name);
364 }
365
366 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000367 int args_count)) {
368 return profiles_->NewCodeEntry(tag, args_count);
369 }
370
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000371 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) {
372 return profiles_->NewCodeEntry(security_token_id);
373 }
374
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000375 void RecordTickSample(const TickSample& sample);
376
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000377 INLINE(CodeMap* code_map()) { return &code_map_; }
378
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000379 INLINE(void Tick()) { sample_rate_calc_.Tick(); }
380 INLINE(double actual_sampling_rate()) {
381 return sample_rate_calc_.ticks_per_ms();
382 }
383
ager@chromium.org357bf652010-04-12 11:30:10 +0000384 static const char* kAnonymousFunctionName;
385 static const char* kProgramEntryName;
386 static const char* kGarbageCollectorEntryName;
387
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000388 private:
ager@chromium.org357bf652010-04-12 11:30:10 +0000389 INLINE(CodeEntry* EntryForVMState(StateTag tag));
390
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000391 CpuProfilesCollection* profiles_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000392 CodeMap code_map_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000393 CodeEntry* program_entry_;
394 CodeEntry* gc_entry_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000395 SampleRateCalculator sample_rate_calc_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000396
397 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
398};
399
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000400} } // namespace v8::internal
401
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000402#endif // ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000403
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000404#endif // V8_PROFILE_GENERATOR_H_