[PATCH v3 16/18] mt retrace: add support for multi-threaded playback
Imre Deak
imre.deak at intel.com
Wed May 23 02:05:30 PDT 2012
Signed-off-by: Imre Deak <imre.deak at intel.com>
---
retrace/retrace_main.cpp | 149 ++++++++++++++++++++++++++++++++++-----------
1 files changed, 112 insertions(+), 37 deletions(-)
diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp
index f7fb711..8202ed6 100644
--- a/retrace/retrace_main.cpp
+++ b/retrace/retrace_main.cpp
@@ -27,8 +27,10 @@
#include <string.h>
#include <iostream>
+#include "glws.hpp"
#include "os_binary.hpp"
#include "os_time.hpp"
+#include "os_workqueue.hpp"
#include "image.hpp"
#include "trace_callset.hpp"
#include "trace_dump.hpp"
@@ -36,6 +38,7 @@
static bool waitOnFinish = false;
+static bool use_threads;
static const char *comparePrefix = NULL;
static const char *snapshotPrefix = NULL;
@@ -44,12 +47,15 @@ static trace::CallSet compareFrequency;
static unsigned dumpStateCallNo = ~0;
+retrace::Retracer retracer;
+
namespace retrace {
trace::Parser parser;
+static std::map<unsigned long, os::WorkQueue *> thread_wq_map;
int verbosity = 0;
bool debug = true;
@@ -62,7 +68,16 @@ bool coreProfile = false;
static unsigned frameNo = 0;
+static bool state_dumped;
+class RenderWork : public os::WorkQueueWork
+{
+ trace::Call *call;
+public:
+ void run(void);
+ RenderWork(trace::Call *_call) { call = _call; }
+ ~RenderWork(void) { delete call; }
+};
void
frameComplete(trace::Call &call) {
@@ -115,54 +130,111 @@ takeSnapshot(unsigned call_no) {
return;
}
+void RenderWork::run(void)
+{
+ bool swapRenderTarget = call->flags &
+ trace::CALL_FLAG_SWAP_RENDERTARGET;
+ bool doSnapshot = snapshotFrequency.contains(*call) ||
+ compareFrequency.contains(*call);
-static void
-mainLoop() {
- retrace::Retracer retracer;
+ if (state_dumped)
+ return;
- addCallbacks(retracer);
+ // For calls which cause rendertargets to be swaped, we take the
+ // snapshot _before_ swapping the rendertargets.
+ if (doSnapshot && swapRenderTarget) {
+ if (call->flags & trace::CALL_FLAG_END_FRAME) {
+ // For swapbuffers/presents we still use this
+ // call number, spite not have been executed yet.
+ takeSnapshot(call->no);
+ } else {
+ // Whereas for ordinate fbo/rendertarget changes we
+ // use the previous call's number.
+ takeSnapshot(call->no - 1);
+ }
+ }
- long long startTime = 0;
- frameNo = 0;
+ retracer.retrace(*call);
- startTime = os::getTime();
- trace::Call *call;
+ if (doSnapshot && !swapRenderTarget)
+ takeSnapshot(call->no);
- while ((call = retrace::parser.parse_call())) {
- bool swapRenderTarget = call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET;
- bool doSnapshot =
- snapshotFrequency.contains(*call) ||
- compareFrequency.contains(*call)
- ;
-
- // For calls which cause rendertargets to be swaped, we take the
- // snapshot _before_ swapping the rendertargets.
- if (doSnapshot && swapRenderTarget) {
- if (call->flags & trace::CALL_FLAG_END_FRAME) {
- // For swapbuffers/presents we still use this call number,
- // spite not have been executed yet.
- takeSnapshot(call->no);
- } else {
- // Whereas for ordinate fbo/rendertarget changes we use the
- // previous call's number.
- takeSnapshot(call->no - 1);
- }
- }
+ if (call->no >= dumpStateCallNo && dumpState(std::cout))
+ state_dumped = true;
+}
+
+static os::WorkQueue *get_work_queue(unsigned long thread_id)
+{
+ os::WorkQueue *thread;
+ std::map<unsigned long, os::WorkQueue *>::iterator it;
- retracer.retrace(*call);
+ it = thread_wq_map.find(thread_id);
+ if (it == thread_wq_map.end()) {
+ thread = new os::WorkQueue();
+ thread_wq_map[thread_id] = thread;
+ } else {
+ thread = it->second;
+ }
- if (doSnapshot && !swapRenderTarget) {
- takeSnapshot(call->no);
- }
+ return thread;
+}
- if (call->no >= dumpStateCallNo &&
- dumpState(std::cout)) {
- exit(0);
+static void exit_work_queues(void)
+{
+ std::map<unsigned long, os::WorkQueue *>::iterator it;
+
+ it = thread_wq_map.begin();
+ while (it != thread_wq_map.end()) {
+ os::WorkQueue *thread_wq = it->second;
+
+ thread_wq->flush();
+ thread_wq->destroy();
+ thread_wq_map.erase(it++);
+ }
+}
+
+static void do_all_calls(void)
+{
+ trace::Call *call;
+ int prev_thread_id = -1;
+ os::WorkQueue *thread_wq = NULL;
+
+ while ((call = parser.parse_call())) {
+ RenderWork *render_work = new RenderWork(call);
+
+ if (use_threads) {
+ if (prev_thread_id != call->thread_id) {
+ if (thread_wq)
+ thread_wq->flush();
+ thread_wq = get_work_queue(call->thread_id);
+ prev_thread_id = call->thread_id;
+ }
+
+ thread_wq->queue_work(render_work);
+ } else {
+ render_work->run();
+ delete call;
}
- delete call;
+ if (state_dumped)
+ break;
}
+ exit_work_queues();
+}
+
+
+static void
+mainLoop() {
+ addCallbacks(retracer);
+
+ long long startTime = 0;
+ frameNo = 0;
+
+ startTime = os::getTime();
+
+ do_all_calls();
+
// Reached the end of trace
flushRendering();
@@ -204,7 +276,8 @@ usage(const char *argv0) {
" -S CALLSET calls to snapshot (default is every frame)\n"
" -v increase output verbosity\n"
" -D CALLNO dump state at specific call no\n"
- " -w waitOnFinish on final frame\n";
+ " -w waitOnFinish on final frame\n"
+ " -t enable threading\n";
}
@@ -274,6 +347,8 @@ int main(int argc, char **argv)
++retrace::verbosity;
} else if (!strcmp(arg, "-w")) {
waitOnFinish = true;
+ } else if (!strcmp(arg, "-t")) {
+ use_threads = true;
} else {
std::cerr << "error: unknown option " << arg << "\n";
usage(argv[0]);
--
1.7.5.4
More information about the apitrace
mailing list