15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/tracing.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
99ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/trace_controller.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/trace_subscriber.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/test_utils.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class InProcessTraceController : public content::TraceSubscriber {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static InProcessTraceController* GetInstance() {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Singleton<InProcessTraceController>::get();
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InProcessTraceController()
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : is_waiting_on_watch_(false),
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        watch_notification_count_(0) {}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~InProcessTraceController() {}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool BeginTracing(const std::string& category_patterns) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return content::TraceController::GetInstance()->BeginTracing(
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        this, category_patterns, base::debug::TraceLog::RECORD_UNTIL_FULL);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool BeginTracingWithWatch(const std::string& category_patterns,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const std::string& category_name,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const std::string& event_name,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int num_occurrences) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(num_occurrences > 0);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    watch_notification_count_ = num_occurrences;
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return BeginTracing(category_patterns) &&
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           content::TraceController::GetInstance()->SetWatchEvent(
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               this, category_name, event_name);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool WaitForWatchEvent(base::TimeDelta timeout) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (watch_notification_count_ == 0)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (timeout != base::TimeDelta()) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Start(FROM_HERE, timeout, this,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   &InProcessTraceController::Timeout);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_waiting_on_watch_ = true;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_ = new content::MessageLoopRunner;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_->Run();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_waiting_on_watch_ = false;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return watch_notification_count_ == 0;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool EndTracing(std::string* json_trace_output) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    using namespace base::debug;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TraceResultBuffer::SimpleOutput output;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    trace_buffer_.SetOutputCallback(output.GetCallback());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    trace_buffer_.Start();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!content::TraceController::GetInstance()->EndTracingAsync(this))
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait for OnEndTracingComplete() to quit the message loop.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // OnTraceDataCollected may be called multiple times while blocking here.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_ = new content::MessageLoopRunner;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_->Run();
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    trace_buffer_.Finish();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    trace_buffer_.SetOutputCallback(TraceResultBuffer::OutputCallback());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *json_trace_output = output.json_output;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Watch notifications can occur during this method's message loop run, but
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // not after, so clear them here.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    watch_notification_count_ = 0;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct DefaultSingletonTraits<InProcessTraceController>;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TraceSubscriber implementation
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnEndTracingComplete() OVERRIDE {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_->Quit();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TraceSubscriber implementation
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnTraceDataCollected(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    trace_buffer_.AddFragment(trace_fragment->data());
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TraceSubscriber implementation
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnEventWatchNotification() OVERRIDE {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (watch_notification_count_ == 0)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (--watch_notification_count_ == 0) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Stop();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (is_waiting_on_watch_)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        message_loop_runner_->Quit();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Timeout() {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(is_waiting_on_watch_);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_->Quit();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For collecting trace data asynchronously.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::debug::TraceResultBuffer trace_buffer_;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::OneShotTimer<InProcessTraceController> timer_;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_waiting_on_watch_;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int watch_notification_count_;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(InProcessTraceController);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace tracing {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool BeginTracing(const std::string& category_patterns) {
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return InProcessTraceController::GetInstance()->BeginTracing(
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      category_patterns);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool BeginTracingWithWatch(const std::string& category_patterns,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::string& category_name,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::string& event_name,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           int num_occurrences) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InProcessTraceController::GetInstance()->BeginTracingWithWatch(
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      category_patterns, category_name, event_name, num_occurrences);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WaitForWatchEvent(base::TimeDelta timeout) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InProcessTraceController::GetInstance()->WaitForWatchEvent(timeout);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EndTracing(std::string* json_trace_output) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InProcessTraceController::GetInstance()->EndTracing(json_trace_output);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace tracing
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
161