[PATCH 1/3][RFC] Support single frame capture with glx
Juha-Pekka Heikkila
juhapekka.heikkila at gmail.com
Mon Mar 2 04:13:26 PST 2015
Added initial possibility to create gl trace starting from
indicated frame. Still work to do the make it replayeable,
now it captures calls only from given frames but misses
needed setup (state, displaylists, textures, .. at least..)
Start with special capture mode by setting environment variable:
APITRACE_SINGLE_FRAME_CAPTURE_MODE=1
When want to start capture frames:
echo 3 > /tmp/apitrace_capture_frame_now.txt
Where 3 indicate amount of frames to be captured.
Signed-off-by: Juha-Pekka Heikkila <juhapekka.heikkila at gmail.com>
---
common/trace_writer.cpp | 29 +++++++---
common/trace_writer.hpp | 14 +++++
common/trace_writer_local.cpp | 127 ++++++++++++++++++++++++++++++++++++++++--
common/trace_writer_local.hpp | 9 +++
4 files changed, 168 insertions(+), 11 deletions(-)
diff --git a/common/trace_writer.cpp b/common/trace_writer.cpp
index 37a6320..1dda884 100644
--- a/common/trace_writer.cpp
+++ b/common/trace_writer.cpp
@@ -42,6 +42,9 @@ namespace trace {
Writer::Writer() :
call_no(0)
{
+ forceWriteFlag = false;
+ singleFrameCaptureMode = false;
+ framesRemainingToCapture = -1;
m_file = File::createSnappy();
close();
}
@@ -80,7 +83,9 @@ Writer::open(const char *filename) {
void inline
Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
- m_file->write(sBuffer, dwBytesToWrite);
+ if (WRITE_TRACE) {
+ m_file->write(sBuffer, dwBytesToWrite);
+ }
}
void inline
@@ -166,7 +171,8 @@ void Writer::writeStackFrame(const RawStackFrame *frame) {
_writeUInt(frame->offset);
}
_writeByte(trace::BACKTRACE_END);
- frames[frame->id] = true;
+ if (WRITE_TRACE)
+ frames[frame->id] = true;
}
}
@@ -180,10 +186,16 @@ unsigned Writer::beginEnter(const FunctionSig *sig, unsigned thread_id) {
for (unsigned i = 0; i < sig->num_args; ++i) {
_writeString(sig->arg_names[i]);
}
- functions[sig->id] = true;
+ if (WRITE_TRACE)
+ functions[sig->id] = true;
}
- return call_no++;
+ if (WRITE_TRACE) {
+ return call_no++;
+ }
+ else {
+ return call_no;
+ }
}
void Writer::endEnter(void) {
@@ -222,7 +234,8 @@ void Writer::beginStruct(const StructSig *sig) {
for (unsigned i = 0; i < sig->num_members; ++i) {
_writeString(sig->member_names[i]);
}
- structs[sig->id] = true;
+ if (WRITE_TRACE)
+ structs[sig->id] = true;
}
}
@@ -332,7 +345,8 @@ void Writer::writeEnum(const EnumSig *sig, signed long long value) {
_writeString(sig->values[i].name);
writeSInt(sig->values[i].value);
}
- enums[sig->id] = true;
+ if (WRITE_TRACE)
+ enums[sig->id] = true;
}
writeSInt(value);
}
@@ -349,7 +363,8 @@ void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
_writeString(sig->flags[i].name);
_writeUInt(sig->flags[i].value);
}
- bitmasks[sig->id] = true;
+ if (WRITE_TRACE)
+ bitmasks[sig->id] = true;
}
_writeUInt(value);
}
diff --git a/common/trace_writer.hpp b/common/trace_writer.hpp
index 1f4cb5c..0ae3f48 100644
--- a/common/trace_writer.hpp
+++ b/common/trace_writer.hpp
@@ -37,6 +37,13 @@
#include "trace_model.hpp"
+/*
+ * These flags together decide if we really should write what is being
+ * tried to write
+ */
+#define WRITE_TRACE (!singleFrameCaptureMode || forceWriteFlag || \
+ (singleFrameCaptureMode && framesRemainingToCapture >= 0))
+
namespace trace {
class File;
@@ -51,6 +58,13 @@ namespace trace {
std::vector<bool> bitmasks;
std::vector<bool> frames;
+ /**
+ * Flag to control capture flow.
+ */
+ bool singleFrameCaptureMode;
+ int framesRemainingToCapture;
+ bool forceWriteFlag;
+
public:
Writer();
~Writer();
diff --git a/common/trace_writer_local.cpp b/common/trace_writer_local.cpp
index 473d419..475ac47 100644
--- a/common/trace_writer_local.cpp
+++ b/common/trace_writer_local.cpp
@@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include "os.hpp"
#include "os_thread.hpp"
@@ -39,6 +40,10 @@
#include "trace_format.hpp"
#include "os_backtrace.hpp"
+extern "C" {
+
+extern void stateRebuild(void);
+};
namespace trace {
@@ -55,6 +60,15 @@ const FunctionSig free_sig = {2, "free", 1, free_args};
static const char *realloc_args[2] = {"ptr", "size"};
const FunctionSig realloc_sig = {3, "realloc", 2, realloc_args};
+#ifdef __linux__
+static const char *capture_starter_filename = \
+ "/tmp/apitrace_capture_frame_now.txt";
+#endif
+
+#ifdef ANDROID
+static const char *capture_starter_filename = \
+ "/data/data/apitrace_capture_frame_now.txt";
+#endif
static void exceptionCallback(void)
{
@@ -62,6 +76,38 @@ static void exceptionCallback(void)
}
+bool LocalWriter::checkSingleFrameCaptureRequest(void) {
+ struct stat file_stat;
+ char fileread[256];
+ int err, rVal;
+
+ err = stat(capture_starter_filename, &file_stat);
+ if (err != 0) {
+ return false;
+ }
+
+ if (difftime(file_stat.st_mtim.tv_sec, oldFileModTime.tv_sec) < 1)
+ return false;
+
+ oldFileModTime = file_stat.st_mtim;
+
+ FILE *fp = fopen(capture_starter_filename, "ra");
+ if (!fp)
+ return false;
+
+ memset((void*)&fileread, sizeof(fileread), 1);
+ fread((void*)&fileread, 1, std::min((int)file_stat.st_size, \
+ (int)sizeof(fileread)), fp);
+ fclose(fp);
+
+ rVal = atoi(fileread);
+ if (rVal > 0) {
+ framesRemainingToCapture = rVal+1;
+ return true;
+ }
+ return false;
+}
+
LocalWriter::LocalWriter() :
acquired(0)
{
@@ -71,12 +117,31 @@ LocalWriter::LocalWriter() :
// Install the signal handlers as early as possible, to prevent
// interfering with the application's signal handling.
os::setExceptionCallback(exceptionCallback);
+
+#if defined (__linux__) || defined (ANDROID)
+ if (getenv("APITRACE_SINGLE_FRAME_CAPTURE_MODE") != NULL) {
+ singleFrameCaptureMode = true;
+ isSwapBufferCall = false;
+ char zerostring[] = "0";
+ FILE *fp = fopen(capture_starter_filename, "wa");
+ fwrite((void*)zerostring, 1, sizeof(*zerostring), fp);
+ fclose(fp);
+
+ struct stat file_stat;
+ stat(capture_starter_filename, &file_stat);
+ oldFileModTime = file_stat.st_mtim;
+ }
+#endif
}
LocalWriter::~LocalWriter()
{
os::resetExceptionCallback();
checkProcessId();
+#if defined (__linux__) || defined (ANDROID)
+ if (singleFrameCaptureMode)
+ remove(capture_starter_filename);
+#endif
}
void
@@ -172,7 +237,27 @@ unsigned LocalWriter::beginEnter(const FunctionSig *sig, bool fake) {
mutex.lock();
++acquired;
+ signame = sig->name;
+
+ forceWriteFlag = false;
+ isSwapBufferCall = strcmp(signame, "glXSwapBuffers")==0?true:false;
+
+ if (strncmp(signame, "glX", 3) == 0 &&
+ !(isSwapBufferCall&&framesRemainingToCapture < 0)) {
+ forceWriteFlag = true;
+ }
+
+ if (isSwapBufferCall&&framesRemainingToCapture >= 0)
+ forceWriteFlag = true;
+
+
checkProcessId();
+
+ if (singleFrameCaptureMode && !forceWriteFlag &&
+ framesRemainingToCapture <= 0) {
+ return 0;
+ }
+
if (!m_file->isOpened()) {
open();
}
@@ -198,7 +283,10 @@ unsigned LocalWriter::beginEnter(const FunctionSig *sig, bool fake) {
}
void LocalWriter::endEnter(void) {
- Writer::endEnter();
+ if (WRITE_TRACE) {
+ Writer::endEnter();
+ }
+
--acquired;
mutex.unlock();
}
@@ -206,13 +294,44 @@ void LocalWriter::endEnter(void) {
void LocalWriter::beginLeave(unsigned call) {
mutex.lock();
++acquired;
- Writer::beginLeave(call);
+
+ if (WRITE_TRACE) {
+ Writer::beginLeave(call);
+ }
}
+extern "C" void stateRebuild(void);
+
+
void LocalWriter::endLeave(void) {
- Writer::endLeave();
+ if (WRITE_TRACE) {
+ Writer::endLeave();
+ }
+
--acquired;
mutex.unlock();
+
+ if (singleFrameCaptureMode && isSwapBufferCall)
+ {
+ if (!forceWriteFlag || framesRemainingToCapture < 0) {
+ /*
+ * accept new capture requests only after old one
+ * has been handled. this is to avoid silly problems
+ * with state rebuilding.
+ */
+ if (checkSingleFrameCaptureRequest()) {
+ ::stateRebuild();
+ }
+ }
+
+ if (framesRemainingToCapture >= 0) {
+ framesRemainingToCapture--;
+ }
+
+ if (framesRemainingToCapture == 0) {
+ framesRemainingToCapture = -1;
+ }
+ }
}
void LocalWriter::flush(void) {
@@ -265,5 +384,5 @@ void fakeMemcpy(const void *ptr, size_t size) {
}
-} /* namespace trace */
+} /* namespace trace */
diff --git a/common/trace_writer_local.hpp b/common/trace_writer_local.hpp
index 3b00c81..bb5e71d 100644
--- a/common/trace_writer_local.hpp
+++ b/common/trace_writer_local.hpp
@@ -78,6 +78,15 @@ namespace trace {
void checkProcessId();
+ /**
+ * Capture n following frames instead of continuous capture
+ */
+ bool checkSingleFrameCaptureRequest(void);
+
+ timespec oldFileModTime;
+ bool isSwapBufferCall;
+ const char* signame;
+
public:
/**
* Should never called directly -- use localWriter singleton below
--
1.8.5.1
More information about the apitrace
mailing list