| 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 |