OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 26 matching lines...) Expand all Loading... |
37 #include "macro-assembler.h" | 37 #include "macro-assembler.h" |
38 #include "platform.h" | 38 #include "platform.h" |
39 #include "runtime-profiler.h" | 39 #include "runtime-profiler.h" |
40 #include "serialize.h" | 40 #include "serialize.h" |
41 #include "string-stream.h" | 41 #include "string-stream.h" |
42 #include "vm-state-inl.h" | 42 #include "vm-state-inl.h" |
43 | 43 |
44 namespace v8 { | 44 namespace v8 { |
45 namespace internal { | 45 namespace internal { |
46 | 46 |
47 // | |
48 // Sliding state window. Updates counters to keep track of the last | |
49 // window of kBufferSize states. This is useful to track where we | |
50 // spent our time. | |
51 // | |
52 class SlidingStateWindow { | |
53 public: | |
54 explicit SlidingStateWindow(Isolate* isolate); | |
55 ~SlidingStateWindow(); | |
56 void AddState(StateTag state); | |
57 | |
58 private: | |
59 static const int kBufferSize = 256; | |
60 Counters* counters_; | |
61 int current_index_; | |
62 bool is_full_; | |
63 byte buffer_[kBufferSize]; | |
64 | |
65 | |
66 void IncrementStateCounter(StateTag state) { | |
67 counters_->state_counters(state)->Increment(); | |
68 } | |
69 | |
70 | |
71 void DecrementStateCounter(StateTag state) { | |
72 counters_->state_counters(state)->Decrement(); | |
73 } | |
74 }; | |
75 | |
76 | |
77 // | |
78 // The Profiler samples pc and sp values for the main thread. | 47 // The Profiler samples pc and sp values for the main thread. |
79 // Each sample is appended to a circular buffer. | 48 // Each sample is appended to a circular buffer. |
80 // An independent thread removes data and writes it to the log. | 49 // An independent thread removes data and writes it to the log. |
81 // This design minimizes the time spent in the sampler. | 50 // This design minimizes the time spent in the sampler. |
82 // | 51 // |
83 class Profiler: public Thread { | 52 class Profiler: public Thread { |
84 public: | 53 public: |
85 explicit Profiler(Isolate* isolate); | 54 explicit Profiler(Isolate* isolate); |
86 void Engage(); | 55 void Engage(); |
87 void Disengage(); | 56 void Disengage(); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 | 151 |
183 | 152 |
184 // | 153 // |
185 // Ticker used to provide ticks to the profiler and the sliding state | 154 // Ticker used to provide ticks to the profiler and the sliding state |
186 // window. | 155 // window. |
187 // | 156 // |
188 class Ticker: public Sampler { | 157 class Ticker: public Sampler { |
189 public: | 158 public: |
190 Ticker(Isolate* isolate, int interval): | 159 Ticker(Isolate* isolate, int interval): |
191 Sampler(isolate, interval), | 160 Sampler(isolate, interval), |
192 window_(NULL), | |
193 profiler_(NULL) {} | 161 profiler_(NULL) {} |
194 | 162 |
195 ~Ticker() { if (IsActive()) Stop(); } | 163 ~Ticker() { if (IsActive()) Stop(); } |
196 | 164 |
197 virtual void Tick(TickSample* sample) { | 165 virtual void Tick(TickSample* sample) { |
198 if (profiler_) profiler_->Insert(sample); | 166 if (profiler_) profiler_->Insert(sample); |
199 if (window_) window_->AddState(sample->state); | |
200 } | |
201 | |
202 void SetWindow(SlidingStateWindow* window) { | |
203 window_ = window; | |
204 if (!IsActive()) Start(); | |
205 } | |
206 | |
207 void ClearWindow() { | |
208 window_ = NULL; | |
209 if (!profiler_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop(); | |
210 } | 167 } |
211 | 168 |
212 void SetProfiler(Profiler* profiler) { | 169 void SetProfiler(Profiler* profiler) { |
213 ASSERT(profiler_ == NULL); | 170 ASSERT(profiler_ == NULL); |
214 profiler_ = profiler; | 171 profiler_ = profiler; |
215 IncreaseProfilingDepth(); | 172 IncreaseProfilingDepth(); |
216 if (!FLAG_prof_lazy && !IsActive()) Start(); | 173 if (!FLAG_prof_lazy && !IsActive()) Start(); |
217 } | 174 } |
218 | 175 |
219 void ClearProfiler() { | 176 void ClearProfiler() { |
220 DecreaseProfilingDepth(); | 177 DecreaseProfilingDepth(); |
221 profiler_ = NULL; | 178 profiler_ = NULL; |
222 if (!window_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop(); | 179 if (IsActive()) Stop(); |
223 } | 180 } |
224 | 181 |
225 protected: | 182 protected: |
226 virtual void DoSampleStack(TickSample* sample) { | 183 virtual void DoSampleStack(TickSample* sample) { |
227 StackTracer::Trace(isolate(), sample); | 184 StackTracer::Trace(isolate(), sample); |
228 } | 185 } |
229 | 186 |
230 private: | 187 private: |
231 SlidingStateWindow* window_; | |
232 Profiler* profiler_; | 188 Profiler* profiler_; |
233 }; | 189 }; |
234 | 190 |
235 | 191 |
236 // | 192 // |
237 // SlidingStateWindow implementation. | |
238 // | |
239 SlidingStateWindow::SlidingStateWindow(Isolate* isolate) | |
240 : counters_(isolate->counters()), current_index_(0), is_full_(false) { | |
241 for (int i = 0; i < kBufferSize; i++) { | |
242 buffer_[i] = static_cast<byte>(OTHER); | |
243 } | |
244 isolate->logger()->ticker_->SetWindow(this); | |
245 } | |
246 | |
247 | |
248 SlidingStateWindow::~SlidingStateWindow() { | |
249 LOGGER->ticker_->ClearWindow(); | |
250 } | |
251 | |
252 | |
253 void SlidingStateWindow::AddState(StateTag state) { | |
254 if (is_full_) { | |
255 DecrementStateCounter(static_cast<StateTag>(buffer_[current_index_])); | |
256 } else if (current_index_ == kBufferSize - 1) { | |
257 is_full_ = true; | |
258 } | |
259 buffer_[current_index_] = static_cast<byte>(state); | |
260 IncrementStateCounter(state); | |
261 ASSERT(IsPowerOf2(kBufferSize)); | |
262 current_index_ = (current_index_ + 1) & (kBufferSize - 1); | |
263 } | |
264 | |
265 | |
266 // | |
267 // Profiler implementation. | 193 // Profiler implementation. |
268 // | 194 // |
269 Profiler::Profiler(Isolate* isolate) | 195 Profiler::Profiler(Isolate* isolate) |
270 : Thread("v8:Profiler"), | 196 : Thread("v8:Profiler"), |
271 isolate_(isolate), | 197 isolate_(isolate), |
272 head_(0), | 198 head_(0), |
273 tail_(0), | 199 tail_(0), |
274 overflow_(false), | 200 overflow_(false), |
275 buffer_semaphore_(OS::CreateSemaphore(0)), | 201 buffer_semaphore_(OS::CreateSemaphore(0)), |
276 engaged_(false), | 202 engaged_(false), |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 | 437 |
512 int utf8_pos_; | 438 int utf8_pos_; |
513 char utf8_buffer_[kUtf8BufferSize]; | 439 char utf8_buffer_[kUtf8BufferSize]; |
514 uc16 utf16_buffer[kUtf16BufferSize]; | 440 uc16 utf16_buffer[kUtf16BufferSize]; |
515 }; | 441 }; |
516 | 442 |
517 | 443 |
518 Logger::Logger() | 444 Logger::Logger() |
519 : ticker_(NULL), | 445 : ticker_(NULL), |
520 profiler_(NULL), | 446 profiler_(NULL), |
521 sliding_state_window_(NULL), | |
522 log_events_(NULL), | 447 log_events_(NULL), |
523 logging_nesting_(0), | 448 logging_nesting_(0), |
524 cpu_profiler_nesting_(0), | 449 cpu_profiler_nesting_(0), |
525 log_(new Log(this)), | 450 log_(new Log(this)), |
526 name_buffer_(new NameBuffer), | 451 name_buffer_(new NameBuffer), |
527 address_to_name_map_(NULL), | 452 address_to_name_map_(NULL), |
528 is_initialized_(false), | 453 is_initialized_(false), |
529 code_event_handler_(NULL), | 454 code_event_handler_(NULL), |
530 last_address_(NULL), | 455 last_address_(NULL), |
531 prev_sp_(NULL), | 456 prev_sp_(NULL), |
(...skipping 873 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1405 } | 1330 } |
1406 | 1331 |
1407 | 1332 |
1408 void Logger::PauseProfiler() { | 1333 void Logger::PauseProfiler() { |
1409 if (!log_->IsEnabled()) return; | 1334 if (!log_->IsEnabled()) return; |
1410 if (profiler_ != NULL) { | 1335 if (profiler_ != NULL) { |
1411 // It is OK to have negative nesting. | 1336 // It is OK to have negative nesting. |
1412 if (--cpu_profiler_nesting_ == 0) { | 1337 if (--cpu_profiler_nesting_ == 0) { |
1413 profiler_->pause(); | 1338 profiler_->pause(); |
1414 if (FLAG_prof_lazy) { | 1339 if (FLAG_prof_lazy) { |
1415 if (!FLAG_sliding_state_window && !RuntimeProfiler::IsEnabled()) { | 1340 ticker_->Stop(); |
1416 ticker_->Stop(); | |
1417 } | |
1418 FLAG_log_code = false; | 1341 FLAG_log_code = false; |
1419 LOG(ISOLATE, UncheckedStringEvent("profiler", "pause")); | 1342 LOG(ISOLATE, UncheckedStringEvent("profiler", "pause")); |
1420 } | 1343 } |
1421 --logging_nesting_; | 1344 --logging_nesting_; |
1422 } | 1345 } |
1423 } | 1346 } |
1424 } | 1347 } |
1425 | 1348 |
1426 | 1349 |
1427 void Logger::ResumeProfiler() { | 1350 void Logger::ResumeProfiler() { |
1428 if (!log_->IsEnabled()) return; | 1351 if (!log_->IsEnabled()) return; |
1429 if (profiler_ != NULL) { | 1352 if (profiler_ != NULL) { |
1430 if (cpu_profiler_nesting_++ == 0) { | 1353 if (cpu_profiler_nesting_++ == 0) { |
1431 ++logging_nesting_; | 1354 ++logging_nesting_; |
1432 if (FLAG_prof_lazy) { | 1355 if (FLAG_prof_lazy) { |
1433 profiler_->Engage(); | 1356 profiler_->Engage(); |
1434 LOG(ISOLATE, UncheckedStringEvent("profiler", "resume")); | 1357 LOG(ISOLATE, UncheckedStringEvent("profiler", "resume")); |
1435 FLAG_log_code = true; | 1358 FLAG_log_code = true; |
1436 LogCompiledFunctions(); | 1359 LogCompiledFunctions(); |
1437 LogAccessorCallbacks(); | 1360 LogAccessorCallbacks(); |
1438 if (!FLAG_sliding_state_window && !ticker_->IsActive()) { | 1361 if (!ticker_->IsActive()) ticker_->Start(); |
1439 ticker_->Start(); | |
1440 } | |
1441 } | 1362 } |
1442 profiler_->resume(); | 1363 profiler_->resume(); |
1443 } | 1364 } |
1444 } | 1365 } |
1445 } | 1366 } |
1446 | 1367 |
1447 | 1368 |
1448 // This function can be called when Log's mutex is acquired, | 1369 // This function can be called when Log's mutex is acquired, |
1449 // either from main or Profiler's thread. | 1370 // either from main or Profiler's thread. |
1450 void Logger::LogFailure() { | 1371 void Logger::LogFailure() { |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1774 // -> thread local top -> heap -> logger). | 1695 // -> thread local top -> heap -> logger). |
1775 // ASSERT(VMState::is_outermost_external()); | 1696 // ASSERT(VMState::is_outermost_external()); |
1776 | 1697 |
1777 log_->Initialize(); | 1698 log_->Initialize(); |
1778 | 1699 |
1779 if (FLAG_ll_prof) LogCodeInfo(); | 1700 if (FLAG_ll_prof) LogCodeInfo(); |
1780 | 1701 |
1781 Isolate* isolate = Isolate::Current(); | 1702 Isolate* isolate = Isolate::Current(); |
1782 ticker_ = new Ticker(isolate, kSamplingIntervalMs); | 1703 ticker_ = new Ticker(isolate, kSamplingIntervalMs); |
1783 | 1704 |
1784 if (FLAG_sliding_state_window && sliding_state_window_ == NULL) { | |
1785 sliding_state_window_ = new SlidingStateWindow(isolate); | |
1786 } | |
1787 | |
1788 bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api | 1705 bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api |
1789 || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect | 1706 || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect |
1790 || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof | 1707 || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof |
1791 || FLAG_log_internal_timer_events; | 1708 || FLAG_log_internal_timer_events; |
1792 | 1709 |
1793 if (start_logging) { | 1710 if (start_logging) { |
1794 logging_nesting_ = 1; | 1711 logging_nesting_ = 1; |
1795 } | 1712 } |
1796 | 1713 |
1797 if (FLAG_prof) { | 1714 if (FLAG_prof) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1844 if (!is_initialized_) return NULL; | 1761 if (!is_initialized_) return NULL; |
1845 is_initialized_ = false; | 1762 is_initialized_ = false; |
1846 | 1763 |
1847 // Stop the profiler before closing the file. | 1764 // Stop the profiler before closing the file. |
1848 if (profiler_ != NULL) { | 1765 if (profiler_ != NULL) { |
1849 profiler_->Disengage(); | 1766 profiler_->Disengage(); |
1850 delete profiler_; | 1767 delete profiler_; |
1851 profiler_ = NULL; | 1768 profiler_ = NULL; |
1852 } | 1769 } |
1853 | 1770 |
1854 delete sliding_state_window_; | |
1855 sliding_state_window_ = NULL; | |
1856 | |
1857 delete ticker_; | 1771 delete ticker_; |
1858 ticker_ = NULL; | 1772 ticker_ = NULL; |
1859 | 1773 |
1860 return log_->Close(); | 1774 return log_->Close(); |
1861 } | 1775 } |
1862 | 1776 |
1863 | 1777 |
1864 void Logger::EnableSlidingStateWindow() { | |
1865 // If the ticker is NULL, Logger::SetUp has not been called yet. In | |
1866 // that case, we set the sliding_state_window flag so that the | |
1867 // sliding window computation will be started when Logger::SetUp is | |
1868 // called. | |
1869 if (ticker_ == NULL) { | |
1870 FLAG_sliding_state_window = true; | |
1871 return; | |
1872 } | |
1873 // Otherwise, if the sliding state window computation has not been | |
1874 // started we do it now. | |
1875 if (sliding_state_window_ == NULL) { | |
1876 sliding_state_window_ = new SlidingStateWindow(Isolate::Current()); | |
1877 } | |
1878 } | |
1879 | |
1880 // Protects the state below. | 1778 // Protects the state below. |
1881 static Mutex* active_samplers_mutex = NULL; | 1779 static Mutex* active_samplers_mutex = NULL; |
1882 | 1780 |
1883 List<Sampler*>* SamplerRegistry::active_samplers_ = NULL; | 1781 List<Sampler*>* SamplerRegistry::active_samplers_ = NULL; |
1884 | 1782 |
1885 | 1783 |
1886 void SamplerRegistry::SetUp() { | 1784 void SamplerRegistry::SetUp() { |
1887 if (!active_samplers_mutex) { | 1785 if (!active_samplers_mutex) { |
1888 active_samplers_mutex = OS::CreateMutex(); | 1786 active_samplers_mutex = OS::CreateMutex(); |
1889 } | 1787 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1931 void SamplerRegistry::RemoveActiveSampler(Sampler* sampler) { | 1829 void SamplerRegistry::RemoveActiveSampler(Sampler* sampler) { |
1932 ASSERT(sampler->IsActive()); | 1830 ASSERT(sampler->IsActive()); |
1933 ScopedLock lock(active_samplers_mutex); | 1831 ScopedLock lock(active_samplers_mutex); |
1934 ASSERT(active_samplers_ != NULL); | 1832 ASSERT(active_samplers_ != NULL); |
1935 bool removed = active_samplers_->RemoveElement(sampler); | 1833 bool removed = active_samplers_->RemoveElement(sampler); |
1936 ASSERT(removed); | 1834 ASSERT(removed); |
1937 USE(removed); | 1835 USE(removed); |
1938 } | 1836 } |
1939 | 1837 |
1940 } } // namespace v8::internal | 1838 } } // namespace v8::internal |
OLD | NEW |