* Allow clamping to a GL version or a number of extensions.
-* Trace multiple threads:
-
- * `GetCurrentThreadId()`
-
- * `pthread_self()`
-
* Put (de)compression in a separate thread.
* Trace TSCs
" --colour=<WHEN> Colored syntax highlighting\n"
" WHEN is 'auto', 'always', or 'never'\n"
" --no-arg-names Don't dump argument names\n"
+ " --thread-ids Dump thread ids\n"
;
}
command(int argc, char *argv[])
{
trace::DumpFlags dumpFlags = 0;
+ bool dumpThreadIds = false;
int i;
color = COLOR_OPTION_NEVER;
} else if (!strcmp(arg, "--no-arg-names")) {
dumpFlags |= trace::DUMP_FLAG_NO_ARG_NAMES;
+ } else if (!strcmp(arg, "--thread-ids")) {
+ dumpThreadIds = true;
} else {
std::cerr << "error: unknown option " << arg << "\n";
usage();
while ((call = p.parse_call())) {
if (verbose ||
!(call->flags & trace::CALL_FLAG_VERBOSE)) {
+ if (dumpThreadIds) {
+ std::cout << std::hex << call->thread_id << std::dec << " ";
+ }
trace::dump(*call, std::cout, dumpFlags);
}
delete call;
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Simple OS abstraction.
+ *
+ * Mimics C++11 / boost threads.
+ */
+
+#ifndef _OS_THREAD_HPP_
+#define _OS_THREAD_HPP_
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+namespace os {
+
+
+ namespace thread {
+
+ /**
+ * Thread ID
+ *
+ * XXX: Actually C++11 thread::id is not an integral type, but we rely on that.
+ */
+#ifdef _WIN32
+ typedef DWORD id;
+#else
+ typedef pthread_t id;
+#endif
+
+ } /* namespace thread */
+
+
+ namespace this_thread {
+
+ /**
+ * Get current thread ID.
+ */
+ inline thread::id
+ get_id(void) {
+#ifdef _WIN32
+ return GetCurrentThreadId();
+#else
+ return pthread_self();
+#endif
+ }
+
+ } /* namespace this_thread */
+
+
+} /* namespace os */
+
+#endif /* _OS_THREAD_HPP_ */
*
* - version 3:
* - enums signatures are recorded for the a whole set of values (not as individual values)
+ *
+ * - version 4:
+ * - call enter events include thread ID
*/
-#define TRACE_VERSION 3
+#define TRACE_VERSION 4
/*
*
* trace = event* EOF
*
- * event = EVENT_ENTER call_sig call_detail+
+ * event = EVENT_ENTER thread_id call_sig call_detail+
* | EVENT_LEAVE call_no call_detail+
*
* call_sig = sig_id ( name arg_names )?
class Call
{
public:
+ unsigned thread_id;
unsigned no;
const FunctionSig *sig;
std::vector<Value *> args;
CallFlags flags;
- Call(FunctionSig *_sig, const CallFlags &_flags) :
+ Call(FunctionSig *_sig, const CallFlags &_flags, unsigned _thread_id) :
+ thread_id(_thread_id),
sig(_sig),
args(_sig->num_args),
ret(0),
void Parser::parse_enter(Mode mode) {
+ unsigned thread_id;
+
+ if (version >= 4) {
+ thread_id = read_uint();
+ } else {
+ thread_id = 0;
+ }
+
FunctionSigFlags *sig = parse_function_sig();
- Call *call = new Call(sig, sig->flags);
+ Call *call = new Call(sig, sig->flags, thread_id);
call->no = next_call_no++;
}
}
-unsigned Writer::beginEnter(const FunctionSig *sig) {
+unsigned Writer::beginEnter(const FunctionSig *sig, unsigned thread_id) {
_writeByte(trace::EVENT_ENTER);
+ _writeUInt(thread_id);
_writeUInt(sig->id);
if (!lookup(functions, sig->id)) {
_writeString(sig->name);
bool open(const char *filename);
void close(void);
- unsigned beginEnter(const FunctionSig *sig);
+ unsigned beginEnter(const FunctionSig *sig, unsigned thread_id);
void endEnter(void);
void beginLeave(unsigned call);
#include <string.h>
#include "os.hpp"
+#include "os_thread.hpp"
#include "os_string.hpp"
#include "trace_file.hpp"
#include "trace_writer.hpp"
open();
}
- return Writer::beginEnter(sig);
+ os::thread::id id = os::this_thread::get_id();
+
+ return Writer::beginEnter(sig, static_cast<unsigned>(id));
}
void LocalWriter::endEnter(void) {
}
void visit(Call *call) {
- unsigned call_no = writer.beginEnter(call->sig);
+ unsigned call_no = writer.beginEnter(call->sig, call->thread_id);
for (unsigned i = 0; i < call->args.size(); ++i) {
if (call->args[i]) {
writer.beginArg(i);