summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.cc3
-rw-r--r--chrome/browser/resources/gpu_internals.html11
-rw-r--r--chrome/browser/resources/gpu_internals/raw_events_view.css14
-rw-r--r--chrome/browser/resources/gpu_internals/raw_events_view.html9
-rw-r--r--chrome/browser/resources/gpu_internals/raw_events_view.js76
-rw-r--r--chrome/browser/resources/gpu_internals/tracing_controller.css7
-rw-r--r--chrome/browser/resources/gpu_internals/tracing_controller.html14
-rw-r--r--chrome/browser/resources/gpu_internals/tracing_controller.js36
-rw-r--r--chrome/browser/ui/webui/gpu_internals_ui.cc55
-rw-r--r--chrome/chrome_browser.gypi1
-rw-r--r--chrome/renderer/ggl/ggl.cc3
-rw-r--r--chrome/renderer/render_widget.cc3
-rw-r--r--content/gpu/gpu_command_buffer_stub.cc2
-rw-r--r--gpu/command_buffer/service/gpu_processor.cc2
-rw-r--r--gpu/common/gpu_trace_event.cc216
-rw-r--r--gpu/common/gpu_trace_event.h291
-rw-r--r--gpu/gpu.gyp16
17 files changed, 723 insertions, 36 deletions
diff --git a/chrome/browser/gpu_process_host_ui_shim.cc b/chrome/browser/gpu_process_host_ui_shim.cc
index 380a37c..bc5b9da 100644
--- a/chrome/browser/gpu_process_host_ui_shim.cc
+++ b/chrome/browser/gpu_process_host_ui_shim.cc
@@ -15,6 +15,7 @@
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/renderer_host/render_widget_host_view.h"
#include "content/common/gpu_messages.h"
+#include "gpu/common/gpu_trace_event.h"
#if defined(OS_LINUX)
// These two #includes need to come after gpu_messages.h.
@@ -269,6 +270,7 @@ void GpuProcessHostUIShim::EstablishGpuChannel(
int renderer_id,
EstablishChannelCallback *callback) {
DCHECK(CalledOnValidThread());
+ GPU_TRACE_EVENT0("gpu", "GpuProcessHostUIShim::EstablishGpuChannel");
linked_ptr<EstablishChannelCallback> wrapped_callback(callback);
// If GPU features are already blacklisted, no need to establish the channel.
@@ -539,4 +541,3 @@ void GpuProcessHostUIShim::OnScheduleComposite(int renderer_id,
}
#endif
-
diff --git a/chrome/browser/resources/gpu_internals.html b/chrome/browser/resources/gpu_internals.html
index 8763249..5c17de7 100644
--- a/chrome/browser/resources/gpu_internals.html
+++ b/chrome/browser/resources/gpu_internals.html
@@ -29,6 +29,7 @@ body {
<link rel="stylesheet" href="gpu_internals/timeline_view.css">
<link rel="stylesheet" href="gpu_internals/timeline.css">
<link rel="stylesheet" href="gpu_internals/tracing_controller.css">
+<link rel="stylesheet" href="gpu_internals/raw_events_view.css">
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/cr/event_target.js"></script>
<script src="chrome://resources/js/cr/ui.js"></script>
@@ -44,6 +45,7 @@ body {
<script src="gpu_internals/timeline_track.js"></script>
<script src="gpu_internals/fast_rect_renderer.js"></script>
<script src="gpu_internals/timeline_view.js"></script>
+<script src="gpu_internals/raw_events_view.js"></script>
<script src="gpu_internals/simulated_trace_data.js"></script>
<script>
@@ -62,6 +64,12 @@ function onLoad() {
// Create the views.
cr.ui.decorate('#info-view', gpu.InfoView);
+ var rawEventsView = $('raw-events-view');
+ if (browserBridge.debugMode)
+ cr.ui.decorate('#raw-events-view', gpu.RawEventsView);
+ else
+ rawEventsView.parentNode.removeChild(rawEventsView);
+
timelineView = $('timeline-view');
if (browserBridge.debugMode)
cr.ui.decorate(timelineView, gpu.TimelineView);
@@ -100,9 +108,8 @@ document.addEventListener('DOMContentLoaded', onLoad);
<!-- Tabs -->
<div id="main-tabs">
<include src="gpu_internals/info_view.html">
+ <include src="gpu_internals/raw_events_view.html">
<include src="gpu_internals/timeline_view.html">
</div>
-
- <include src="gpu_internals/tracing_controller.html">
</body>
</html>
diff --git a/chrome/browser/resources/gpu_internals/raw_events_view.css b/chrome/browser/resources/gpu_internals/raw_events_view.css
new file mode 100644
index 0000000..c282960
--- /dev/null
+++ b/chrome/browser/resources/gpu_internals/raw_events_view.css
@@ -0,0 +1,14 @@
+/*
+Copyright (c) 2011 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.
+*/
+#raw-events-view {
+ padding: 4px;
+}
+
+#raw-events-view-data {
+ cursor: text;
+ font-family: monospace;
+ -webkit-user-select: text;
+} \ No newline at end of file
diff --git a/chrome/browser/resources/gpu_internals/raw_events_view.html b/chrome/browser/resources/gpu_internals/raw_events_view.html
new file mode 100644
index 0000000..464bba8
--- /dev/null
+++ b/chrome/browser/resources/gpu_internals/raw_events_view.html
@@ -0,0 +1,9 @@
+<!--
+Copyright (c) 2011 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.
+-->
+<div id=raw-events-view label="Raw Events">
+ <div class="raw-events-view-data">
+ </div>
+</div>
diff --git a/chrome/browser/resources/gpu_internals/raw_events_view.js b/chrome/browser/resources/gpu_internals/raw_events_view.js
new file mode 100644
index 0000000..5ff981a
--- /dev/null
+++ b/chrome/browser/resources/gpu_internals/raw_events_view.js
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 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.
+
+/**
+ *
+ * @fileoverview Displays the traced data in raw format. Its primarily
+ * usefulness is to allow users to copy-paste their data in an easy to
+ * read format for bug reports.
+ *
+ */
+cr.define('gpu', function() {
+ /**
+ * Provides information on the GPU process and underlying graphics hardware.
+ * @constructor
+ * @extends {gpu.Tab}
+ */
+ var RawEventsView = cr.ui.define(gpu.Tab);
+
+ RawEventsView.prototype = {
+ __proto__: gpu.Tab.prototype,
+
+ decorate: function() {
+ tracingController.addEventListener('traceBegun', this.refresh.bind(this));
+ tracingController.addEventListener('traceEnded', this.refresh.bind(this));
+ this.addEventListener('selectedChange', this.onSelectedChange_);
+ this.refresh();
+ },
+
+ onSelectedChange_: function() {
+ if (this.selected) {
+ if (!tracingController.traceEvents.length) {
+ tracingController.beginTracing();
+ }
+ if (this.needsRefreshOnShow_) {
+ this.needsRefreshOnShow_ = false;
+ this.refresh();
+ }
+ }
+ },
+
+ /**
+ * Updates the view based on its currently known data
+ */
+ refresh: function() {
+ if (this.parentNode.selectedTab != this) {
+ this.needsRefreshOnShow_ = true;
+ }
+
+ var dataElement = this.querySelector('.raw-events-view-data');
+ if (tracingController.isTracingEnabled) {
+ var tmp = 'Still tracing. ' +
+ 'Uncheck the enable tracing button to see traced data.';
+ dataElement.textContent = tmp;
+ } else if (!tracingController.traceEvents.length) {
+ dataElement.textContent =
+ 'No trace data collected. Collect data first.';
+ } else {
+ var events = tracingController.traceEvents;
+ var text = JSON.stringify(events);
+ dataElement.textContent = text;
+
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ var range = document.createRange();
+ range.selectNodeContents(dataElement);
+ selection.addRange(range);
+ }
+ }
+
+ };
+
+ return {
+ RawEventsView: RawEventsView
+ };
+});
diff --git a/chrome/browser/resources/gpu_internals/tracing_controller.css b/chrome/browser/resources/gpu_internals/tracing_controller.css
index 331fe85..895d695 100644
--- a/chrome/browser/resources/gpu_internals/tracing_controller.css
+++ b/chrome/browser/resources/gpu_internals/tracing_controller.css
@@ -26,8 +26,7 @@ found in the LICENSE file.
border-top-right-radius: 8px;
border-top-left-radius: 8px;
background-clip: border-box;
- background: rgb(255,0,0);
- border-left: 1px solid black;
- border-top: 1px solid black;
- border-right: 1px solid black;
+ background: rgb(255, 0, 0);
+ border: 1px solid black;
+ border-bottom: 0;
}
diff --git a/chrome/browser/resources/gpu_internals/tracing_controller.html b/chrome/browser/resources/gpu_internals/tracing_controller.html
deleted file mode 100644
index 7db2635..0000000
--- a/chrome/browser/resources/gpu_internals/tracing_controller.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!--
-Copyright (c) 2011 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.
--->
-<div hidden>
- <div id="gpu-tracing-start-button-template" class="gpu-tracing-start-button">
- Record new data
- </div>
- <div id="gpu-tracing-overlay-template" class="gpu-tracing-overlay">
- <div class="gpu-tracing-status">Tracing active.</div>
- <button class="gpu-tracing-stop-button">Stop tracing</button>
- </div>
-</div>
diff --git a/chrome/browser/resources/gpu_internals/tracing_controller.js b/chrome/browser/resources/gpu_internals/tracing_controller.js
index f46e417..8d7471b 100644
--- a/chrome/browser/resources/gpu_internals/tracing_controller.js
+++ b/chrome/browser/resources/gpu_internals/tracing_controller.js
@@ -7,20 +7,29 @@
* @fileoverview State and UI for trace data collection.
*/
cr.define('gpu', function() {
+
function TracingController() {
- this.overlay_ = $('gpu-tracing-overlay-template').cloneNode(true);
- this.overlay_.removeAttribute('id');
- cr.ui.decorate(this.overlay_, gpu.Overlay);
+ this.startButton_ = document.createElement('div');
+ this.startButton_.className = 'gpu-tracing-start-button';
+ this.startButton_.textContent = 'Start tracing';
+ this.startButton_.onclick = this.beginTracing.bind(this);
+ document.body.appendChild(this.startButton_);
- this.traceEvents_ = [];
+ this.overlay_ = document.createElement('div');
+ this.overlay_.className = 'gpu-tracing-overlay';
+
+ cr.ui.decorate(this.overlay_, gpu.Overlay);
- var startButton = $('gpu-tracing-start-button-template').cloneNode(true);
- startButton.removeAttribute('id');
- document.body.appendChild(startButton);
- startButton.onclick = this.beginTracing.bind(this);
+ var statusDiv = document.createElement('div');
+ statusDiv.textContent = 'Tracing active.';
+ this.overlay_.appendChild(statusDiv);
- var stopButton = this.overlay_.querySelector('.gpu-tracing-stop-button');
+ var stopButton = document.createElement('button');
stopButton.onclick = this.endTracing.bind(this);
+ stopButton.innerText = 'Stop tracing';
+ this.overlay_.appendChild(stopButton);
+
+ this.traceEvents_ = [];
}
TracingController.prototype = {
@@ -93,17 +102,18 @@ cr.define('gpu', function() {
console.log('Finishing trace');
if (!browserBridge.debugMode) {
- chrome.send('beginToEndTracing');
+ chrome.send('endTracingAsync');
} else {
- var events = getTimelineTestData1();
+ var events = window.getTimelineTestData1 ?
+ getTimelineTestData1() : [];
this.onTraceDataCollected(events);
window.setTimeout(this.onEndTracingComplete.bind(this), 250);
}
},
+
/**
- * Called by the browser when all processes ack tracing
- * having completed.
+ * Called by the browser when all processes complete tracing.
*/
onEndTracingComplete: function() {
this.overlay_.visible = false;
diff --git a/chrome/browser/ui/webui/gpu_internals_ui.cc b/chrome/browser/ui/webui/gpu_internals_ui.cc
index 8e8bf2c..0729ef1 100644
--- a/chrome/browser/ui/webui/gpu_internals_ui.cc
+++ b/chrome/browser/ui/webui/gpu_internals_ui.cc
@@ -35,6 +35,7 @@
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/browser/gpu_process_host.h"
+#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
@@ -75,6 +76,8 @@ class GpuMessageHandler
virtual void RegisterMessages();
// Mesages
+ void OnBeginTracing(const ListValue* list);
+ void OnEndTracingAsync(const ListValue* list);
void OnBrowserBridgeInitialized(const ListValue* list);
void OnCallAsync(const ListValue* list);
@@ -82,6 +85,8 @@ class GpuMessageHandler
Value* OnRequestClientInfo(const ListValue* list);
Value* OnRequestLogMessages(const ListValue* list);
+ // Callbacks.
+ void OnTraceDataCollected(const std::string& json_events);
void OnGpuInfoUpdate();
// Executes the javascript function |function_name| in the renderer, passing
@@ -95,7 +100,11 @@ class GpuMessageHandler
// Cache the Singleton for efficiency.
GpuDataManager* gpu_data_manager_;
+ void OnEndTracingComplete();
+
Callback0::Type* gpu_info_update_callback_;
+
+ bool trace_enabled_;
};
////////////////////////////////////////////////////////////////////////////////
@@ -141,7 +150,9 @@ std::string GpuHTMLSource::GetMimeType(const std::string&) const {
//
////////////////////////////////////////////////////////////////////////////////
-GpuMessageHandler::GpuMessageHandler() : gpu_info_update_callback_(NULL) {
+GpuMessageHandler::GpuMessageHandler()
+ : gpu_info_update_callback_(NULL)
+ , trace_enabled_(false) {
gpu_data_manager_ = GpuDataManager::GetInstance();
DCHECK(gpu_data_manager_);
}
@@ -151,6 +162,9 @@ GpuMessageHandler::~GpuMessageHandler() {
gpu_data_manager_->RemoveGpuInfoUpdateCallback(gpu_info_update_callback_);
delete gpu_info_update_callback_;
}
+
+ if (trace_enabled_)
+ OnEndTracingAsync(NULL);
}
WebUIMessageHandler* GpuMessageHandler::Attach(WebUI* web_ui) {
@@ -164,6 +178,12 @@ void GpuMessageHandler::RegisterMessages() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
web_ui_->RegisterMessageCallback(
+ "beginTracing",
+ NewCallback(this, &GpuMessageHandler::OnBeginTracing));
+ web_ui_->RegisterMessageCallback(
+ "endTracingAsync",
+ NewCallback(this, &GpuMessageHandler::OnEndTracingAsync));
+ web_ui_->RegisterMessageCallback(
"browserBridgeInitialized",
NewCallback(this, &GpuMessageHandler::OnBrowserBridgeInitialized));
web_ui_->RegisterMessageCallback(
@@ -368,6 +388,38 @@ void GpuMessageHandler::OnGpuInfoUpdate() {
delete gpu_info_val;
}
+void GpuMessageHandler::OnBeginTracing(const ListValue* args) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ trace_enabled_ = true;
+ // TODO(jbates): TracingController::BeginTracing()
+}
+
+void GpuMessageHandler::OnEndTracingAsync(const ListValue* list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(trace_enabled_);
+
+ // TODO(jbates): TracingController::OnEndTracingAsync(new
+ // Callback(this, GpuMessageHandler::OnEndTracingComplete))
+}
+
+void GpuMessageHandler::OnEndTracingComplete() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ trace_enabled_ = false;
+ web_ui_->CallJavascriptFunction("tracingController.onEndTracingComplete");
+}
+
+void GpuMessageHandler::OnTraceDataCollected(const std::string& json_events) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::wstring javascript;
+ javascript += L"tracingController.onTraceDataCollected(";
+ javascript += UTF8ToWide(json_events);
+ javascript += L");";
+
+ web_ui_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(string16(),
+ WideToUTF16Hack(javascript));
+}
+
} // namespace
@@ -385,4 +437,3 @@ GpuInternalsUI::GpuInternalsUI(TabContents* contents) : WebUI(contents) {
// Set up the chrome://gpu/ source.
contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
}
-
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index c235e4e..16898a7 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -28,6 +28,7 @@
'userfeedback_proto',
'../app/app.gyp:app_resources',
'../content/content.gyp:content_browser',
+ '../gpu/gpu.gyp:gpu_common',
'../media/media.gyp:media',
'../ppapi/ppapi.gyp:ppapi_proxy', # For PpapiMsg_LoadPlugin
'../printing/printing.gyp:printing',
diff --git a/chrome/renderer/ggl/ggl.cc b/chrome/renderer/ggl/ggl.cc
index 9fb4bb0..c13b02c 100644
--- a/chrome/renderer/ggl/ggl.cc
+++ b/chrome/renderer/ggl/ggl.cc
@@ -15,11 +15,13 @@
#include "chrome/renderer/render_widget.h"
#include "ipc/ipc_channel_handle.h"
+
#if defined(ENABLE_GPU)
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "gpu/command_buffer/client/gles2_lib.h"
#include "gpu/command_buffer/common/constants.h"
+#include "gpu/common/gpu_trace_event.h"
#include "gpu/GLES2/gles2_command_buffer.h"
#endif // ENABLE_GPU
@@ -387,6 +389,7 @@ bool Context::MakeCurrent(Context* context) {
}
bool Context::SwapBuffers() {
+ GPU_TRACE_EVENT0("gpu", "Context::SwapBuffers");
// Don't request latest error status from service. Just use the locally cached
// information from the last flush.
if (command_buffer_->GetLastState().error != gpu::error::kNoError)
diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc
index b19a87c..8081288 100644
--- a/chrome/renderer/render_widget.cc
+++ b/chrome/renderer/render_widget.cc
@@ -17,6 +17,7 @@
#include "chrome/renderer/render_process.h"
#include "chrome/renderer/render_thread.h"
#include "chrome/renderer/renderer_webkitclient_impl.h"
+#include "gpu/common/gpu_trace_event.h"
#include "ipc/ipc_sync_message.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkShader.h"
@@ -546,6 +547,8 @@ void RenderWidget::CallDoDeferredUpdate() {
}
void RenderWidget::DoDeferredUpdate() {
+ GPU_TRACE_EVENT0("render_widget", "DoDeferredUpdate");
+
if (!webwidget_ || update_reply_pending())
return;
diff --git a/content/gpu/gpu_command_buffer_stub.cc b/content/gpu/gpu_command_buffer_stub.cc
index c1e9b1e9..d838c9f 100644
--- a/content/gpu/gpu_command_buffer_stub.cc
+++ b/content/gpu/gpu_command_buffer_stub.cc
@@ -12,6 +12,7 @@
#include "content/gpu/gpu_channel.h"
#include "content/gpu/gpu_command_buffer_stub.h"
#include "content/gpu/gpu_thread.h"
+#include "gpu/common/gpu_trace_event.h"
using gpu::Buffer;
@@ -351,6 +352,7 @@ void GpuCommandBufferStub::OnResizeOffscreenFrameBuffer(const gfx::Size& size) {
}
void GpuCommandBufferStub::OnSwapBuffers() {
+ GPU_TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnSwapBuffers");
Send(new GpuCommandBufferMsg_SwapBuffers(route_id_));
}
diff --git a/gpu/command_buffer/service/gpu_processor.cc b/gpu/command_buffer/service/gpu_processor.cc
index 45d21d7..c7d19d3 100644
--- a/gpu/command_buffer/service/gpu_processor.cc
+++ b/gpu/command_buffer/service/gpu_processor.cc
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "app/gfx/gl/gl_context.h"
+#include "gpu/common/gpu_trace_event.h"
using ::base::SharedMemory;
@@ -124,6 +125,7 @@ const unsigned int kMaxOutstandingSwapBuffersCallsPerOnscreenContext = 1;
#endif
void GPUProcessor::ProcessCommands() {
+ GPU_TRACE_EVENT0("gpu", "GPUProcessor:ProcessCommands");
CommandBuffer::State state = command_buffer_->GetState();
if (state.error != error::kNoError)
return;
diff --git a/gpu/common/gpu_trace_event.cc b/gpu/common/gpu_trace_event.cc
new file mode 100644
index 0000000..d9caec3
--- /dev/null
+++ b/gpu/common/gpu_trace_event.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2010 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 "gpu/common/gpu_trace_event.h"
+
+#include "base/format_macros.h"
+#include "base/process_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "base/time.h"
+
+#define USE_UNRELIABLE_NOW
+
+using namespace base;
+
+namespace gpu {
+
+// Controls the number of trace events we will buffer in-memory
+// before flushing them.
+#define TRACE_EVENT_BUFFER_SIZE 16384
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceLog::Category
+//
+////////////////////////////////////////////////////////////////////////////////
+TraceCategory::TraceCategory(const char* name, bool enabled)
+ : name_(name) {
+ base::subtle::NoBarrier_Store(&enabled_,
+ static_cast<base::subtle::Atomic32>(enabled));
+}
+
+TraceCategory::~TraceCategory() {
+ base::subtle::NoBarrier_Store(&enabled_,
+ static_cast<base::subtle::Atomic32>(0));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceEvent
+//
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+const char* GetPhaseStr(TraceEventPhase phase) {
+ if (phase == GPU_TRACE_EVENT_PHASE_BEGIN) {
+ return "B";
+ } else if (phase == GPU_TRACE_EVENT_PHASE_INSTANT) {
+ return "I";
+ } else if (phase == GPU_TRACE_EVENT_PHASE_END) {
+ return "E";
+ } else {
+ DCHECK(false);
+ return "?";
+ }
+}
+}
+
+void TraceEvent::AppendAsJSON(std::string* out,
+ const std::vector<TraceEvent>& events) {
+ *out += "[";
+ for (size_t i = 0; i < events.size(); ++i) {
+ if (i > 0)
+ *out += ",";
+ events[i].AppendAsJSON(out);
+ }
+ *out += "]";
+}
+
+void TraceEvent::AppendAsJSON(std::string* out) const {
+ int nargs = 0;
+ for (int i = 0; i < TRACE_MAX_NUM_ARGS; ++i) {
+ if (argNames[i] == NULL)
+ break;
+ nargs += 1;
+ }
+
+ const char* phaseStr = GetPhaseStr(phase);
+ int64 time_int64 = timestamp.ToInternalValue();
+ long long unsigned int time_llui =
+ static_cast<long long unsigned int>(time_int64);
+ StringAppendF(out,
+ "{cat:'%s',pid:%i,tid:%i,ts:0x%llx,ph:'%s',name:'%s',args:{",
+ category->name(),
+ static_cast<int>(processId),
+ static_cast<int>(threadId),
+ time_llui,
+ phaseStr,
+ name);
+ for (int i = 0; i < nargs; ++i) {
+ if (i > 0)
+ *out += ",";
+ *out += argNames[i];
+ *out += ":'";
+ *out += argValues[i];
+ *out += "'";
+ }
+ *out += "}}";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceLog
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// static
+TraceLog* TraceLog::GetInstance() {
+ return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get();
+}
+
+TraceLog::TraceLog()
+ : enabled_(false)
+{
+ logged_events_.reserve(1024);
+}
+
+TraceLog::~TraceLog() {
+}
+
+TraceCategory* TraceLog::GetCategory(const char* name) {
+ AutoLock lock(lock_);
+ // TODO(nduca): replace with a hash_map.
+ for (int i = categories_.size() - 1; i >= 0; i-- ) {
+ if (strcmp(categories_[i]->name(), name) == 0)
+ return categories_[i];
+ }
+ TraceCategory* category = new TraceCategory(name, enabled_);
+ categories_.push_back(category);
+ return category;
+}
+
+void TraceLog::SetEnabled(bool enabled) {
+ AutoLock lock(lock_);
+ if (enabled == enabled_)
+ return;
+ if (enabled) {
+ // Enable all categories.
+ enabled_ = true;
+ for (size_t i = 0; i < categories_.size(); i++) {
+ base::subtle::NoBarrier_Store(&categories_[i]->enabled_,
+ static_cast<base::subtle::Atomic32>(1));
+ }
+ } else {
+ // Disable all categories.
+ for (size_t i = 0; i < categories_.size(); i++) {
+ base::subtle::NoBarrier_Store(&categories_[i]->enabled_,
+ static_cast<base::subtle::Atomic32>(0));
+ }
+ enabled_ = false;
+ FlushWithLockAlreadyHeld();
+ }
+}
+
+void TraceLog::SetOutputCallback(TraceLog::OutputCallback* cb) {
+ AutoLock lock(lock_);
+ if (enabled_) {
+ FlushWithLockAlreadyHeld();
+ }
+ output_callback_.reset(cb);
+}
+
+void TraceLog::AddRemotelyCollectedData(const std::string& json_events) {
+ AutoLock lock(lock_);
+ if (output_callback_.get())
+ output_callback_->Run(json_events);
+}
+
+void TraceLog::Flush() {
+ AutoLock lock(lock_);
+ FlushWithLockAlreadyHeld();
+}
+
+void TraceLog::FlushWithLockAlreadyHeld() {
+ if (output_callback_.get() && logged_events_.size()) {
+ std::string json_events;
+ TraceEvent::AppendAsJSON(&json_events, logged_events_);
+ output_callback_->Run(json_events);
+ }
+ logged_events_.erase(logged_events_.begin(), logged_events_.end());
+}
+
+void TraceLog::AddTraceEvent(TraceEventPhase phase,
+ const char* file, int line,
+ TraceCategory* category,
+ const char* name,
+ const char* arg1name, const char* arg1val,
+ const char* arg2name, const char* arg2val) {
+ DCHECK(file && name);
+#ifdef USE_UNRELIABLE_NOW
+ TimeTicks now = TimeTicks::HighResNow();
+#else
+ TimeTicks now = TimeTicks::Now();
+#endif
+ //static_cast<unsigned long>(base::GetCurrentProcId()),
+ AutoLock lock(lock_);
+ logged_events_.push_back(TraceEvent());
+ TraceEvent& event = logged_events_.back();
+ event.processId = static_cast<unsigned long>(base::GetCurrentProcId());
+ event.threadId = PlatformThread::CurrentId();
+ event.timestamp = now;
+ event.phase = phase;
+ event.category = category;
+ event.name = name;
+ event.argNames[0] = arg1name;
+ event.argValues[0] = arg1name ? arg1val : "";
+ event.argNames[1] = arg2name;
+ event.argValues[1] = arg2name ? arg2val : "";
+ COMPILE_ASSERT(TRACE_MAX_NUM_ARGS == 2, TraceEvent_arc_count_out_of_sync);
+
+ if (logged_events_.size() > TRACE_EVENT_BUFFER_SIZE)
+ FlushWithLockAlreadyHeld();
+}
+
+} // namespace gpu
diff --git a/gpu/common/gpu_trace_event.h b/gpu/common/gpu_trace_event.h
new file mode 100644
index 0000000..1c8e46a
--- /dev/null
+++ b/gpu/common/gpu_trace_event.h
@@ -0,0 +1,291 @@
+// Copyright (c) 2010 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.
+
+// Trace events are for tracking application performance.
+//
+// Events are issued against categories. Whereas LOG's
+// categories are statically defined, TRACE categories are created
+// implicitly with a string. For example:
+// GPU_TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent")
+//
+// Events can be INSTANT, or can be pairs of BEGIN and END:
+// GPU_TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")
+// doSomethingCostly()
+// GPU_TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")
+//
+// A common use case is to trace entire function scopes. This
+// issues a trace BEGIN and END automatically:
+// void doSomethingCostly() {
+// GPU_TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly");
+// ...
+// }
+//
+// Additional parameters can be associated with an event:
+// void doSomethingCostly2(int howMuch) {
+// GPU_TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly",
+// "howMuch", StringPrintf("%i", howMuch).c_str());
+// ...
+// }
+//
+// The trace system will automatically add to this information the
+// current process id, thread id, a timestamp down to the
+// microsecond, as well as the file and line number of the calling location.
+//
+// By default, trace collection is compiled in, but turned off at runtime.
+// Collecting trace data is the responsibility of the embedding
+// application. In Chrome's case, navigating to about:gpu will turn on
+// tracing and display data collected across all active processes.
+//
+
+#ifndef GPU_TRACE_EVENT_H_
+#define GPU_TRACE_EVENT_H_
+#pragma once
+
+#include "build/build_config.h"
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "base/scoped_vector.h"
+#include "base/atomicops.h"
+#include "base/singleton.h"
+#include "base/time.h"
+#include "base/timer.h"
+#include "base/callback.h"
+#include <vector>
+
+
+// Implementation detail: trace event macros create temporary variables
+// to keep instrumentation overhead low. These macros give each temporary
+// variable a unique name based on the line number to prevent name collissions.
+#define GPU_TRACE_EVENT_UNIQUE_IDENTIFIER3(a,b) a##b
+#define GPU_TRACE_EVENT_UNIQUE_IDENTIFIER2(a,b) \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER3(a,b)
+#define GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(name_prefix) \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER2(name_prefix, __LINE__)
+
+// Records a pair of begin and end events called "name" for the current
+// scope, with 0, 1 or 2 associated arguments. If the category is not
+// enabled, then this does nothing.
+#define GPU_TRACE_EVENT0(category, name) \
+ GPU_TRACE_EVENT1(category, name, NULL, NULL)
+#define GPU_TRACE_EVENT1(category, name, arg1name, arg1val) \
+ GPU_TRACE_EVENT2(category, name, arg1name, arg1val, NULL, NULL)
+#define GPU_TRACE_EVENT2(category, name, arg1name, arg1val, arg2name, arg2val) \
+ static gpu::TraceCategory* \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \
+ gpu::TraceLog::GetInstance()->GetCategory(category); \
+ if (base::subtle::Acquire_Load(\
+ &(GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \
+ gpu::TraceLog::GetInstance()->AddTraceEvent( \
+ gpu::GPU_TRACE_EVENT_PHASE_BEGIN, \
+ __FILE__, __LINE__, \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \
+ name, \
+ arg1name, arg1val, \
+ arg2name, arg2val); \
+ } \
+ gpu::internal::TraceEndOnScopeClose __profileScope ## __LINE ( \
+ __FILE__, __LINE__, \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), name);
+
+// Records a single event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+#define GPU_TRACE_EVENT_INSTANT0(category, name) \
+ GPU_TRACE_EVENT_INSTANT1(category, name, NULL, NULL)
+#define GPU_TRACE_EVENT_INSTANT1(category, name, arg1name, arg1val) \
+ GPU_TRACE_EVENT_INSTANT2(category, name, arg1name, arg1val, NULL, NULL)
+#define GPU_TRACE_EVENT_INSTANT2(category, name, arg1name, arg1val, \
+ arg2name, arg2val) \
+ static gpu::TraceCategory* \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \
+ gpu::TraceLog::GetInstance()->GetCategory(category); \
+ if (base::subtle::Acquire_Load( \
+ &(GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \
+ gpu::TraceLog::GetInstance()->AddTraceEvent( \
+ gpu::GPU_TRACE_EVENT_PHASE_INSTANT, \
+ __FILE__, __LINE__, \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \
+ name, \
+ arg1name, arg1val, \
+ arg2name, arg2val); \
+ }
+
+// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+#define GPU_TRACE_EVENT_BEGIN0(category, name) \
+ GPU_TRACE_EVENT_BEGIN1(category, name, NULL, NULL)
+#define GPU_TRACE_EVENT_BEGIN1(category, name, arg1name, arg1val) \
+ GPU_TRACE_EVENT_BEGIN2(category, name, arg1name, arg1val, NULL, NULL)
+#define GPU_TRACE_EVENT_BEGIN2(category, name, arg1name, arg1val, \
+ arg2name, arg2val) \
+ static gpu::TraceCategory* \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \
+ gpu::TraceLog::GetInstance()->GetCategory(category); \
+ if (base::subtle::Acquire_Load( \
+ &(GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \
+ gpu::TraceLog::GetInstance()->AddTraceEvent( \
+ gpu::GPU_TRACE_EVENT_PHASE_BEGIN, \
+ __FILE__, __LINE__, \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \
+ name, \
+ arg1name, arg1val, \
+ arg2name, arg2val); \
+ }
+
+// Records a single END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define GPU_TRACE_EVENT_END0(category, name) \
+ static gpu::TraceCategory* \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic) = \
+ gpu::TraceLog::GetInstance()->GetCategory(category); \
+ if (base::subtle::Acquire_Load( \
+ &(GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic))->enabled_)) { \
+ gpu::TraceLog::GetInstance()->AddTraceEvent( \
+ gpu::GPU_TRACE_EVENT_PHASE_END, \
+ __FILE__, __LINE__, \
+ GPU_TRACE_EVENT_UNIQUE_IDENTIFIER(catstatic), \
+ name, \
+ arg1name, arg1val, \
+ arg2name, arg2val); \
+ }
+
+
+namespace gpu {
+
+// Categories allow enabling/disabling of streams of trace events
+// Don't manipulate the category object directly, as this may lead
+// to threading issues. Use the TraceLog methods instead.
+class TraceCategory {
+ public:
+ TraceCategory(const char* name, bool enabled);
+ ~TraceCategory();
+
+ const char* name() const { return name_; }
+
+ // NEVER read these directly, let the macros do it for you
+ volatile base::subtle::Atomic32 enabled_;
+ protected:
+ const char* name_;
+};
+
+#define TRACE_MAX_NUM_ARGS 2
+
+enum TraceEventPhase {
+ GPU_TRACE_EVENT_PHASE_BEGIN,
+ GPU_TRACE_EVENT_PHASE_END,
+ GPU_TRACE_EVENT_PHASE_INSTANT
+};
+
+// Output records are "Events" and can be obtained via the
+// OutputCallback whenever the logging system decides to flush. This
+// can happen at any time, on any thread, or you can programatically
+// force it to happen.
+struct TraceEvent {
+ static void AppendAsJSON(std::string* out,
+ const std::vector<TraceEvent>& events);
+ void AppendAsJSON(std::string* out) const;
+
+
+ unsigned long processId;
+ unsigned long threadId;
+ base::TimeTicks timestamp;
+ TraceEventPhase phase;
+ TraceCategory* category;
+ const char* name;
+ const char* argNames[TRACE_MAX_NUM_ARGS];
+ std::string argValues[TRACE_MAX_NUM_ARGS];
+};
+
+
+class TraceLog {
+ public:
+ static TraceLog* GetInstance();
+
+ // Global enable of tracing. Currently enables all categories or not.
+ // TODO(nduca) Replaced with an Enable/DisableCategory() that
+ // implicitly controls the global logging state.
+ void SetEnabled(bool enabled);
+
+ // When enough events are collected, they are handed (in bulk) to
+ // the output callback. If no callback is set, the output will be
+ // silently dropped.
+ typedef Callback1<const std::string& /* json_events */>::Type OutputCallback;
+ void SetOutputCallback(OutputCallback* cb);
+
+ // Forwards data collected by a child process to the registered
+ // output callback.
+ void AddRemotelyCollectedData(const std::string& json_events);
+
+ // Flushes all logged data to the callback.
+ void Flush();
+
+ // Called by GPU_TRACE_EVENT* macros, don't call this directly.
+ TraceCategory* GetCategory(const char* name);
+
+ // Called by GPU_TRACE_EVENT* macros, don't call this directly.
+ void AddTraceEvent(TraceEventPhase phase,
+ const char* file, int line,
+ TraceCategory* category,
+ const char* name,
+ const char* arg1name, const char* arg1val,
+ const char* arg2name, const char* arg2val);
+
+ private:
+ // This allows constructor and destructor to be private and usable only
+ // by the Singleton class.
+ friend struct StaticMemorySingletonTraits<TraceLog>;
+
+ TraceLog();
+ ~TraceLog();
+ void FlushWithLockAlreadyHeld();
+
+ // TODO(nduca): switch to per-thread trace buffers to reduce thread
+ // synchronization.
+ base::Lock lock_;
+ bool enabled_;
+ ScopedVector<TraceCategory> categories_;
+ scoped_ptr<OutputCallback> output_callback_;
+ std::vector<TraceEvent> logged_events_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceLog);
+};
+
+namespace internal {
+
+// Used by GPU_TRACE_EVENTx macro. Do not use directly.
+class TraceEndOnScopeClose {
+ public:
+ TraceEndOnScopeClose(const char* file, int line,
+ TraceCategory* category,
+ const char* name)
+ : file_(file)
+ , line_(line)
+ , category_(category)
+ , name_(name) { }
+
+ ~TraceEndOnScopeClose() {
+ if (base::subtle::Acquire_Load(&category_->enabled_))
+ gpu::TraceLog::GetInstance()->AddTraceEvent(
+ gpu::GPU_TRACE_EVENT_PHASE_END,
+ file_, line_,
+ category_,
+ name_,
+ NULL, NULL, NULL, NULL);
+ }
+
+ private:
+ const char* file_;
+ int line_;
+ TraceCategory* category_;
+ const char* name_;
+};
+
+} // namespace internal
+
+} // namespace gpu
+
+#endif // GPU_TRACE_EVENT_H_
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 0fb7581..d53badd 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -25,6 +25,20 @@
},
'targets': [
{
+ 'target_name': 'gpu_common',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'common/gpu_trace_event.cc',
+ 'common/gpu_trace_event.h',
+ ],
+ },
+ {
'target_name': 'command_buffer_common',
'type': 'static_library',
'include_dirs': [
@@ -163,6 +177,7 @@
},
'dependencies': [
'command_buffer_common',
+ 'gpu_common',
'../app/app.gyp:app_base',
'../base/base.gyp:base',
'../ui/gfx/gfx.gyp:gfx',
@@ -231,6 +246,7 @@
'command_buffer_client',
'command_buffer_common',
'command_buffer_service',
+ 'gpu_common',
'gpu_unittest_utils',
'gles2_implementation_client_side_arrays',
'gles2_cmd_helper',