#include <limits.h> // for CHAR_MAX
#include <iostream>
#include <getopt.h>
+#ifndef _WIN32
+#include <unistd.h> // for isatty()
+#endif
#include "os_binary.hpp"
#include "os_time.hpp"
static bool waitOnFinish = false;
static bool loopOnFinish = false;
-static const char *comparePrefix = NULL;
static const char *snapshotPrefix = NULL;
static enum {
PNM_FMT,
} snapshotFormat = PNM_FMT;
static trace::CallSet snapshotFrequency;
-static trace::CallSet compareFrequency;
static trace::ParseBookmark lastFrameStart;
static unsigned dumpStateCallNo = ~0;
/**
- * Take/compare snapshots.
+ * Take snapshots.
*/
static void
takeSnapshot(unsigned call_no) {
static unsigned snapshot_no = 0;
- assert(snapshotPrefix || comparePrefix);
-
- image::Image *ref = NULL;
-
- if (comparePrefix) {
- os::String filename = os::String::format("%s%010u.png", comparePrefix, call_no);
- ref = image::readPNG(filename);
- if (!ref) {
- return;
- }
- if (retrace::verbosity >= 0) {
- std::cout << "Read " << filename << "\n";
- }
- }
+ assert(snapshotPrefix);
image::Image *src = dumper->getSnapshot();
if (!src) {
}
}
- if (ref) {
- std::cout << "Snapshot " << call_no << " average precision of " << src->compare(*ref) << " bits\n";
- delete ref;
- }
-
delete src;
snapshot_no++;
retraceCall(trace::Call *call) {
bool swapRenderTarget = call->flags &
trace::CALL_FLAG_SWAP_RENDERTARGET;
- bool doSnapshot = snapshotFrequency.contains(*call) ||
- compareFrequency.contains(*call);
+ bool doSnapshot = snapshotFrequency.contains(*call);
// For calls which cause rendertargets to be swaped, we take the
// snapshot _before_ swapping the rendertargets.
" --pgpu gpu profiling (gpu times per draw call)\n"
" --ppd pixels drawn profiling (pixels drawn per draw call)\n"
" --pmem memory usage profiling (vsize rss per call)\n"
- " -c, --compare=PREFIX compare against snapshots with given PREFIX\n"
- " -C, --calls=CALLSET calls to compare (default is every frame)\n"
" --call-nos[=BOOL] use call numbers in snapshot filenames\n"
" --core use core profile\n"
" --db use a double buffer visual (default)\n"
};
const static char *
-shortOptions = "bc:C:D:hs:S:vw";
+shortOptions = "bD:hs:S:vw";
const static struct option
longOptions[] = {
{"benchmark", no_argument, 0, 'b'},
{"call-nos", optional_argument, 0, CALL_NOS_OPT },
- {"calls", required_argument, 0, 'C'},
- {"compare", required_argument, 0, 'c'},
{"core", no_argument, 0, CORE_OPT},
{"db", no_argument, 0, DB_OPT},
{"driver", required_argument, 0, DRIVER_OPT},
using namespace retrace;
int i;
- assert(compareFrequency.empty());
assert(snapshotFrequency.empty());
int opt;
case CALL_NOS_OPT:
useCallNos = trace::boolOption(optarg);
break;
- case 'c':
- comparePrefix = optarg;
- if (compareFrequency.empty()) {
- compareFrequency = trace::CallSet(trace::FREQUENCY_FRAME);
- }
- break;
- case 'C':
- compareFrequency = trace::CallSet(optarg);
- if (comparePrefix == NULL) {
- comparePrefix = "";
- }
- break;
case 'D':
dumpStateCallNo = atoi(optarg);
dumpingState = true;
if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) {
os::setBinaryMode(stdout);
retrace::verbosity = -2;
+ } else {
+ /*
+ * Create the snapshot directory if it does not exist.
+ *
+ * We can't just use trimFilename() because when applied to
+ * "/foo/boo/" it would merely return "/foo".
+ *
+ * XXX: create nested directories.
+ */
+ os::String prefix(snapshotPrefix);
+ os::String::iterator sep = prefix.rfindSep(false);
+ if (sep != prefix.end()) {
+ prefix.erase(sep, prefix.end());
+ if (!prefix.exists() && !os::createDirectory(prefix)) {
+ std::cerr << "error: failed to create `" << prefix.str() << "` directory\n";
+ }
+ }
}
break;
case SNAPSHOT_FORMAT_OPT:
}
}
+#ifndef _WIN32
+ if (!isatty(STDOUT_FILENO)) {
+ dumpFlags |= trace::DUMP_FLAG_NO_COLOR;
+ }
+#endif
+
retrace::setUp();
if (retrace::profiling) {
retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn, retrace::profilingMemoryUsage);