X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=retrace%2Fretrace_main.cpp;h=f9eabcb3b5cfe26729f17e28ab3fbb39bad02ab7;hb=58167d7abcd4159c5524ceca67f0ec58c96b0af7;hp=f91928beb2ee7244e5fa7c3447748dd41e8ef55e;hpb=06555614b7385c49964d27aaeec68dec6ff31744;p=apitrace diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp index f91928b..f9eabcb 100644 --- a/retrace/retrace_main.cpp +++ b/retrace/retrace_main.cpp @@ -29,13 +29,14 @@ #include "os_binary.hpp" #include "os_time.hpp" +#include "os_thread.hpp" #include "image.hpp" #include "trace_callset.hpp" #include "trace_dump.hpp" #include "retrace.hpp" -static bool wait = false; +static bool waitOnFinish = false; static const char *comparePrefix = NULL; static const char *snapshotPrefix = NULL; @@ -44,23 +45,30 @@ static trace::CallSet compareFrequency; static unsigned dumpStateCallNo = ~0; +retrace::Retracer retracer; + namespace retrace { trace::Parser parser; +trace::Profiler profiler; int verbosity = 0; bool debug = true; -bool profiling = false; - +bool dumpingState = false; bool doubleBuffer = true; bool coreProfile = false; +bool profiling = false; +bool profilingGpuTimes = false; +bool profilingCpuTimes = false; +bool profilingPixelsDrawn = false; -static unsigned frameNo = 0; +unsigned frameNo = 0; +unsigned callNo = 0; void @@ -115,54 +123,240 @@ takeSnapshot(unsigned call_no) { } +class RelayRunner; + + static void -mainLoop() { - retrace::Retracer retracer; +retraceCall(trace::Call *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); + } + } - addCallbacks(retracer); + callNo = call->no; + retracer.retrace(*call); - long long startTime = 0; + if (doSnapshot && !swapRenderTarget) + takeSnapshot(call->no); - startTime = os::getTime(); - trace::Call *call; + if (call->no >= dumpStateCallNo && + dumpState(std::cout)) { + exit(0); + } +} - 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); + +class RelayRace +{ +public: + std::vector runners; + + RelayRace(); + + RelayRunner * + getRunner(unsigned leg); + + void + startRace(void); + + void + passBaton(trace::Call *call); + + void + finishRace(); +}; + + +class RelayRunner +{ +public: + RelayRace *race; + unsigned leg; + os::mutex mutex; + os::condition_variable wake_cond; + + bool finished; + trace::Call *baton; + os::thread *thread; + + static void * + runnerThread(RelayRunner *_this); + + RelayRunner(RelayRace *race, unsigned _leg) : + race(race), + leg(_leg), + finished(false), + baton(0), + thread(0) + { + if (leg) { + thread = new os::thread(runnerThread, this); + } + } + + void + runRace(void) { + os::unique_lock lock(mutex); + + while (1) { + while (!finished && !baton) { + wake_cond.wait(lock); } + + if (finished) { + break; + } + + assert(baton); + trace::Call *call = baton; + baton = 0; + + runLeg(call); } - retracer.retrace(*call); + if (0) std::cerr << "leg " << leg << " actually finishing\n"; - if (doSnapshot && !swapRenderTarget) { - takeSnapshot(call->no); + if (leg == 0) { + std::vector::iterator it; + for (it = race->runners.begin() + 1; it != race->runners.end(); ++it) { + RelayRunner* runner = *it; + runner->finishRace(); + } } + } - if (call->no >= dumpStateCallNo && - dumpState(std::cout)) { - exit(0); + void runLeg(trace::Call *call) { + do { + assert(call); + assert(call->thread_id == leg); + retraceCall(call); + delete call; + call = parser.parse_call(); + } while (call && call->thread_id == leg); + + if (call) { + assert(call->thread_id != leg); + flushRendering(); + race->passBaton(call); + } else { + if (0) std::cerr << "finished on leg " << leg << "\n"; + if (leg) { + race->finishRace(); + } else { + finished = true; + } } + } + + void receiveBaton(trace::Call *call) { + assert (call->thread_id == leg); - delete call; + mutex.lock(); + baton = call; + mutex.unlock(); + + wake_cond.signal(); } - // Reached the end of trace - flushRendering(); + void finishRace() { + if (0) std::cerr << "notify finish to leg " << leg << "\n"; + + mutex.lock(); + finished = true; + mutex.unlock(); + + wake_cond.signal(); + } +}; + +void * +RelayRunner::runnerThread(RelayRunner *_this) { + _this->runRace(); + return 0; +} + + +RelayRace::RelayRace() { + runners.push_back(new RelayRunner(this, 0)); +} + +RelayRunner * +RelayRace::getRunner(unsigned leg) { + RelayRunner *runner; + + if (leg >= runners.size()) { + runners.resize(leg + 1); + runner = 0; + } else { + runner = runners[leg]; + } + if (!runner) { + runner = new RelayRunner(this, leg); + runners[leg] = runner; + } + return runner; +} + +void +RelayRace::startRace(void) { + trace::Call *call; + call = parser.parse_call(); + + if (!call) { + return; + } + + assert(call->thread_id == 0); + + RelayRunner *foreRunner = getRunner(0); + if (call->thread_id == 0) { + foreRunner->baton = call; + } else { + passBaton(call); + } + + foreRunner->runRace(); +} + +void +RelayRace::passBaton(trace::Call *call) { + if (0) std::cerr << "switching to thread " << call->thread_id << "\n"; + RelayRunner *runner = getRunner(call->thread_id); + runner->receiveBaton(call); +} + +void +RelayRace::finishRace(void) { + RelayRunner *runner = getRunner(0); + runner->finishRace(); +} + + +static void +mainLoop() { + addCallbacks(retracer); + + long long startTime = 0; + frameNo = 0; + + startTime = os::getTime(); + + RelayRace race; + race.startRace(); long long endTime = os::getTime(); float timeInterval = (endTime - startTime) * (1.0 / os::timeFrequency); @@ -174,10 +368,10 @@ mainLoop() { " average of " << (frameNo/timeInterval) << " fps\n"; } - if (wait) { + if (waitOnFinish) { waitForInput(); } else { - exit(0); + return; } } @@ -188,11 +382,13 @@ mainLoop() { static void usage(const char *argv0) { std::cout << - "Usage: " << argv0 << " [OPTION] TRACE\n" + "Usage: " << argv0 << " [OPTION] TRACE [...]\n" "Replay TRACE.\n" "\n" " -b benchmark mode (no error checking or warning messages)\n" - " -p profiling mode (run whole trace, dump profiling info)\n" + " -pcpu cpu profiling (cpu times per call)\n" + " -pgpu gpu profiling (gpu times per draw call)\n" + " -ppd pixels drawn profiling (pixels drawn per draw call)\n" " -c PREFIX compare against snapshots\n" " -C CALLSET calls to compare (default is every frame)\n" " -core use core profile\n" @@ -202,13 +398,15 @@ 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 wait on final frame\n"; + " -w waitOnFinish on final frame\n"; } extern "C" int main(int argc, char **argv) { + using namespace retrace; + assert(compareFrequency.empty()); assert(snapshotFrequency.empty()); @@ -225,10 +423,6 @@ int main(int argc, char **argv) } else if (!strcmp(arg, "-b")) { retrace::debug = false; retrace::verbosity = -1; - } else if (!strcmp(arg, "-p")) { - retrace::debug = false; - retrace::profiling = true; - retrace::verbosity = -1; } else if (!strcmp(arg, "-c")) { comparePrefix = argv[++i]; if (compareFrequency.empty()) { @@ -241,6 +435,7 @@ int main(int argc, char **argv) } } else if (!strcmp(arg, "-D")) { dumpStateCallNo = atoi(argv[++i]); + dumpingState = true; retrace::verbosity = -2; } else if (!strcmp(arg, "-core")) { retrace::coreProfile = true; @@ -268,7 +463,19 @@ int main(int argc, char **argv) } else if (!strcmp(arg, "-v")) { ++retrace::verbosity; } else if (!strcmp(arg, "-w")) { - wait = true; + waitOnFinish = true; + } else if (arg[1] == 'p') { + retrace::debug = false; + retrace::profiling = true; + retrace::verbosity = -1; + + if (!strcmp(arg, "-pcpu")) { + retrace::profilingCpuTimes = true; + } else if (!strcmp(arg, "-pgpu")) { + retrace::profilingGpuTimes = true; + } else if (!strcmp(arg, "-ppd")) { + retrace::profilingPixelsDrawn = true; + } } else { std::cerr << "error: unknown option " << arg << "\n"; usage(argv[0]); @@ -277,6 +484,9 @@ int main(int argc, char **argv) } retrace::setUp(); + if (retrace::profiling) { + retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn); + } for ( ; i < argc; ++i) { if (!retrace::parser.open(argv[i])) { @@ -289,7 +499,8 @@ int main(int argc, char **argv) retrace::parser.close(); } - retrace::cleanUp(); + // XXX: X often hangs on XCloseDisplay + //retrace::cleanUp(); return 0; }