summaryrefslogtreecommitdiffstats
path: root/external/optick/optick_core.linux.h
diff options
context:
space:
mode:
Diffstat (limited to 'external/optick/optick_core.linux.h')
-rw-r--r--external/optick/optick_core.linux.h410
1 files changed, 410 insertions, 0 deletions
diff --git a/external/optick/optick_core.linux.h b/external/optick/optick_core.linux.h
new file mode 100644
index 0000000..e0f4b49
--- /dev/null
+++ b/external/optick/optick_core.linux.h
@@ -0,0 +1,410 @@
+#pragma once
+#if defined(__linux__)
+
+#include "optick.config.h"
+#if USE_OPTICK
+
+#include "optick_core.platform.h"
+
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <unistd.h>
+
+namespace Optick
+{
+ const char* Platform::GetName()
+ {
+ return "Linux";
+ }
+
+ ThreadID Platform::GetThreadID()
+ {
+ return syscall(SYS_gettid);
+ }
+
+ ProcessID Platform::GetProcessID()
+ {
+ return (ProcessID)getpid();
+ }
+
+ int64 Platform::GetFrequency()
+ {
+ return 1000000000;
+ }
+
+ int64 Platform::GetTime()
+ {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+ }
+}
+
+#if OPTICK_ENABLE_TRACING
+
+#include "optick_memory.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+namespace ft
+{
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ struct base_event
+ {
+ int64_t timestamp;
+ short common_type;
+ uint8_t cpu_id;
+ base_event(short type) : timestamp(-1), common_type(type), cpu_id(uint8_t(-1)) {}
+};
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ template<short TYPE>
+ struct event : public base_event
+ {
+ static const short type = TYPE;
+ event() : base_event(TYPE) {}
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ struct process_state
+ {
+ enum type
+ {
+ Unknown,
+ //D Uninterruptible sleep(usually IO)
+ UninterruptibleSleep,
+ //R Running or runnable(on run queue)
+ Running,
+ //S Interruptible sleep(waiting for an event to complete)
+ InterruptibleSleep,
+ //T Stopped, either by a job control signal or because it is being traced.
+ Stopped,
+ //X dead(should never be seen)
+ Dead,
+ //Z Defunct(“zombie”) process, terminated but not reaped by its parent.
+ Zombie,
+ };
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ struct sched_switch : public event<305>
+ {
+ char prev_comm[16];
+ pid_t prev_pid;
+ int prev_prio;
+ process_state::type prev_state;
+ char next_comm[16];
+ pid_t next_pid;
+ int next_prio;
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+} // namespace ft
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace Optick
+{
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static const char* KERNEL_TRACING_PATH = "/sys/kernel/debug/tracing";
+static const char* FTRACE_TRACE = "trace";
+static const char* FTRACE_TRACING_ON = "tracing_on";
+static const char* FTRACE_TRACE_CLOCK = "trace_clock";
+static const char* FTRACE_OPTIONS_IRQ_INFO = "options/irq-info";
+static const char* FTRACE_SCHED_SWITCH = "events/sched/sched_switch/enable";
+static const uint8_t PROCESS_STATE_REASON_START = 38;
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+class FTrace : public Trace
+{
+ bool isActive;
+ string password;
+
+ bool Parse(const char* line);
+ bool ProcessEvent(const ft::base_event& ev);
+
+ void Set(const char* name, bool value);
+ void Set(const char* name, const char* value);
+ void Exec(const char* cmd);
+public:
+
+ FTrace();
+ ~FTrace();
+
+ virtual void SetPassword(const char* pwd) override { password = pwd; }
+ virtual CaptureStatus::Type Start(Mode::Type mode, int frequency, const ThreadList& threads) override;
+ virtual bool Stop() override;
+};
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+FTrace g_FTrace;
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+struct Parser
+{
+ const char* cursor;
+ const char* finish;
+ size_t length;
+
+ Parser(const char* b) : cursor(b), finish(b + strlen(b)) {}
+
+ bool Skip(size_t count)
+ {
+ if ((size_t)(finish - cursor) > count)
+ {
+ cursor += count;
+ return true;
+ }
+ return false;
+ }
+
+ bool Skip(const char* text, char* output = nullptr, size_t size = 0)
+ {
+ if (const char* ptr = strstr(cursor, text))
+ {
+ if (output != nullptr)
+ {
+ size_t count = std::min(size - 1, (size_t)(ptr - cursor));
+ strncpy(output, cursor, count);
+ output[count] = '\0';
+ }
+ cursor = ptr + strlen(text);
+ return true;
+ }
+ return false;
+ }
+
+ void SkipSpaces()
+ {
+ while (cursor != finish && (*cursor == ' ' || *cursor == '\t' || *cursor == '\n'))
+ ++cursor;
+ }
+
+ bool Starts(const char* text) const
+ {
+ return strncmp(cursor, text, strlen(text)) == 0;
+ }
+
+ int GetInt() const
+ {
+ return atoi(cursor);
+ }
+
+ char GetChar() const
+ {
+ return *cursor;
+ }
+};
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+CaptureStatus::Type FTrace::Start(Mode::Type mode, int /*frequency*/, const ThreadList& /*threads*/)
+{
+ if (!isActive)
+ {
+ // Disable tracing
+ Set(FTRACE_TRACING_ON, false);
+ // Cleanup old data
+ Set(FTRACE_TRACE, "");
+ // Set clock type
+ Set(FTRACE_TRACE_CLOCK, "mono");
+ // Disable irq info
+ Set(FTRACE_OPTIONS_IRQ_INFO, false);
+ // Enable switch events
+ Set(FTRACE_SCHED_SWITCH, (mode & Mode::SWITCH_CONTEXT) != 0);
+
+ // Enable tracing
+ Set(FTRACE_TRACING_ON, true);
+
+ isActive = true;
+ }
+
+ return CaptureStatus::OK;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool FTrace::Stop()
+{
+ if (!isActive)
+ {
+ return false;
+ }
+
+ // Reset variables
+ Set(FTRACE_TRACING_ON, false);
+ Set(FTRACE_SCHED_SWITCH, false);
+
+ // Parsing the output
+ char buffer[256] = { 0 };
+ sprintf_s(buffer, "echo \'%s\' | sudo -S sh -c \'cat %s/%s\'", password.c_str(), KERNEL_TRACING_PATH, FTRACE_TRACE);
+ if (FILE* pipe = popen(buffer, "r"))
+ {
+ char* line = NULL;
+ size_t len = 0;
+ while ((getline(&line, &len, pipe)) != -1)
+ Parse(line);
+ fclose(pipe);
+ }
+
+ // Cleanup data
+ Set(FTRACE_TRACE, "");
+
+ isActive = false;
+
+ return true;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool FTrace::Parse(const char * line)
+{
+ // sched_switch:
+ // ConsoleApp-8687 [000] 181944.352057: sched_switch: prev_comm=ConsoleApp prev_pid=8687 prev_prio=120 prev_state=S ==> next_comm=ConsoleApp next_pid=8686 next_prio=120
+
+ Parser p(line);
+ if (p.Starts("#"))
+ return true;
+
+ if (!p.Skip(16))
+ return false;
+
+ if (!p.Skip("["))
+ return false;
+
+ int cpu = p.GetInt();
+ if (!p.Skip("]"))
+ return false;
+
+ int64 timestampInt = p.GetInt();
+ if (!p.Skip("."))
+ return false;
+
+ int64 timestampFraq = p.GetInt();
+ if (!p.Skip(": "))
+ return false;
+
+ int64 timestamp = ((timestampInt * 1000000) + timestampFraq) * 1000;
+
+ if (p.Starts("sched_switch:"))
+ {
+ ft::sched_switch ev;
+ ev.cpu_id = cpu;
+ ev.timestamp = timestamp;
+
+ if (!p.Skip("prev_comm="))
+ return false;
+
+ if (!p.Skip(" prev_pid=", ev.prev_comm, OPTICK_ARRAY_SIZE(ev.prev_comm)))
+ return false;
+
+ ev.prev_pid = p.GetInt();
+
+ if (!p.Skip(" prev_prio="))
+ return false;
+
+ ev.prev_prio = p.GetInt();
+
+ if (!p.Skip(" prev_state="))
+ return false;
+
+ switch (p.GetChar())
+ {
+ case 'D':
+ ev.prev_state = ft::process_state::UninterruptibleSleep;
+ break;
+
+ case 'R':
+ ev.prev_state = ft::process_state::Running;
+ break;
+
+ case 'S':
+ ev.prev_state = ft::process_state::InterruptibleSleep;
+ break;
+
+ case 'T':
+ ev.prev_state = ft::process_state::Stopped;
+ break;
+
+ case 'X':
+ ev.prev_state = ft::process_state::Dead;
+ break;
+
+ case 'Z':
+ ev.prev_state = ft::process_state::Zombie;
+ break;
+
+ default:
+ ev.prev_state = ft::process_state::Unknown;
+ break;
+ }
+
+ if (!p.Skip("==> next_comm="))
+ return false;
+
+ if (!p.Skip(" next_pid=", ev.next_comm, OPTICK_ARRAY_SIZE(ev.prev_comm)))
+ return false;
+
+ ev.next_pid = p.GetInt();
+
+ if (!p.Skip(" next_prio="))
+ return false;
+
+ ev.next_prio = p.GetInt();
+
+ return ProcessEvent(ev);
+ }
+ return true;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool FTrace::ProcessEvent(const ft::base_event& ev)
+{
+ switch (ev.common_type)
+ {
+ case ft::sched_switch::type:
+ {
+ const ft::sched_switch& switchEv = (const ft::sched_switch&)ev;
+ SwitchContextDesc desc;
+ desc.reason = switchEv.prev_state + PROCESS_STATE_REASON_START;
+ desc.cpuId = switchEv.cpu_id;
+ desc.oldThreadId = (uint64)switchEv.prev_pid;
+ desc.newThreadId = (uint64)switchEv.next_pid;
+ desc.timestamp = switchEv.timestamp;
+ Core::Get().ReportSwitchContext(desc);
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void FTrace::Set(const char * name, bool value)
+{
+ Set(name, value ? "1" : "0");
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void FTrace::Set(const char* name, const char* value)
+{
+ char buffer[256] = { 0 };
+ sprintf_s(buffer, "echo %s > %s/%s", value, KERNEL_TRACING_PATH, name);
+ Exec(buffer);
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void FTrace::Exec(const char* cmd)
+{
+ char buffer[256] = { 0 };
+ sprintf_s(buffer, "echo \'%s\' | sudo -S sh -c \'%s\'", password.c_str(), cmd);
+ std::system(buffer);
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+FTrace::FTrace() : isActive(false)
+{
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+FTrace::~FTrace()
+{
+ Stop();
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+Trace* Platform::GetTrace()
+{
+ return &g_FTrace;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+SymbolEngine* Platform::GetSymbolEngine()
+{
+ return nullptr;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+}
+#endif //OPTICK_ENABLE_TRACING
+#endif //USE_OPTICK
+#endif //__linux__ \ No newline at end of file