Revert of https://codereview.chromium.org/99103004/

Reason for revert: Bug 323749 still unresolved

TBR=
NOTREECHECKS=true
NOTRY=true

Review URL: https://codereview.chromium.org/101543004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238424 0039d316-1c4b-4281-b951-d872f2087c98
parent 02c6ab4d
This diff is collapsed.
......@@ -354,6 +354,16 @@ class TraceSamplingThread;
class BASE_EXPORT TraceLog {
public:
// Notification is a mask of one or more of the following events.
enum Notification {
// The trace buffer does not flush dynamically, so when it fills up,
// subsequent trace events will be dropped. This callback is generated when
// the trace buffer is full. The callback must be thread safe.
TRACE_BUFFER_FULL = 1 << 0,
// A subscribed trace-event occurred.
EVENT_WATCH_NOTIFICATION = 1 << 1
};
// Options determines how the trace buffer stores data.
enum Options {
// Record until the trace buffer is full.
......@@ -385,6 +395,10 @@ class BASE_EXPORT TraceLog {
static TraceLog* GetInstance();
// Convert the given string to trace options. Defaults to RECORD_UNTIL_FULL if
// the string does not provide valid options.
static Options TraceOptionsFromString(const std::string& str);
// Get set of known category groups. This can change as new code paths are
// reached. The known category groups are inserted into |category_groups|.
void GetKnownCategoryGroups(std::vector<std::string>* category_groups);
......@@ -438,7 +452,14 @@ class BASE_EXPORT TraceLog {
bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
float GetBufferPercentFull() const;
bool BufferIsFull() const;
// Set the thread-safe notification callback. The callback can occur at any
// time and from any thread. WARNING: It is possible for the previously set
// callback to be called during OR AFTER a call to SetNotificationCallback.
// Therefore, the target of the callback must either be a global function,
// ref-counted object or a LazyInstance with Leaky traits (or equivalent).
typedef base::Callback<void(int)> NotificationCallback;
void SetNotificationCallback(const NotificationCallback& cb);
// Not using base::Callback because of its limited by 7 parameters.
// Also, using primitive type allows directly passing callback from WebCore.
......@@ -526,11 +547,12 @@ class BASE_EXPORT TraceLog {
const char* name,
TraceEventHandle handle);
// For every matching event, the callback will be called.
typedef base::Callback<void()> WatchEventCallback;
// For every matching event, a notification will be fired. NOTE: the
// notification will fire for each matching event that has already occurred
// since tracing was started (including before tracing if the process was
// started with tracing turned on).
void SetWatchEvent(const std::string& category_name,
const std::string& event_name,
const WatchEventCallback& callback);
const std::string& event_name);
// Cancel the watch event. If tracing is enabled, this may race with the
// watch event notification firing.
void CancelWatchEvent();
......@@ -599,6 +621,29 @@ class BASE_EXPORT TraceLog {
void UpdateCategoryGroupEnabledFlags();
void UpdateCategoryGroupEnabledFlag(int category_index);
// Helper class for managing notification_thread_count_ and running
// notification callbacks. This is very similar to a reader-writer lock, but
// shares the lock with TraceLog and manages the notification flags.
class NotificationHelper {
public:
inline explicit NotificationHelper(TraceLog* trace_log);
inline ~NotificationHelper();
// Called only while TraceLog::lock_ is held. This ORs the given
// notification with any existing notifications.
inline void AddNotificationWhileLocked(int notification);
// Called only while TraceLog::lock_ is NOT held. If there are any pending
// notifications from previous calls to AddNotificationWhileLocked, this
// will call the NotificationCallback.
inline void SendNotificationIfAny();
private:
TraceLog* trace_log_;
NotificationCallback callback_copy_;
int notification_;
};
class ThreadLocalEventBuffer;
class OptionalAutoLock;
......@@ -614,10 +659,9 @@ class BASE_EXPORT TraceLog {
const TimeTicks& timestamp,
TraceEvent* trace_event);
TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
bool check_buffer_is_full);
void CheckIfBufferIsFullWhileLocked();
void SetDisabledWhileLocked();
TraceEvent* AddEventToThreadSharedChunkWhileLocked(
NotificationHelper* notifier, TraceEventHandle* handle);
void CheckIfBufferIsFullWhileLocked(NotificationHelper* notifier);
TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
OptionalAutoLock* lock);
......@@ -648,10 +692,12 @@ class BASE_EXPORT TraceLog {
}
// This lock protects TraceLog member accesses from arbitrary threads.
mutable Lock lock_;
Lock lock_;
int locked_line_;
bool enabled_;
int num_traces_recorded_;
subtle::AtomicWord /* bool */ buffer_is_full_;
NotificationCallback notification_callback_;
scoped_ptr<TraceBuffer> logged_events_;
subtle::AtomicWord /* EventCallback */ event_callback_;
bool dispatching_to_observer_list_;
......@@ -675,7 +721,6 @@ class BASE_EXPORT TraceLog {
TimeDelta time_offset_;
// Allow tests to wake up when certain events occur.
WatchEventCallback watch_event_callback_;
subtle::AtomicWord /* const unsigned char* */ watch_category_;
std::string watch_event_name_;
......
......@@ -53,8 +53,10 @@ class TraceEventTestFixture : public testing::Test {
WaitableEvent* flush_complete_event,
const scoped_refptr<base::RefCountedString>& events_str,
bool has_more_events);
void OnWatchEventMatched() {
++event_watch_notification_;
void OnTraceNotification(int notification) {
if (notification & TraceLog::EVENT_WATCH_NOTIFICATION)
++event_watch_notification_;
notifications_received_ |= notification;
}
DictionaryValue* FindMatchingTraceEntry(const JsonKeyValue* key_values);
DictionaryValue* FindNamePhase(const char* name, const char* phase);
......@@ -77,6 +79,7 @@ class TraceEventTestFixture : public testing::Test {
void BeginSpecificTrace(const std::string& filter) {
event_watch_notification_ = 0;
notifications_received_ = 0;
TraceLog::GetInstance()->SetEnabled(CategoryFilter(filter),
TraceLog::RECORD_UNTIL_FULL);
}
......@@ -124,13 +127,16 @@ class TraceEventTestFixture : public testing::Test {
virtual void SetUp() OVERRIDE {
const char* name = PlatformThread::GetName();
old_thread_name_ = name ? strdup(name) : NULL;
notifications_received_ = 0;
TraceLog::DeleteForTesting();
TraceLog* tracelog = TraceLog::GetInstance();
ASSERT_TRUE(tracelog);
ASSERT_FALSE(tracelog->IsEnabled());
tracelog->SetNotificationCallback(
base::Bind(&TraceEventTestFixture::OnTraceNotification,
base::Unretained(this)));
trace_buffer_.SetOutputCallback(json_output_.GetCallback());
event_watch_notification_ = 0;
}
virtual void TearDown() OVERRIDE {
if (TraceLog::GetInstance())
......@@ -147,6 +153,7 @@ class TraceEventTestFixture : public testing::Test {
base::debug::TraceResultBuffer trace_buffer_;
base::debug::TraceResultBuffer::SimpleOutput json_output_;
int event_watch_notification_;
int notifications_received_;
private:
// We want our singleton torn down after each test.
......@@ -1181,17 +1188,14 @@ TEST_F(TraceEventTestFixture, Categories) {
TEST_F(TraceEventTestFixture, EventWatchNotification) {
// Basic one occurrence.
BeginTrace();
TraceLog::WatchEventCallback callback =
base::Bind(&TraceEventTestFixture::OnWatchEventMatched,
base::Unretained(this));
TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
TraceLog::GetInstance()->SetWatchEvent("cat", "event");
TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
EndTraceAndFlush();
EXPECT_EQ(event_watch_notification_, 1);
// Auto-reset after end trace.
BeginTrace();
TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
TraceLog::GetInstance()->SetWatchEvent("cat", "event");
EndTraceAndFlush();
BeginTrace();
TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
......@@ -1201,7 +1205,7 @@ TEST_F(TraceEventTestFixture, EventWatchNotification) {
// Multiple occurrence.
BeginTrace();
int num_occurrences = 5;
TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
TraceLog::GetInstance()->SetWatchEvent("cat", "event");
for (int i = 0; i < num_occurrences; ++i)
TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
EndTraceAndFlush();
......@@ -1209,21 +1213,21 @@ TEST_F(TraceEventTestFixture, EventWatchNotification) {
// Wrong category.
BeginTrace();
TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
TraceLog::GetInstance()->SetWatchEvent("cat", "event");
TRACE_EVENT_INSTANT0("wrong_cat", "event", TRACE_EVENT_SCOPE_THREAD);
EndTraceAndFlush();
EXPECT_EQ(event_watch_notification_, 0);
// Wrong name.
BeginTrace();
TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
TraceLog::GetInstance()->SetWatchEvent("cat", "event");
TRACE_EVENT_INSTANT0("cat", "wrong_event", TRACE_EVENT_SCOPE_THREAD);
EndTraceAndFlush();
EXPECT_EQ(event_watch_notification_, 0);
// Canceled.
BeginTrace();
TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
TraceLog::GetInstance()->SetWatchEvent("cat", "event");
TraceLog::GetInstance()->CancelWatchEvent();
TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
EndTraceAndFlush();
......@@ -1730,7 +1734,23 @@ TEST_F(TraceEventTestFixture, TraceCategoriesAfterNestedEnable) {
trace_log->SetDisabled();
}
TEST_F(TraceEventTestFixture, TraceOptionsParsing) {
EXPECT_EQ(TraceLog::RECORD_UNTIL_FULL,
TraceLog::TraceOptionsFromString(std::string()));
EXPECT_EQ(TraceLog::RECORD_UNTIL_FULL,
TraceLog::TraceOptionsFromString("record-until-full"));
EXPECT_EQ(TraceLog::RECORD_CONTINUOUSLY,
TraceLog::TraceOptionsFromString("record-continuously"));
EXPECT_EQ(TraceLog::RECORD_UNTIL_FULL | TraceLog::ENABLE_SAMPLING,
TraceLog::TraceOptionsFromString("enable-sampling"));
EXPECT_EQ(TraceLog::RECORD_CONTINUOUSLY | TraceLog::ENABLE_SAMPLING,
TraceLog::TraceOptionsFromString(
"record-continuously,enable-sampling"));
}
TEST_F(TraceEventTestFixture, TraceSampling) {
event_watch_notification_ = 0;
TraceLog::GetInstance()->SetEnabled(
CategoryFilter("*"),
TraceLog::Options(TraceLog::RECORD_UNTIL_FULL |
......@@ -1749,6 +1769,7 @@ TEST_F(TraceEventTestFixture, TraceSampling) {
}
TEST_F(TraceEventTestFixture, TraceSamplingScope) {
event_watch_notification_ = 0;
TraceLog::GetInstance()->SetEnabled(
CategoryFilter("*"),
TraceLog::Options(TraceLog::RECORD_UNTIL_FULL |
......@@ -1783,6 +1804,7 @@ TEST_F(TraceEventTestFixture, TraceSamplingScope) {
}
TEST_F(TraceEventTestFixture, TraceContinuousSampling) {
event_watch_notification_ = 0;
TraceLog::GetInstance()->SetEnabled(
CategoryFilter("*"),
TraceLog::Options(TraceLog::MONITOR_SAMPLING));
......@@ -2049,7 +2071,7 @@ TEST_F(TraceEventCallbackTest, TraceEventCallbackWhileFull) {
TraceLog::RECORD_UNTIL_FULL);
do {
TRACE_EVENT_INSTANT0("all", "badger badger", TRACE_EVENT_SCOPE_GLOBAL);
} while (!TraceLog::GetInstance()->BufferIsFull());
} while ((notifications_received_ & TraceLog::TRACE_BUFFER_FULL) == 0);
TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("*"),
Callback);
TRACE_EVENT_INSTANT0("all", "a snake", TRACE_EVENT_SCOPE_GLOBAL);
......
......@@ -66,7 +66,7 @@
#include "content/public/browser/download_item.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/browser/trace_controller.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "net/proxy/proxy_config_service_fixed.h"
......@@ -86,7 +86,7 @@ using content::BrowserThread;
using content::DownloadItem;
using content::NavigationController;
using content::RenderViewHost;
using content::TracingController;
using content::TraceController;
using content::WebContents;
namespace {
......@@ -376,6 +376,20 @@ void AutomationProvider::OnChannelConnected(int pid) {
SendInitialLoadMessage();
}
void AutomationProvider::OnEndTracingComplete() {
IPC::Message* reply_message = tracing_data_.reply_message.release();
if (reply_message) {
AutomationMsg_EndTracing::WriteReplyParams(
reply_message, tracing_data_.trace_output.size(), true);
Send(reply_message);
}
}
void AutomationProvider::OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& trace_fragment) {
tracing_data_.trace_output.push_back(trace_fragment->data());
}
bool AutomationProvider::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
bool deserialize_success = true;
......@@ -398,6 +412,7 @@ bool AutomationProvider::OnMessageReceived(const IPC::Message& message) {
JavaScriptStressTestControl)
IPC_MESSAGE_HANDLER(AutomationMsg_BeginTracing, BeginTracing)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EndTracing, EndTracing)
IPC_MESSAGE_HANDLER(AutomationMsg_GetTracingOutput, GetTracingOutput)
#if defined(OS_WIN)
// These are for use with external tabs.
IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
......@@ -707,28 +722,39 @@ void AutomationProvider::JavaScriptStressTestControl(int tab_handle,
void AutomationProvider::BeginTracing(const std::string& category_patterns,
bool* success) {
*success = TracingController::GetInstance()->EnableRecording(
category_patterns, TracingController::DEFAULT_OPTIONS,
TracingController::EnableRecordingDoneCallback());
tracing_data_.trace_output.clear();
*success = TraceController::GetInstance()->BeginTracing(
this,
category_patterns,
base::debug::TraceLog::RECORD_UNTIL_FULL);
}
void AutomationProvider::EndTracing(IPC::Message* reply_message) {
base::FilePath path;
if (!TracingController::GetInstance()->DisableRecording(
path, base::Bind(&AutomationProvider::OnTraceDataCollected, this,
reply_message))) {
bool success = false;
if (!tracing_data_.reply_message.get())
success = TraceController::GetInstance()->EndTracingAsync(this);
if (success) {
// Defer EndTracing reply until TraceController calls us back with all the
// events.
tracing_data_.reply_message.reset(reply_message);
} else {
// If failed to call EndTracingAsync, need to reply with failure now.
AutomationMsg_EndTracing::WriteReplyParams(reply_message, path, false);
AutomationMsg_EndTracing::WriteReplyParams(reply_message, size_t(0), false);
Send(reply_message);
}
// Otherwise defer EndTracing reply until TraceController calls us back.
}
void AutomationProvider::OnTraceDataCollected(IPC::Message* reply_message,
const base::FilePath& path) {
if (reply_message) {
AutomationMsg_EndTracing::WriteReplyParams(reply_message, path, true);
Send(reply_message);
void AutomationProvider::GetTracingOutput(std::string* chunk,
bool* success) {
// The JSON data is sent back to the test in chunks, because IPC sends will
// fail if they are too large.
if (tracing_data_.trace_output.empty()) {
*chunk = "";
*success = false;
} else {
*chunk = tracing_data_.trace_output.front();
tracing_data_.trace_output.pop_front();
*success = true;
}
}
......
......@@ -29,6 +29,7 @@
#include "components/autofill/core/browser/field_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/trace_subscriber.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
......@@ -81,7 +82,8 @@ class AutomationProvider
public IPC::Sender,
public base::SupportsWeakPtr<AutomationProvider>,
public base::RefCountedThreadSafe<
AutomationProvider, content::BrowserThread::DeleteOnUIThread> {
AutomationProvider, content::BrowserThread::DeleteOnUIThread>,
public content::TraceSubscriber {
public:
explicit AutomationProvider(Profile* profile);
......@@ -213,6 +215,17 @@ class AutomationProvider
bool reinitialize_on_channel_error_;
private:
// Storage for EndTracing() to resume operations after a callback.
struct TracingData {
std::list<std::string> trace_output;
scoped_ptr<IPC::Message> reply_message;
};
// TraceSubscriber:
virtual void OnEndTracingComplete() OVERRIDE;
virtual void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
void OnUnhandledMessage(const IPC::Message& message);
// Clear and reinitialize the automation IPC channel.
......@@ -241,8 +254,7 @@ class AutomationProvider
void BeginTracing(const std::string& category_patterns, bool* success);
void EndTracing(IPC::Message* reply_message);
void OnTraceDataCollected(IPC::Message* reply_message,
const base::FilePath& path);
void GetTracingOutput(std::string* chunk, bool* success);
// Asynchronous request for printing the current tab.
void PrintAsync(int tab_handle);
......@@ -339,6 +351,10 @@ class AutomationProvider
// ID of automation channel.
std::string channel_id_;
// Trace data that has been collected but not flushed to the automation
// client.
TracingData tracing_data_;
DISALLOW_COPY_AND_ASSIGN(AutomationProvider);
};
......
......@@ -374,33 +374,24 @@ void SendReport(scoped_refptr<FeedbackData> data) {
bool ZipString(const base::FilePath& filename,
const std::string& data, std::string* compressed_logs) {
base::FilePath temp_path;
base::FilePath zip_file;
// Create a temporary directory, put the logs into a file in it.
// Create a temporary directory, put the logs into a file in it. Create
// another temporary file to receive the zip file in.
if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""), &temp_path))
return false;
base::FilePath temp_file = temp_path.Append(filename);
if (file_util::WriteFile(temp_file, data.c_str(), data.size()) == -1)
if (file_util::WriteFile(temp_path.Append(filename),
data.c_str(), data.size()) == -1)
return false;
return ZipFile(temp_file, compressed_logs);
}
bool ZipFile(const base::FilePath& filename, std::string* compressed_logs) {
base::FilePath zip_file;
// Create a temporary file to receive the zip file in it.
if (!file_util::CreateTemporaryFile(&zip_file))
return false;
if (!zip::Zip(filename, zip_file, false))
if (!zip::Zip(temp_path, zip_file, false))
return false;
if (!base::ReadFileToString(zip_file, compressed_logs))
return false;
base::DeleteFile(zip_file, false);
return true;
}
......
......@@ -38,7 +38,6 @@ namespace feedback_util {
void SendReport(scoped_refptr<FeedbackData> data);
bool ZipString(const base::FilePath& filename,
const std::string& data, std::string* compressed_data);
bool ZipFile(const base::FilePath& filename, std::string* compressed_data);
} // namespace feedback_util
......
......@@ -5,21 +5,20 @@
#include "chrome/browser/feedback/tracing_manager.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "base/location.h"
#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/feedback/feedback_util.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/browser/trace_controller.h"
namespace {
// Only once trace manager can exist at a time.
TracingManager* g_tracing_manager = NULL;
// Trace IDs start at 1 and increase.
int g_next_trace_id = 1;
// Name of the file to store the tracing data as.
const base::FilePath::CharType kTracingFilename[] =
FILE_PATH_LITERAL("tracing.json");
}
TracingManager::TracingManager()
......@@ -42,10 +41,7 @@ int TracingManager::RequestTrace() {
current_trace_id_ = g_next_trace_id;
++g_next_trace_id;
content::TracingController::GetInstance()->DisableRecording(
base::FilePath(),
base::Bind(&TracingManager::OnTraceDataCollected,
weak_ptr_factory_.GetWeakPtr()));
content::TraceController::GetInstance()->EndTracingAsync(this);
return current_trace_id_;
}
......@@ -80,6 +76,7 @@ void TracingManager::DiscardTraceData(int id) {
// If the trace is discarded before it is complete, clean up the accumulators.
if (id == current_trace_id_) {
current_trace_id_ = 0;
data_ = "";
// If the trace has already been requested, provide an empty string.
if (!trace_callback_.is_null()) {
......@@ -90,18 +87,20 @@ void TracingManager::DiscardTraceData(int id) {
}
void TracingManager::StartTracing() {
content::TracingController::GetInstance()->EnableRecording(
"", content::TracingController::DEFAULT_OPTIONS,
content::TracingController::EnableRecordingDoneCallback());
content::TraceController::GetInstance()->BeginTracing(
this, "-test_*",
base::debug::TraceLog::RECORD_CONTINUOUSLY);
}
void TracingManager::OnTraceDataCollected(const base::FilePath& path) {
void TracingManager::OnEndTracingComplete() {
if (!current_trace_id_)
return;
data_ = std::string("[") + data_ + "]";
std::string output_val;
feedback_util::ZipFile(path, &output_val);
base::DeleteFile(path, false);
feedback_util::ZipString(
base::FilePath(kTracingFilename), data_, &output_val);
scoped_refptr<base::RefCountedString> output(
base::RefCountedString::TakeString(&output_val));
......@@ -114,6 +113,7 @@ void TracingManager::OnTraceDataCollected(const base::FilePath& path) {
}
current_trace_id_ = 0;
data_ = "";
// Tracing has to be restarted asynchronous, so the TracingController can
// clean up.
......@@ -123,6 +123,15 @@ void TracingManager::OnTraceDataCollected(const base::FilePath& path) {
weak_ptr_factory_.GetWeakPtr()));
}
void TracingManager::OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& trace_fragment) {
if (current_trace_id_) {
if (!data_.empty())
data_ += ",";
data_ += trace_fragment->data();
}
}
// static
scoped_ptr<TracingManager> TracingManager::Create() {
if (g_tracing_manager)
......
......@@ -12,18 +12,13 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/trace_subscriber.h"
namespace base {
class RefCountedString;
class FilePath;
}
// Callback used for getting the output of a trace.
typedef base::Callback<void(scoped_refptr<base::RefCountedString> trace_data)>
TraceDataCallback;
// This class is used to manage performance metrics that can be attached to
// This class is used to manage performance meterics that can be attached to
// feedback reports. This class is a Singleton that is owned by the preference
// system. It should only be created when it is enabled, and should only be
// accessed elsewhere via Get().
......@@ -33,7 +28,7 @@ typedef base::Callback<void(scoped_refptr<base::RefCountedString> trace_data)>
// version of the performance data. That data can then be requested via
// GetTraceData(). When the data is no longer needed, it should be discarded
// via DiscardTraceData().
class TracingManager {
class TracingManager : public content::TraceSubscriber {
public:
virtual ~TracingManager();
......@@ -55,10 +50,17 @@ class TracingManager {
void DiscardTraceData(int id);
private:
void StartTracing();
// content::TraceSubscriber overrides
virtual void OnEndTracingComplete() OVERRIDE;
virtual void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
TracingManager();
void StartTracing();
void OnTraceDataCollected(const base::FilePath& path);
// Data being collected from the current trace.
std::string data_;
// ID of the trace that is being collected.
int current_trace_id_;
......
......@@ -934,7 +934,15 @@ IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_BeginTracing,
// End tracing (called after BeginTracing). This blocks until tracing has
// stopped on all processes and all the events are ready to be retrieved.
IPC_SYNC_MESSAGE_CONTROL0_2(AutomationMsg_EndTracing,
base::FilePath /* result_file_path */,
size_t /* num_trace_chunks */,
bool /* success */)
// Retrieve trace event data (called after EndTracing). Must call exactly
// |num_trace_chunks| times.
// TODO(jbates): See bug 100255, IPC send fails if message is too big. This
// code can be removed if that limitation is fixed.
IPC_SYNC_MESSAGE_CONTROL0_2(AutomationMsg_GetTracingOutput,
std::string /* trace_chunk */,
bool /* success */)
// Used on Mac OS X to read the number of active Mach ports used in the browser
......
......@@ -7,7 +7,7 @@
#include <sstream>
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
......@@ -410,13 +410,31 @@ bool AutomationProxy::BeginTracing(const std::string& category_patterns) {
bool AutomationProxy::EndTracing(std::string* json_trace_output) {
bool success = false;
base::FilePath path;
if (!Send(new AutomationMsg_EndTracing(&path, &success)) || !success)
size_t num_trace_chunks = 0;
if (!Send(new AutomationMsg_EndTracing(&num_trace_chunks, &success)) ||
!success)
return false;
bool ok = base::ReadFileToString(path, json_trace_output);
DCHECK(ok);
base::DeleteFile(path, false);
std::string chunk;
base::debug::TraceResultBuffer buffer;
base::debug::TraceResultBuffer::SimpleOutput output;
buffer.SetOutputCallback(output.GetCallback());
// TODO(jbates): See bug 100255, IPC send fails if message is too big. This
// code can be simplified if that limitation is fixed.
// Workaround IPC payload size limitation by getting chunks.
buffer.Start();
for (size_t i = 0; i < num_trace_chunks; ++i) {
// The broswer side AutomationProvider resets state at BeginTracing,
// so it can recover even after this fails mid-way.
if (!Send(new AutomationMsg_GetTracingOutput(&chunk, &success)) ||
!success)
return false;
buffer.AddFragment(chunk);
}
buffer.Finish();
*json_trace_output = output.json_output;
return true;
}
......
......@@ -4,21 +4,19 @@
#include "chrome/test/base/tracing.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/debug/trace_event.h"
#include "base/memory/singleton.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/timer/timer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/browser/trace_controller.h"
#include "content/public/browser/trace_subscriber.h"
#include "content/public/test/test_utils.h"
namespace {
using content::BrowserThread;
class InProcessTraceController {
class InProcessTraceController : public content::TraceSubscriber {
public:
static InProcessTraceController* GetInstance() {
return Singleton<InProcessTraceController>::get();
......@@ -31,10 +29,8 @@ class InProcessTraceController {
bool BeginTracing(const std::string& category_patterns) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return content::TracingController::GetInstance()->EnableRecording(
category_patterns, content::TracingController::DEFAULT_OPTIONS,
content::TracingController::EnableRecordingDoneCallback());
return true;
return content::TraceController::GetInstance()->BeginTracing(
this, category_patterns, base::debug::TraceLog::RECORD_UNTIL_FULL);
}
bool BeginTracingWithWatch(const std::string& category_patterns,
......@@ -44,11 +40,9 @@ class InProcessTraceController {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(num_occurrences > 0);
watch_notification_count_ = num_occurrences;
return content::TracingController::GetInstance()->SetWatchEvent(
category_name, event_name,
base::Bind(&InProcessTraceController::OnWatchEventMatched,
base::Unretained(this))) &&
BeginTracing(category_patterns);
return BeginTracing(category_patterns) &&
content::TraceController::GetInstance()->SetWatchEvent(
this, category_name, event_name);
}
bool WaitForWatchEvent(base::TimeDelta timeout) {
......@@ -73,16 +67,20 @@ class InProcessTraceController {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
using namespace base::debug;
if (!content::TracingController::GetInstance()->DisableRecording(
base::FilePath(),
base::Bind(&InProcessTraceController::OnTraceDataCollected,
base::Unretained(this),
base::Unretained(json_trace_output))))
return false;
TraceResultBuffer::SimpleOutput output;
trace_buffer_.SetOutputCallback(output.GetCallback());
trace_buffer_.Start();
if (!content::TraceController::GetInstance()->EndTracingAsync(this))
return false;
// Wait for OnEndTracingComplete() to quit the message loop.
// OnTraceDataCollected may be called multiple times while blocking here.
message_loop_runner_ = new content::MessageLoopRunner;
message_loop_runner_->Run();
trace_buffer_.Finish();
trace_buffer_.SetOutputCallback(TraceResultBuffer::OutputCallback());
*json_trace_output = output.json_output;
// Watch notifications can occur during this method's message loop run, but
// not after, so clear them here.
......@@ -93,40 +91,19 @@ class InProcessTraceController {
private:
friend struct DefaultSingletonTraits<InProcessTraceController>;
void OnEndTracingComplete() {
// TraceSubscriber implementation
virtual void OnEndTracingComplete() OVERRIDE {
message_loop_runner_->Quit();
}
void OnTraceDataCollected(std::string* json_trace_output,
const base::FilePath& path) {
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&InProcessTraceController::ReadTraceData,
base::Unretained(this),
base::Unretained(json_trace_output),
path));
// TraceSubscriber implementation
virtual void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE {
trace_buffer_.AddFragment(trace_fragment->data());
}
void ReadTraceData(std::string* json_trace_output,
const base::FilePath& path) {
json_trace_output->clear();
bool ok = base::ReadFileToString(path, json_trace_output);
DCHECK(ok);
base::DeleteFile(path, false);
// The callers expect an array of trace events.
const char* preamble = "{\"traceEvents\": ";
const char* trailout = "}";
DCHECK(StartsWithASCII(*json_trace_output, preamble, true));
DCHECK(EndsWith(*json_trace_output, trailout, true));
json_trace_output->erase(0, strlen(preamble));
json_trace_output->erase(json_trace_output->end() - 1);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&InProcessTraceController::OnEndTracingComplete,
base::Unretained(this)));
}
void OnWatchEventMatched() {
// TraceSubscriber implementation
virtual void OnEventWatchNotification() OVERRIDE {
if (watch_notification_count_ == 0)
return;
if (--watch_notification_count_ == 0) {
......@@ -141,6 +118,9 @@ class InProcessTraceController {
message_loop_runner_->Quit();
}
// For collecting trace data asynchronously.
base::debug::TraceResultBuffer trace_buffer_;
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
base::OneShotTimer<InProcessTraceController> timer_;
......
......@@ -19,11 +19,14 @@ ChildTraceMessageFilter::ChildTraceMessageFilter(
void ChildTraceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
channel_ = channel;
TraceLog::GetInstance()->SetNotificationCallback(
base::Bind(&ChildTraceMessageFilter::OnTraceNotification, this));
channel_->Send(new TracingHostMsg_ChildSupportsTracing());
}
void ChildTraceMessageFilter::OnFilterRemoved() {
channel_ = NULL;
TraceLog::GetInstance()->SetNotificationCallback(
TraceLog::NotificationCallback());
}
bool ChildTraceMessageFilter::OnMessageReceived(const IPC::Message& message) {
......@@ -107,24 +110,14 @@ void ChildTraceMessageFilter::OnGetTraceBufferPercentFull() {
void ChildTraceMessageFilter::OnSetWatchEvent(const std::string& category_name,
const std::string& event_name) {
TraceLog::GetInstance()->SetWatchEvent(
category_name, event_name,
base::Bind(&ChildTraceMessageFilter::OnWatchEventMatched, this));
TraceLog::GetInstance()->SetWatchEvent(category_name.c_str(),
event_name.c_str());
}
void ChildTraceMessageFilter::OnCancelWatchEvent() {
TraceLog::GetInstance()->CancelWatchEvent();
}
void ChildTraceMessageFilter::OnWatchEventMatched() {
if (!ipc_message_loop_->BelongsToCurrentThread()) {
ipc_message_loop_->PostTask(FROM_HERE,
base::Bind(&ChildTraceMessageFilter::OnWatchEventMatched, this));
return;
}
channel_->Send(new TracingHostMsg_WatchEventMatched);
}
void ChildTraceMessageFilter::OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr,
bool has_more_events) {
......@@ -164,4 +157,14 @@ void ChildTraceMessageFilter::OnMonitoringTraceDataCollected(
channel_->Send(new TracingHostMsg_CaptureMonitoringSnapshotAck());
}
void ChildTraceMessageFilter::OnTraceNotification(int notification) {
if (!ipc_message_loop_->BelongsToCurrentThread()) {
ipc_message_loop_->PostTask(FROM_HERE,
base::Bind(&ChildTraceMessageFilter::OnTraceNotification, this,
notification));
return;
}
channel_->Send(new TracingHostMsg_TraceNotification(notification));
}
} // namespace tracing
......@@ -43,7 +43,6 @@ class ChildTraceMessageFilter : public IPC::ChannelProxy::MessageFilter {
void OnSetWatchEvent(const std::string& category_name,
const std::string& event_name);
void OnCancelWatchEvent();
void OnWatchEventMatched();
// Callback from trace subsystem.
void OnTraceDataCollected(
......@@ -54,6 +53,8 @@ class ChildTraceMessageFilter : public IPC::ChannelProxy::MessageFilter {
const scoped_refptr<base::RefCountedString>& events_str_ptr,
bool has_more_events);
void OnTraceNotification(int notification);
IPC::Channel* channel_;
base::MessageLoopProxy* ipc_message_loop_;
......
......@@ -30,7 +30,7 @@ IPC_MESSAGE_CONTROL3(TracingMsg_EnableMonitoring,
base::TimeTicks /* browser_time */,
int /* base::debug::TraceLog::Options */)
// Sent to all child processes to stop monitoring.
// Sent to all child processes to stop monitoring..
IPC_MESSAGE_CONTROL0(TracingMsg_DisableMonitoring)
// Sent to all child processes to capture the current monitorint snapshot.
......@@ -47,9 +47,6 @@ IPC_MESSAGE_CONTROL2(TracingMsg_SetWatchEvent,
// Sent to all child processes to clear watch event.
IPC_MESSAGE_CONTROL0(TracingMsg_CancelWatchEvent)
// Sent everytime when a watch event is matched.
IPC_MESSAGE_CONTROL0(TracingHostMsg_WatchEventMatched);
// Notify the browser that this child process supports tracing.
IPC_MESSAGE_CONTROL0(TracingHostMsg_ChildSupportsTracing)
......@@ -60,6 +57,10 @@ IPC_MESSAGE_CONTROL1(TracingHostMsg_EndTracingAck,
// Reply from child processes acking TracingMsg_CaptureMonitoringSnapshot.
IPC_MESSAGE_CONTROL0(TracingHostMsg_CaptureMonitoringSnapshotAck)
// Sent if the trace buffer becomes full.
IPC_MESSAGE_CONTROL1(TracingHostMsg_TraceNotification,
int /* base::debug::TraceLog::Notification */)
// Child processes send back trace data in JSON chunks.
IPC_MESSAGE_CONTROL1(TracingHostMsg_TraceDataCollected,
std::string /*json trace data*/)
......
......@@ -6,9 +6,12 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "content/public/browser/tracing_controller.h"
#include "content/browser/tracing/trace_subscriber_stdio.h"
#include "content/public/browser/trace_controller.h"
#include "jni/TracingControllerAndroid_jni.h"
namespace content {
......@@ -18,9 +21,29 @@ static jlong Init(JNIEnv* env, jobject obj) {
return reinterpret_cast<intptr_t>(profiler);
}
class TracingControllerAndroid::Subscriber
: public content::TraceSubscriberStdio {
public:
Subscriber(TracingControllerAndroid* profiler, const base::FilePath& path)
: TraceSubscriberStdio(path, FILE_TYPE_ARRAY, false),
profiler_(profiler) {}
void set_profiler(TracingControllerAndroid* profiler) {
CHECK(!profiler_);
profiler_ = profiler;
}
virtual void OnEndTracingComplete() OVERRIDE {
TraceSubscriberStdio::OnEndTracingComplete();
profiler_->OnTracingStopped();
}
private:
TracingControllerAndroid* profiler_;
};
TracingControllerAndroid::TracingControllerAndroid(JNIEnv* env, jobject obj)
: weak_java_object_(env, obj),
weak_factory_(this) {}
: weak_java_object_(env, obj) {}
TracingControllerAndroid::~TracingControllerAndroid() {}
......@@ -33,37 +56,39 @@ bool TracingControllerAndroid::StartTracing(JNIEnv* env,
jstring jfilename,
jstring jcategories,
jboolean record_continuously) {
file_path_ = base::FilePath(
base::android::ConvertJavaStringToUTF8(env, jfilename));
if (subscriber_.get()) {
return false;
}
std::string filename = base::android::ConvertJavaStringToUTF8(env, jfilename);
std::string categories =
base::android::ConvertJavaStringToUTF8(env, jcategories);
// This log is required by adb_profile_chrome.py.
LOG(WARNING) << "Logging performance trace to file: " << file_path_.value();
return TracingController::GetInstance()->EnableRecording(
subscriber_.reset(new Subscriber(this, base::FilePath(filename)));
return TraceController::GetInstance()->BeginTracing(
subscriber_.get(),
categories,
record_continuously ? TracingController::RECORD_CONTINUOUSLY
: TracingController::DEFAULT_OPTIONS,
TracingController::EnableRecordingDoneCallback());
record_continuously ? base::debug::TraceLog::RECORD_CONTINUOUSLY
: base::debug::TraceLog::RECORD_UNTIL_FULL);
}
void TracingControllerAndroid::StopTracing(JNIEnv* env, jobject obj) {
if (!TracingController::GetInstance()->DisableRecording(
file_path_,
base::Bind(&TracingControllerAndroid::OnTracingStopped,
weak_factory_.GetWeakPtr()))) {
if (!subscriber_.get()) {
return;
}
TraceController* controller = TraceController::GetInstance();
if (!controller->EndTracingAsync(subscriber_.get())) {
LOG(ERROR) << "EndTracingAsync failed, forcing an immediate stop";
OnTracingStopped(file_path_);
controller->CancelSubscriber(subscriber_.get());
OnTracingStopped();
}
}
void TracingControllerAndroid::OnTracingStopped(
const base::FilePath& file_path) {
void TracingControllerAndroid::OnTracingStopped() {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env);
if (obj.obj())
if (obj.obj()) {
Java_TracingControllerAndroid_onTracingStopped(env, obj.obj());
}
subscriber_.reset();
}
static jstring GetDefaultCategories(JNIEnv* env, jobject obj) {
......
......@@ -6,8 +6,7 @@
#define CONTENT_BROWSER_ANDROID_TRACING_CONTROLLER_ANDROID_H_
#include "base/android/jni_helper.h"
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "base/memory/scoped_ptr.h"
namespace content {
......@@ -26,11 +25,12 @@ class TracingControllerAndroid {
private:
~TracingControllerAndroid();
void OnTracingStopped(const base::FilePath& file_path);
void OnTracingStopped();
JavaObjectWeakGlobalRef weak_java_object_;
base::FilePath file_path_;
base::WeakPtrFactory<TracingControllerAndroid> weak_factory_;
class Subscriber;
scoped_ptr<Subscriber> subscriber_;
DISALLOW_COPY_AND_ASSIGN(TracingControllerAndroid);
};
......
......@@ -6,18 +6,14 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/location.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "content/browser/devtools/devtools_http_handler_impl.h"
#include "content/browser/devtools/devtools_protocol_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/browser/trace_controller.h"
#include "content/public/browser/trace_subscriber.h"
namespace content {
......@@ -27,23 +23,10 @@ const char kRecordUntilFull[] = "record-until-full";
const char kRecordContinuously[] = "record-continuously";
const char kEnableSampling[] = "enable-sampling";
void ReadFile(
const base::FilePath& path,
const base::Callback<void(const scoped_refptr<base::RefCountedString>&)>
callback) {
std::string trace_data;
if (!base::ReadFileToString(path, &trace_data))
LOG(ERROR) << "Failed to read file: " << path.value();
base::DeleteFile(path, false);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(callback, make_scoped_refptr(
base::RefCountedString::TakeString(&trace_data))));
}
} // namespace
DevToolsTracingHandler::DevToolsTracingHandler()
: weak_factory_(this) {
: is_running_(false) {
RegisterCommandHandler(devtools::Tracing::start::kName,
base::Bind(&DevToolsTracingHandler::OnStart,
base::Unretained(this)));
......@@ -55,60 +38,28 @@ DevToolsTracingHandler::DevToolsTracingHandler()
DevToolsTracingHandler::~DevToolsTracingHandler() {
}
void DevToolsTracingHandler::BeginReadingRecordingResult(
const base::FilePath& path) {
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&ReadFile, path,
base::Bind(&DevToolsTracingHandler::ReadRecordingResult,
weak_factory_.GetWeakPtr())));
}
void DevToolsTracingHandler::ReadRecordingResult(
const scoped_refptr<base::RefCountedString>& trace_data) {
if (trace_data->data().size()) {
scoped_ptr<base::Value> trace_value(base::JSONReader::Read(
trace_data->data()));
DictionaryValue* dictionary = NULL;
bool ok = trace_value->GetAsDictionary(&dictionary);
DCHECK(ok);
ListValue* list = NULL;
ok = dictionary->GetList("traceEvents", &list);
DCHECK(ok);
std::string buffer;
for (size_t i = 0; i < list->GetSize(); ++i) {
std::string item;
base::Value* item_value;
list->Get(i, &item_value);
base::JSONWriter::Write(item_value, &item);
if (buffer.size())
buffer.append(",");
buffer.append(item);
if (i % 1000 == 0) {
OnTraceDataCollected(buffer);
buffer.clear();
}
}
if (buffer.size())
OnTraceDataCollected(buffer);
}
void DevToolsTracingHandler::OnEndTracingComplete() {
is_running_ = false;
SendNotification(devtools::Tracing::tracingComplete::kName, NULL);
}
void DevToolsTracingHandler::OnTraceDataCollected(
const std::string& trace_fragment) {
// Hand-craft protocol notification message so we can substitute JSON
// that we already got as string as a bare object, not a quoted string.
std::string message = base::StringPrintf(
"{ \"method\": \"%s\", \"params\": { \"%s\": [ %s ] } }",
devtools::Tracing::dataCollected::kName,
devtools::Tracing::dataCollected::kValue,
trace_fragment.c_str());
SendRawMessage(message);
const scoped_refptr<base::RefCountedString>& trace_fragment) {
if (is_running_) {
// Hand-craft protocol notification message so we can substitute JSON
// that we already got as string as a bare object, not a quoted string.
std::string message = base::StringPrintf(
"{ \"method\": \"%s\", \"params\": { \"%s\": [ %s ] } }",
devtools::Tracing::dataCollected::kName,
devtools::Tracing::dataCollected::kValue,
trace_fragment->data().c_str());
SendRawMessage(message);
}
}
TracingController::Options DevToolsTracingHandler::TraceOptionsFromString(
// Note, if you add more options here you also need to update:
// base/debug/trace_event_impl:TraceOptionsFromString
base::debug::TraceLog::Options DevToolsTracingHandler::TraceOptionsFromString(
const std::string& options) {
std::vector<std::string> split;
std::vector<std::string>::iterator iter;
......@@ -117,14 +68,18 @@ TracingController::Options DevToolsTracingHandler::TraceOptionsFromString(
base::SplitString(options, ',', &split);
for (iter = split.begin(); iter != split.end(); ++iter) {
if (*iter == kRecordUntilFull) {
ret &= ~TracingController::RECORD_CONTINUOUSLY;
ret |= base::debug::TraceLog::RECORD_UNTIL_FULL;
} else if (*iter == kRecordContinuously) {
ret |= TracingController::RECORD_CONTINUOUSLY;
ret |= base::debug::TraceLog::RECORD_CONTINUOUSLY;
} else if (*iter == kEnableSampling) {
ret |= TracingController::ENABLE_SAMPLING;
ret |= base::debug::TraceLog::ENABLE_SAMPLING;
}
}
return static_cast<TracingController::Options>(ret);
if (!(ret & base::debug::TraceLog::RECORD_UNTIL_FULL) &&
!(ret & base::debug::TraceLog::RECORD_CONTINUOUSLY))
ret |= base::debug::TraceLog::RECORD_UNTIL_FULL;
return static_cast<base::debug::TraceLog::Options>(ret);
}
scoped_refptr<DevToolsProtocol::Response>
......@@ -135,26 +90,23 @@ DevToolsTracingHandler::OnStart(
if (params)
params->GetString(devtools::Tracing::start::kCategories, &categories);
TracingController::Options options = TracingController::DEFAULT_OPTIONS;
base::debug::TraceLog::Options options =
base::debug::TraceLog::RECORD_UNTIL_FULL;
if (params && params->HasKey(devtools::Tracing::start::kTraceOptions)) {
std::string options_param;
params->GetString(devtools::Tracing::start::kTraceOptions, &options_param);
options = TraceOptionsFromString(options_param);
}
TracingController::GetInstance()->EnableRecording(
categories, options,
TracingController::EnableRecordingDoneCallback());
TraceController::GetInstance()->BeginTracing(this, categories, options);
is_running_ = true;
return command->SuccessResponse(NULL);
}
scoped_refptr<DevToolsProtocol::Response>
DevToolsTracingHandler::OnEnd(
scoped_refptr<DevToolsProtocol::Command> command) {
TracingController::GetInstance()->DisableRecording(
base::FilePath(),
base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult,
weak_factory_.GetWeakPtr()));
TraceController::GetInstance()->EndTracingAsync(this);
return command->SuccessResponse(NULL);
}
......
......@@ -5,36 +5,36 @@
#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_TRACING_HANDLER_H_
#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_TRACING_HANDLER_H_
#include "base/memory/weak_ptr.h"
#include "base/debug/trace_event.h"
#include "content/browser/devtools/devtools_protocol.h"
#include "content/public/browser/tracing_controller.h"
namespace base {
class RefCountedString;
}
#include "content/public/browser/trace_subscriber.h"
namespace content {
// This class bridges DevTools remote debugging server with the trace
// infrastructure.
class DevToolsTracingHandler : public DevToolsProtocol::Handler {
class DevToolsTracingHandler
: public TraceSubscriber,
public DevToolsProtocol::Handler {
public:
DevToolsTracingHandler();
virtual ~DevToolsTracingHandler();
private:
void BeginReadingRecordingResult(const base::FilePath& path);
void ReadRecordingResult(const scoped_refptr<base::RefCountedString>& result);
void OnTraceDataCollected(const std::string& trace_fragment);
// TraceSubscriber:
virtual void OnEndTracingComplete() OVERRIDE;;
virtual void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
private:
scoped_refptr<DevToolsProtocol::Response> OnStart(
scoped_refptr<DevToolsProtocol::Command> command);
scoped_refptr<DevToolsProtocol::Response> OnEnd(
scoped_refptr<DevToolsProtocol::Command> command);
TracingController::Options TraceOptionsFromString(const std::string& options);
base::debug::TraceLog::Options TraceOptionsFromString(
const std::string& options);
base::WeakPtrFactory<DevToolsTracingHandler> weak_factory_;
bool is_running_;
DISALLOW_COPY_AND_ASSIGN(DevToolsTracingHandler);
};
......
......@@ -101,6 +101,7 @@
#include "content/browser/speech/speech_recognition_dispatcher_host.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/streams/stream_context.h"
#include "content/browser/tracing/trace_controller_impl.h"
#include "content/browser/tracing/trace_message_filter.h"
#include "content/browser/vibration/vibration_message_filter.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
......
This diff is collapsed.
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_TRACING_TRACE_CONTROLLER_IMPL_H_
#define CONTENT_BROWSER_TRACING_TRACE_CONTROLLER_IMPL_H_
#include <set>
#include <string>
#include <vector>
#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "content/public/browser/trace_controller.h"
class CommandLine;
namespace content {
class TraceMessageFilter;
class TraceControllerImpl : public TraceController {
public:
static TraceControllerImpl* GetInstance();
// TraceController implementation:
virtual bool BeginTracing(TraceSubscriber* subscriber,
const std::string& category_patterns,
base::debug::TraceLog::Options options) OVERRIDE;
virtual bool EndTracingAsync(TraceSubscriber* subscriber) OVERRIDE;
virtual bool GetTraceBufferPercentFullAsync(
TraceSubscriber* subscriber) OVERRIDE;
virtual bool SetWatchEvent(TraceSubscriber* subscriber,
const std::string& category_name,
const std::string& event_name) OVERRIDE;
virtual bool CancelWatchEvent(TraceSubscriber* subscriber) OVERRIDE;
virtual void CancelSubscriber(TraceSubscriber* subscriber) OVERRIDE;
virtual bool GetKnownCategoryGroupsAsync(TraceSubscriber* subscriber)
OVERRIDE;
private:
typedef std::set<scoped_refptr<TraceMessageFilter> > FilterMap;
friend struct base::DefaultLazyInstanceTraits<TraceControllerImpl>;
friend class TraceMessageFilter;
TraceControllerImpl();
virtual ~TraceControllerImpl();
bool is_tracing_enabled() const {
return can_end_tracing();
}
bool can_end_tracing() const {
return is_tracing_ && pending_end_ack_count_ == 0;
}
// Can get Buffer Percent Full
bool can_get_buffer_percent_full() const {
return is_tracing_ &&
pending_end_ack_count_ == 0 &&
pending_bpf_ack_count_ == 0;
}
bool can_begin_tracing(TraceSubscriber* subscriber) const {
return !is_tracing_ &&
(subscriber_ == NULL || subscriber == subscriber_);
}
// Methods for use by TraceMessageFilter.
void AddFilter(TraceMessageFilter* filter);
void RemoveFilter(TraceMessageFilter* filter);
void OnTracingBegan(TraceSubscriber* subscriber);
void OnEndTracingAck(const std::vector<std::string>& known_category_groups);
void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr);
void OnTraceNotification(int notification);
void OnTraceBufferPercentFullReply(float percent_full);
// Callback of TraceLog::Flush() for the local trace.
void OnLocalTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr,
bool has_more_events);
FilterMap filters_;
TraceSubscriber* subscriber_;
// Pending acks for EndTracingAsync:
int pending_end_ack_count_;
// Pending acks for GetTraceBufferPercentFullAsync:
int pending_bpf_ack_count_;
float maximum_bpf_;
bool is_tracing_;
bool is_get_category_groups_;
std::set<std::string> known_category_groups_;
std::string watch_category_;
std::string watch_name_;
base::debug::TraceLog::Options trace_options_;
base::debug::CategoryFilter category_filter_;
DISALLOW_COPY_AND_ASSIGN(TraceControllerImpl);
};
} // namespace content
#endif // CONTENT_BROWSER_TRACING_TRACE_CONTROLLER_IMPL_H_
......@@ -5,6 +5,7 @@
#include "content/browser/tracing/trace_message_filter.h"
#include "components/tracing/tracing_messages.h"
#include "content/browser/tracing/trace_controller_impl.h"
#include "content/browser/tracing/tracing_controller_impl.h"
namespace content {
......@@ -16,8 +17,6 @@ TraceMessageFilter::TraceMessageFilter() :
is_awaiting_buffer_percent_full_ack_(false) {
}
TraceMessageFilter::~TraceMessageFilter() {}
void TraceMessageFilter::OnChannelClosing() {
if (has_child_) {
if (is_awaiting_end_ack_)
......@@ -29,7 +28,8 @@ void TraceMessageFilter::OnChannelClosing() {
if (is_awaiting_buffer_percent_full_ack_)
OnTraceBufferPercentFullReply(0.0f);
TracingControllerImpl::GetInstance()->RemoveTraceMessageFilter(this);
TraceControllerImpl::GetInstance()->RemoveFilter(this);
TracingControllerImpl::GetInstance()->RemoveFilter(this);
}
}
......@@ -47,8 +47,8 @@ bool TraceMessageFilter::OnMessageReceived(const IPC::Message& message,
OnTraceDataCollected)
IPC_MESSAGE_HANDLER(TracingHostMsg_MonitoringTraceDataCollected,
OnMonitoringTraceDataCollected)
IPC_MESSAGE_HANDLER(TracingHostMsg_WatchEventMatched,
OnWatchEventMatched)
IPC_MESSAGE_HANDLER(TracingHostMsg_TraceNotification,
OnTraceNotification)
IPC_MESSAGE_HANDLER(TracingHostMsg_TraceBufferPercentFullReply,
OnTraceBufferPercentFullReply)
IPC_MESSAGE_UNHANDLED(handled = false)
......@@ -109,9 +109,12 @@ void TraceMessageFilter::SendCancelWatchEvent() {
Send(new TracingMsg_CancelWatchEvent);
}
TraceMessageFilter::~TraceMessageFilter() {}
void TraceMessageFilter::OnChildSupportsTracing() {
has_child_ = true;
TracingControllerImpl::GetInstance()->AddTraceMessageFilter(this);
TraceControllerImpl::GetInstance()->AddFilter(this);
TracingControllerImpl::GetInstance()->AddFilter(this);
}
void TraceMessageFilter::OnEndTracingAck(
......@@ -120,6 +123,7 @@ void TraceMessageFilter::OnEndTracingAck(
// child process is compromised.
if (is_awaiting_end_ack_) {
is_awaiting_end_ack_ = false;
TraceControllerImpl::GetInstance()->OnEndTracingAck(known_categories);
TracingControllerImpl::GetInstance()->OnDisableRecordingAcked(
known_categories);
} else {
......@@ -141,6 +145,7 @@ void TraceMessageFilter::OnCaptureMonitoringSnapshotAcked() {
void TraceMessageFilter::OnTraceDataCollected(const std::string& data) {
scoped_refptr<base::RefCountedString> data_ptr(new base::RefCountedString());
data_ptr->data() = data;
TraceControllerImpl::GetInstance()->OnTraceDataCollected(data_ptr);
TracingControllerImpl::GetInstance()->OnTraceDataCollected(data_ptr);
}
......@@ -152,13 +157,15 @@ void TraceMessageFilter::OnMonitoringTraceDataCollected(
data_ptr);
}
void TraceMessageFilter::OnWatchEventMatched() {
TracingControllerImpl::GetInstance()->OnWatchEventMatched();
void TraceMessageFilter::OnTraceNotification(int notification) {
TraceControllerImpl::GetInstance()->OnTraceNotification(notification);
}
void TraceMessageFilter::OnTraceBufferPercentFullReply(float percent_full) {
if (is_awaiting_buffer_percent_full_ack_) {
is_awaiting_buffer_percent_full_ack_ = false;
TraceControllerImpl::GetInstance()->OnTraceBufferPercentFullReply(
percent_full);
TracingControllerImpl::GetInstance()->OnTraceBufferPercentFullReply(
percent_full);
} else {
......
......@@ -45,7 +45,7 @@ class TraceMessageFilter : public BrowserMessageFilter {
void OnChildSupportsTracing();
void OnEndTracingAck(const std::vector<std::string>& known_categories);
void OnCaptureMonitoringSnapshotAcked();
void OnWatchEventMatched();
void OnTraceNotification(int notification);
void OnTraceBufferPercentFullReply(float percent_full);
void OnTraceDataCollected(const std::string& data);
void OnMonitoringTraceDataCollected(const std::string& data);
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/tracing/trace_subscriber_stdio.h"
#include "base/bind.h"
#include "base/debug/trace_event.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/threading/sequenced_worker_pool.h"
#include "content/public/browser/browser_thread.h"
namespace content {
// All method calls on this class are done on a SequencedWorkerPool thread.
class TraceSubscriberStdio::TraceSubscriberStdioWorker
: public base::RefCountedThreadSafe<TraceSubscriberStdioWorker> {
public:
TraceSubscriberStdioWorker(const base::FilePath& path,
FileType file_type,
bool has_system_trace)
: path_(path),
file_type_(file_type),
has_system_trace_(has_system_trace),
file_(0),
needs_comma_(false),
wrote_trace_(false),
has_pending_system_trace_(false),
wrote_system_trace_(false) {}
void OnTraceStart() {
DCHECK(!file_);
file_ = file_util::OpenFile(path_, "w+");
if (!IsValid()) {
LOG(ERROR) << "Failed to open performance trace file: " << path_.value();
return;
}
VLOG(0) << "Logging performance trace to file: " << path_.value();
if (file_type_ == FILE_TYPE_PROPERTY_LIST)
WriteString("{\"traceEvents\":");
WriteString("[");
}
void OnTraceData(const scoped_refptr<base::RefCountedString>& data_ptr) {
if (!IsValid())
return;
DCHECK(!data_ptr->data().empty());
if (needs_comma_)
WriteString(",");
WriteString(data_ptr->data());
needs_comma_ = true;
}
void OnSystemTraceData(
const scoped_refptr<base::RefCountedString>& data_ptr) {
if (wrote_trace_) {
WriteSystemTrace(data_ptr);
End();
} else {
pending_system_trace_ = data_ptr;
has_pending_system_trace_ = true;
}
}
void OnTraceEnd() {
if (!IsValid())
return;
WriteString("]");
wrote_trace_ = true;
if (!has_system_trace_ || wrote_system_trace_) {
End();
return;
}
WriteString(",");
if (has_pending_system_trace_) {
WriteSystemTrace(pending_system_trace_);
End();
}
}
private:
friend class base::RefCountedThreadSafe<TraceSubscriberStdioWorker>;
~TraceSubscriberStdioWorker() {
CloseFile();
}
bool IsValid() const {
return file_ && (0 == ferror(file_));
}
void CloseFile() {
if (file_) {
fclose(file_);
file_ = 0;
}
}
void End() {
if (file_type_ == FILE_TYPE_PROPERTY_LIST)
WriteString("}");
CloseFile();
}
void WriteSystemTrace(const scoped_refptr<base::RefCountedString>& data_ptr) {
// Newlines need to be replaced with the string "\n" to be parsed correctly.
// Double quotes need to be replaced with the string "\"".
// System logs are ASCII.
const std::string& data = data_ptr->data();
const char* chars = data.c_str();
WriteString("\"systemTraceEvents\":\"");
size_t old_index = 0;
for (size_t new_index = data.find_first_of("\n\"");
std::string::npos != new_index;
old_index = new_index + 1,
new_index = data.find_first_of("\n\"", old_index)) {
WriteChars(chars + old_index, new_index - old_index);
if (chars[new_index] == '\n')
WriteChars("\\n", 2);
else
WriteChars("\\\"", 2);
}
WriteChars(chars + old_index, data.size() - old_index);
WriteString("\"");
wrote_system_trace_ = true;
}
void WriteChars(const char* output_chars, size_t size) {
if (size == 0)
return;
if (IsValid()) {
size_t written = fwrite(output_chars, 1, size, file_);
if (written != size) {
LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file";
CloseFile();
}
}
}
void WriteString(const std::string& output_str) {
WriteChars(output_str.data(), output_str.size());
}
base::FilePath path_;
const FileType file_type_;
const bool has_system_trace_;
FILE* file_;
bool needs_comma_;
bool wrote_trace_;
bool has_pending_system_trace_;
bool wrote_system_trace_;
scoped_refptr<base::RefCountedString> pending_system_trace_;
DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdioWorker);
};
TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path,
FileType file_type,
bool has_system_trace)
: worker_(new TraceSubscriberStdioWorker(path,
file_type,
has_system_trace)) {
if (has_system_trace)
CHECK_EQ(FILE_TYPE_PROPERTY_LIST, file_type);
BrowserThread::PostBlockingPoolSequencedTask(
__FILE__, FROM_HERE,
base::Bind(&TraceSubscriberStdioWorker::OnTraceStart, worker_));
}
TraceSubscriberStdio::~TraceSubscriberStdio() {
}
void TraceSubscriberStdio::OnEndTracingComplete() {
BrowserThread::PostBlockingPoolSequencedTask(
__FILE__, FROM_HERE,
base::Bind(&TraceSubscriberStdioWorker::OnTraceEnd, worker_));
}
void TraceSubscriberStdio::OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& data_ptr) {
BrowserThread::PostBlockingPoolSequencedTask(
__FILE__, FROM_HERE,
base::Bind(&TraceSubscriberStdioWorker::OnTraceData, worker_, data_ptr));
}
void TraceSubscriberStdio::OnEndSystemTracing(
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
BrowserThread::PostBlockingPoolSequencedTask(
__FILE__, FROM_HERE,
base::Bind(&TraceSubscriberStdioWorker::OnSystemTraceData,
worker_,
events_str_ptr));
}
} // namespace content
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_TRACING_TRACE_SUBSCRIBER_STDIO_H_
#define CONTENT_BROWSER_TRACING_TRACE_SUBSCRIBER_STDIO_H_
#include <string>
#include "base/compiler_specific.h"
#include "content/public/browser/trace_subscriber.h"
#include "content/common/content_export.h"
namespace base {
class FilePath;
}
namespace content {
// Stdio implementation of TraceSubscriber. Use this to write traces to a file.
class CONTENT_EXPORT TraceSubscriberStdio
: NON_EXPORTED_BASE(public TraceSubscriber) {
public:
enum FileType {
// Output file as array, representing trace events:
// [event1, event2, ...]
FILE_TYPE_ARRAY,
// Output file as property list with one or two items:
// {traceEvents: [event1, event2, ...],
// systemTraceEvents: "event1\nevent2\n..." // optional}
FILE_TYPE_PROPERTY_LIST
};
// has_system_trace indicates whether system trace events are expected.
TraceSubscriberStdio(const base::FilePath& path,
FileType file_type,
bool has_system_trace);
virtual ~TraceSubscriberStdio();
// Implementation of TraceSubscriber
virtual void OnEndTracingComplete() OVERRIDE;
virtual void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& data_ptr) OVERRIDE;
// To be used as callback to DebugDaemonClient::RequestStopSystemTracing().
virtual void OnEndSystemTracing(
const scoped_refptr<base::RefCountedString>& events_str_ptr);
private:
class TraceSubscriberStdioWorker;
scoped_refptr<TraceSubscriberStdioWorker> worker_;
DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdio);
};
} // namespace content
#endif // CONTENT_BROWSER_TRACING_TRACE_SUBSCRIBER_STDIO_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/tracing/trace_subscriber_stdio.h"
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/threading/sequenced_worker_pool.h"
#include "content/public/browser/browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
class TraceSubscriberStdioTest : public ::testing::Test {};
TEST_F(TraceSubscriberStdioTest, CanWriteArray) {
base::ScopedTempDir trace_dir;
ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
{
TraceSubscriberStdio subscriber(trace_file,
TraceSubscriberStdio::FILE_TYPE_ARRAY,
false);
std::string foo("foo");
subscriber.OnTraceDataCollected(
make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
std::string bar("bar");
subscriber.OnTraceDataCollected(
make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
subscriber.OnEndTracingComplete();
}
BrowserThread::GetBlockingPool()->FlushForTesting();
std::string result;
EXPECT_TRUE(base::ReadFileToString(trace_file, &result));
EXPECT_EQ("[foo,bar]", result);
}
TEST_F(TraceSubscriberStdioTest, CanWritePropertyList) {
base::ScopedTempDir trace_dir;
ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
{
TraceSubscriberStdio subscriber(
trace_file,
TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
false);
std::string foo("foo");
subscriber.OnTraceDataCollected(
make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
std::string bar("bar");
subscriber.OnTraceDataCollected(
make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
subscriber.OnEndTracingComplete();
}
BrowserThread::GetBlockingPool()->FlushForTesting();
std::string result;
EXPECT_TRUE(base::ReadFileToString(trace_file, &result));
EXPECT_EQ("{\"traceEvents\":[foo,bar]}", result);
}
TEST_F(TraceSubscriberStdioTest, CanWriteSystemDataFirst) {
base::ScopedTempDir trace_dir;
ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
{
TraceSubscriberStdio subscriber(
trace_file,
TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
true);
std::string foo("foo");
subscriber.OnTraceDataCollected(
make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
std::string bar("bar");
subscriber.OnTraceDataCollected(
make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
std::string systemTrace("event1\nev\"ent\"2\n");
subscriber.OnEndSystemTracing(
make_scoped_refptr(base::RefCountedString::TakeString(&systemTrace)));
subscriber.OnEndTracingComplete();
}
BrowserThread::GetBlockingPool()->FlushForTesting();
std::string result;
EXPECT_TRUE(base::ReadFileToString(trace_file, &result));
EXPECT_EQ(
"{\"traceEvents\":[foo,bar],\""
"systemTraceEvents\":\"event1\\nev\\\"ent\\\"2\\n\"}",
result);
}
TEST_F(TraceSubscriberStdioTest, CanWriteSystemDataLast) {
base::ScopedTempDir trace_dir;
ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
{
TraceSubscriberStdio subscriber(
trace_file,
TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
true);
std::string foo("foo");
subscriber.OnTraceDataCollected(
make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
std::string bar("bar");
subscriber.OnTraceDataCollected(
make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
std::string systemTrace("event1\nev\"ent\"2\n");
subscriber.OnEndTracingComplete();
subscriber.OnEndSystemTracing(
make_scoped_refptr(base::RefCountedString::TakeString(&systemTrace)));
}
BrowserThread::GetBlockingPool()->FlushForTesting();
std::string result;
EXPECT_TRUE(base::ReadFileToString(trace_file, &result));
EXPECT_EQ(
"{\"traceEvents\":[foo,bar],\""
"systemTraceEvents\":\"event1\\nev\\\"ent\\\"2\\n\"}",
result);
}
} // namespace content
......@@ -122,7 +122,8 @@ class TracingControllerTest : public ContentBrowserTest {
base::Unretained(this),
run_loop.QuitClosure());
bool result = controller->EnableRecording(
"", TracingController::DEFAULT_OPTIONS, callback);
base::debug::CategoryFilter(""), TracingController::Options(),
callback);
ASSERT_TRUE(result);
run_loop.Run();
EXPECT_EQ(enable_recording_done_callback_count(), 1);
......@@ -154,7 +155,8 @@ class TracingControllerTest : public ContentBrowserTest {
base::Unretained(this),
run_loop.QuitClosure());
bool result = controller->EnableMonitoring(
"", TracingController::ENABLE_SAMPLING, callback);
base::debug::CategoryFilter(""), TracingController::ENABLE_SAMPLING,
callback);
ASSERT_TRUE(result);
run_loop.Run();
EXPECT_EQ(enable_monitoring_done_callback_count(), 1);
......@@ -167,8 +169,7 @@ class TracingControllerTest : public ContentBrowserTest {
CaptureMonitoringSnapshotDoneCallbackTest,
base::Unretained(this),
run_loop.QuitClosure());
ASSERT_TRUE(controller->CaptureMonitoringSnapshot(result_file_path,
callback));
controller->CaptureMonitoringSnapshot(result_file_path, callback);
run_loop.Run();
EXPECT_EQ(capture_monitoring_snapshot_done_callback_count(), 1);
}
......@@ -207,7 +208,7 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) {
base::Bind(&TracingControllerTest::GetCategoriesDoneCallbackTest,
base::Unretained(this),
run_loop.QuitClosure());
ASSERT_TRUE(controller->GetCategories(callback));
controller->GetCategories(callback);
run_loop.Run();
EXPECT_EQ(get_categories_done_callback_count(), 1);
}
......@@ -230,7 +231,7 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest,
TracingController* controller = TracingController::GetInstance();
EXPECT_TRUE(controller->EnableRecording(
"", TracingController::DEFAULT_OPTIONS,
base::debug::CategoryFilter(""), TracingController::Options(),
TracingController::EnableRecordingDoneCallback()));
EXPECT_TRUE(controller->DisableRecording(
base::FilePath(), TracingController::TracingFileResultCallback()));
......@@ -257,7 +258,7 @@ IN_PROC_BROWSER_TEST_F(
TracingController* controller = TracingController::GetInstance();
EXPECT_TRUE(controller->EnableMonitoring(
"", TracingController::ENABLE_SAMPLING,
base::debug::CategoryFilter(""), TracingController::ENABLE_SAMPLING,
TracingController::EnableMonitoringDoneCallback()));
controller->CaptureMonitoringSnapshot(
base::FilePath(), TracingController::TracingFileResultCallback());
......
......@@ -11,12 +11,9 @@
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "content/public/browser/trace_subscriber.h"
#include "content/public/browser/tracing_controller.h"
namespace base {
class RefCountedString;
}
namespace content {
class TraceMessageFilter;
......@@ -26,36 +23,32 @@ class TracingControllerImpl : public TracingController {
static TracingControllerImpl* GetInstance();
// TracingController implementation.
virtual bool GetCategories(
virtual void GetCategories(
const GetCategoriesDoneCallback& callback) OVERRIDE;
virtual bool EnableRecording(
const std::string& category_filter,
const base::debug::CategoryFilter& filter,
TracingController::Options options,
const EnableRecordingDoneCallback& callback) OVERRIDE;
virtual bool DisableRecording(
const base::FilePath& result_file_path,
const TracingFileResultCallback& callback) OVERRIDE;
virtual bool EnableMonitoring(const std::string& category_filter,
virtual bool EnableMonitoring(const base::debug::CategoryFilter& filter,
TracingController::Options options,
const EnableMonitoringDoneCallback& callback) OVERRIDE;
virtual bool DisableMonitoring(
const DisableMonitoringDoneCallback& callback) OVERRIDE;
virtual void GetMonitoringStatus(
bool* out_enabled,
std::string* out_category_filter,
base::debug::CategoryFilter* out_filter,
TracingController::Options* out_options) OVERRIDE;
virtual bool CaptureMonitoringSnapshot(
virtual void CaptureMonitoringSnapshot(
const base::FilePath& result_file_path,
const TracingFileResultCallback& callback) OVERRIDE;
virtual bool GetTraceBufferPercentFull(
const GetTraceBufferPercentFullCallback& callback) OVERRIDE;
virtual bool SetWatchEvent(const std::string& category_name,
const std::string& event_name,
const WatchEventCallback& callback) OVERRIDE;
virtual bool CancelWatchEvent() OVERRIDE;
private:
typedef std::set<scoped_refptr<TraceMessageFilter> > TraceMessageFilterMap;
typedef std::set<scoped_refptr<TraceMessageFilter> > FilterMap;
class ResultFile;
friend struct base::DefaultLazyInstanceTraits<TracingControllerImpl>;
......@@ -84,13 +77,9 @@ class TracingControllerImpl : public TracingController {
return pending_trace_buffer_percent_full_callback_.is_null();
}
bool can_cancel_watch_event() const {
return !watch_event_callback_.is_null();
}
// Methods for use by TraceMessageFilter.
void AddTraceMessageFilter(TraceMessageFilter* trace_message_filter);
void RemoveTraceMessageFilter(TraceMessageFilter* trace_message_filter);
void AddFilter(TraceMessageFilter* filter);
void RemoveFilter(TraceMessageFilter* filter);
void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr);
......@@ -113,11 +102,10 @@ class TracingControllerImpl : public TracingController {
void OnCaptureMonitoringSnapshotAcked();
void OnMonitoringSnapshotFileClosed();
void OnTraceNotification(int notification);
void OnTraceBufferPercentFullReply(float percent_full);
void OnWatchEventMatched();
TraceMessageFilterMap trace_message_filters_;
FilterMap filters_;
// Pending acks for DisableRecording.
int pending_disable_recording_ack_count_;
// Pending acks for CaptureMonitoringSnapshot.
......@@ -134,11 +122,8 @@ class TracingControllerImpl : public TracingController {
TracingFileResultCallback pending_capture_monitoring_snapshot_done_callback_;
GetTraceBufferPercentFullCallback pending_trace_buffer_percent_full_callback_;
std::string watch_category_name_;
std::string watch_event_name_;
WatchEventCallback watch_event_callback_;
std::set<std::string> known_category_groups_;
base::debug::CategoryFilter category_filter_;
scoped_ptr<ResultFile> result_file_;
scoped_ptr<ResultFile> monitoring_snapshot_file_;
DISALLOW_COPY_AND_ASSIGN(TracingControllerImpl);
......
......@@ -86,10 +86,11 @@ bool OnBeginRecording(const std::string& data64,
if (use_continuous_tracing)
tracing_options |= TracingController::RECORD_CONTINUOUSLY;
base::debug::CategoryFilter category_filter(category_filter_string);
return TracingController::GetInstance()->EnableRecording(
category_filter_string,
category_filter,
static_cast<TracingController::Options>(tracing_options),
base::Bind(&OnRecordingEnabledAck, callback));
base::Bind(OnRecordingEnabledAck, callback));
}
void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
......
......@@ -177,6 +177,8 @@
'public/browser/speech_recognition_session_context.h',
'public/browser/storage_partition.h',
'public/browser/stream_handle.h',
'public/browser/trace_controller.h',
'public/browser/trace_subscriber.h',
'public/browser/tracing_controller.h',
'public/browser/user_metrics.h',
'public/browser/utility_process_host.h',
......@@ -1156,8 +1158,12 @@
'browser/tcmalloc_internals_request_job.h',
'browser/theme_helper_mac.mm',
'browser/theme_helper_mac.h',
'browser/tracing/trace_controller_impl.cc',
'browser/tracing/trace_controller_impl.h',
'browser/tracing/trace_message_filter.cc',
'browser/tracing/trace_message_filter.h',
'browser/tracing/trace_subscriber_stdio.cc',
'browser/tracing/trace_subscriber_stdio.h',
'browser/tracing/tracing_controller_impl.cc',
'browser/tracing/tracing_controller_impl.h',
'browser/tracing/tracing_ui.cc',
......
......@@ -473,6 +473,7 @@
'browser/streams/stream_unittest.cc',
'browser/streams/stream_url_request_job_unittest.cc',
'browser/system_message_window_win_unittest.cc',
'browser/tracing/trace_subscriber_stdio_unittest.cc',
'browser/web_contents/aura/window_slider_unittest.cc',
'browser/web_contents/web_contents_delegate_unittest.cc',
'browser/web_contents/web_contents_impl_unittest.cc',
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_PUBLIC_BROWSER_TRACE_CONTROLLER_H_
#define CONTENT_PUBLIC_BROWSER_TRACE_CONTROLLER_H_
#include "base/debug/trace_event.h"
#include "content/common/content_export.h"
namespace content {
class TraceSubscriber;
// Note: TraceController is going to be deprecated and replaced with
// TracingController.
//
// TraceController is used on the browser processes to enable/disable
// trace status and collect trace data. Only the browser UI thread is allowed
// to interact with the TraceController object. All calls on the TraceSubscriber
// happen on the UI thread.
class TraceController {
public:
CONTENT_EXPORT static TraceController* GetInstance();
// Called by browser process to start tracing events on all processes.
//
// Currently only one subscriber is allowed at a time.
// Tracing begins immediately locally, and asynchronously on child processes
// as soon as they receive the BeginTracing request.
//
// If BeginTracing was already called previously,
// or if an EndTracingAsync is pending,
// or if another subscriber is tracing,
// BeginTracing will return false meaning it failed.
//
// |category_patterns| is a comma-delimited list of category wildcards.
// A category pattern can have an optional '-' prefix to exclude category
// groups that contain a matching category.
// All the same rules apply above, so for example, having both included and
// excluded category patterns in the same list would not be supported.
//
// |mode| is the tracing mode being used.
//
// Example: BeginTracing("test_MyTest*");
// Example: BeginTracing("test_MyTest*,test_OtherStuff");
// Example: BeginTracing("-excluded_category1,-excluded_category2");
virtual bool BeginTracing(TraceSubscriber* subscriber,
const std::string& category_patterns,
base::debug::TraceLog::Options options) = 0;
// Called by browser process to stop tracing events on all processes.
//
// Child processes typically are caching trace data and only rarely flush
// and send trace data back to the browser process. That is because it may be
// an expensive operation to send the trace data over IPC, and we would like
// to avoid much runtime overhead of tracing. So, to end tracing, we must
// asynchronously ask all child processes to flush any pending trace data.
//
// Once all child processes have acked the EndTracing request,
// TraceSubscriber will be called with OnEndTracingComplete.
//
// If a previous call to EndTracingAsync is already pending,
// or if another subscriber is tracing,
// EndTracingAsync will return false meaning it failed.
virtual bool EndTracingAsync(TraceSubscriber* subscriber) = 0;
// Get the maximum across processes of trace buffer percent full state.
// When the TraceBufferPercentFull value is determined,
// subscriber->OnTraceBufferPercentFullReply is called.
// When any child process reaches 100% full, the TraceController will end
// tracing, and call TraceSubscriber::OnEndTracingComplete.
// GetTraceBufferPercentFullAsync fails in the following conditions:
// trace is ending or disabled;
// a previous call to GetTraceBufferPercentFullAsync is pending; or
// the caller is not the current subscriber.
virtual bool GetTraceBufferPercentFullAsync(TraceSubscriber* subscriber) = 0;
// |subscriber->OnEventWatchNotification()| will be called every time the
// given event occurs on any process.
virtual bool SetWatchEvent(TraceSubscriber* subscriber,
const std::string& category_name,
const std::string& event_name) = 0;
// Cancel the watch event. If tracing is enabled, this may race with the
// watch event notification firing.
virtual bool CancelWatchEvent(TraceSubscriber* subscriber) = 0;
// Cancel the subscriber so that it will not be called when EndTracingAsync is
// acked by all child processes. This will also call EndTracingAsync
// internally if necessary.
// Safe to call even if caller is not the current subscriber.
virtual void CancelSubscriber(TraceSubscriber* subscriber) = 0;
// Get set of known category groups. This can change as new code paths are
// reached. If true is returned, subscriber->OnKnownCategoriesCollected will
// be called once the categories are retrieved from child processes.
virtual bool GetKnownCategoryGroupsAsync(TraceSubscriber* subscriber) = 0;
protected:
virtual ~TraceController() {}
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_TRACE_CONTROLLER_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_PUBLIC_BROWSER_TRACE_SUBSCRIBER_H_
#define CONTENT_PUBLIC_BROWSER_TRACE_SUBSCRIBER_H_
#include <set>
#include "base/memory/ref_counted_memory.h"
namespace content {
// Objects interested in receiving trace data derive from TraceSubscriber. All
// callbacks occur on the UI thread.
// See also: trace_message_filter.h
// See also: child_trace_message_filter.h
class TraceSubscriber {
public:
// Called once after TraceController::EndTracingAsync.
virtual void OnEndTracingComplete() {}
// Called 0 or more times between TraceController::BeginTracing and
// OnEndTracingComplete. Use base::debug::TraceResultBuffer to convert one or
// more trace fragments to JSON.
virtual void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& trace_fragment) = 0;
// Called once after TraceController::GetKnownCategoryGroupsAsync.
virtual void OnKnownCategoriesCollected(
const std::set<std::string>& known_categories) {}
virtual void OnTraceBufferPercentFullReply(float percent_full) {}
virtual void OnEventWatchNotification() {}
protected:
virtual ~TraceSubscriber() {}
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_TRACE_SUBSCRIBER_H_
......@@ -6,9 +6,8 @@
#define CONTENT_PUBLIC_BROWSER_TRACING_CONTROLLER_H_
#include <set>
#include <string>
#include "base/callback.h"
#include "base/debug/trace_event.h"
#include "content/common/content_export.h"
namespace base {
......@@ -26,7 +25,6 @@ class TracingController;
class TracingController {
public:
enum Options {
DEFAULT_OPTIONS = 0,
ENABLE_SYSTRACE = 1 << 0,
ENABLE_SAMPLING = 1 << 1,
RECORD_CONTINUOUSLY = 1 << 2, // For EnableRecording() only.
......@@ -42,7 +40,7 @@ class TracingController {
// groups.
typedef base::Callback<void(const std::set<std::string>&)>
GetCategoriesDoneCallback;
virtual bool GetCategories(
virtual void GetCategories(
const GetCategoriesDoneCallback& callback) = 0;
// Start recording on all processes.
......@@ -53,8 +51,8 @@ class TracingController {
// Once all child processes have acked to the EnableRecording request,
// EnableRecordingDoneCallback will be called back.
//
// |category_filter| is a filter to control what category groups should be
// traced. A filter can have an optional '-' prefix to exclude category groups
// |filter| is a filter to control what category groups should be traced.
// A filter can have an optional '-' prefix to exclude category groups
// that contain a matching category. Having both included and excluded
// category patterns in the same list would not be supported.
//
......@@ -65,7 +63,7 @@ class TracingController {
// |options| controls what kind of tracing is enabled.
typedef base::Callback<void()> EnableRecordingDoneCallback;
virtual bool EnableRecording(
const std::string& category_filter,
const base::debug::CategoryFilter& filter,
TracingController::Options options,
const EnableRecordingDoneCallback& callback) = 0;
......@@ -99,13 +97,11 @@ class TracingController {
// Once all child processes have acked to the EnableMonitoring request,
// EnableMonitoringDoneCallback will be called back.
//
// |category_filter| is a filter to control what category groups should be
// traced.
// |filter| is a filter to control what category groups should be traced.
//
// |options| controls what kind of tracing is enabled.
typedef base::Callback<void()> EnableMonitoringDoneCallback;
virtual bool EnableMonitoring(
const std::string& category_filter,
virtual bool EnableMonitoring(const base::debug::CategoryFilter& filter,
TracingController::Options options,
const EnableMonitoringDoneCallback& callback) = 0;
......@@ -119,8 +115,8 @@ class TracingController {
// Get the current monitoring configuration.
virtual void GetMonitoringStatus(bool* out_enabled,
std::string* out_category_filter,
TracingController::Options* out_options) = 0;
base::debug::CategoryFilter* out_filter,
TracingController::Options* out_options) = 0;
// Get the current monitoring traced data.
//
......@@ -139,7 +135,7 @@ class TracingController {
//
// If |result_file_path| is empty and |callback| is null, trace data won't be
// written to any file.
virtual bool CaptureMonitoringSnapshot(
virtual void CaptureMonitoringSnapshot(
const base::FilePath& result_file_path,
const TracingFileResultCallback& callback) = 0;
......@@ -150,17 +146,6 @@ class TracingController {
virtual bool GetTraceBufferPercentFull(
const GetTraceBufferPercentFullCallback& callback) = 0;
// |callback| will will be called every time the given event occurs on any
// process.
typedef base::Callback<void()> WatchEventCallback;
virtual bool SetWatchEvent(const std::string& category_name,
const std::string& event_name,
const WatchEventCallback& callback) = 0;
// Cancel the watch event. If tracing is enabled, this may race with the
// watch event callback.
virtual bool CancelWatchEvent() = 0;
protected:
virtual ~TracingController() {}
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment