aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/qtools/gtrace.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/qtools/gtrace.cpp')
-rw-r--r--emulator/qtools/gtrace.cpp152
1 files changed, 152 insertions, 0 deletions
diff --git a/emulator/qtools/gtrace.cpp b/emulator/qtools/gtrace.cpp
new file mode 100644
index 0000000..673d8a4
--- /dev/null
+++ b/emulator/qtools/gtrace.cpp
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "gtrace.h"
+
+// A buffer of zeros
+static char zeros[Gtrace::kGtraceEntriesPerBlock * sizeof(Gtrace::trace_entry)];
+
+Gtrace::Gtrace() {
+ gtrace_file_ = NULL;
+ ftrace_ = NULL;
+ fnames_ = NULL;
+ start_sec_ = 0;
+ pdate_ = 0;
+ ptime_ = 0;
+ num_entries_ = 0;
+ blockno_ = 1;
+ current_pid_ = 0;
+}
+
+Gtrace::~Gtrace() {
+ if (ftrace_) {
+ // Extend the trace file to a multiple of 8k. Otherwise gtracepost64
+ // complains.
+ long pos = ftell(ftrace_);
+ long pos_end = (pos + 0x1fff) & ~0x1fff;
+ if (pos_end > pos) {
+ char ch = 0;
+ fseek(ftrace_, pos_end - 1, SEEK_SET);
+ fwrite(&ch, 1, 1, ftrace_);
+ }
+ fclose(ftrace_);
+ }
+ if (fnames_)
+ fclose(fnames_);
+}
+
+void Gtrace::Open(const char *gtrace_file, uint32_t pdate, uint32_t ptime)
+{
+ ftrace_ = fopen(gtrace_file, "w");
+ if (ftrace_ == NULL) {
+ perror(gtrace_file);
+ exit(1);
+ }
+ gtrace_file_ = gtrace_file;
+
+ pdate_ = pdate;
+ ptime_ = ptime;
+ sprintf(gname_file_, "gname_%x_%06x.txt", pdate, ptime);
+ fnames_ = fopen(gname_file_, "w");
+ if (fnames_ == NULL) {
+ perror(gname_file_);
+ exit(1);
+ }
+ fprintf(fnames_, "# File# Proc# Line# Name\n");
+}
+
+void Gtrace::WriteFirstHeader(uint32_t start_sec, uint32_t pid)
+{
+ first_header fh;
+ current_pid_ = pid;
+ start_sec_ = start_sec;
+ FillFirstHeader(start_sec, pid, &fh);
+ fwrite(&fh, sizeof(fh), 1, ftrace_);
+ num_entries_ = 8;
+}
+
+void Gtrace::FillFirstHeader(uint32_t start_sec, uint32_t pid,
+ first_header *fh) {
+ int cpu = 0;
+ int max_files = 16;
+ int max_procedures = 12;
+
+ fh->common.blockno = 0;
+ fh->common.entry_width = 8;
+ fh->common.block_tic = kBaseTic;
+ fh->common.block_time = start_sec;
+ //fh->common.usec_cpu = (start_usec << 8) | (cpu & 0xff);
+ fh->common.usec_cpu = cpu & 0xff;
+ fh->common.pid = pid;
+ fh->common.bug_count = 0;
+ fh->common.zero_count = 0;
+
+ fh->tic = kBaseTic + 1;
+ fh->one = 1;
+ fh->tics_per_second = kTicsPerSecond;
+ fh->trace_time = start_sec;
+ fh->version = 5;
+ fh->file_proc = (max_files << 8) | max_procedures;
+ fh->pdate = pdate_;
+ fh->ptime = ptime_;
+}
+
+void Gtrace::WriteBlockHeader(uint32_t cycle, uint32_t pid)
+{
+ int cpu = 0;
+ block_header bh;
+
+ bh.blockno = blockno_++;
+ bh.entry_width = 8;
+ bh.block_tic = cycle + kBaseTic;
+ bh.block_time = start_sec_ + cycle / kTicsPerSecond;
+ //bh.usec_cpu = (start_usec << 8) | (cpu & 0xff);
+ bh.usec_cpu = cpu & 0xff;
+ bh.pid = pid;
+ bh.bug_count = 0;
+ bh.zero_count = 0;
+ fwrite(&bh, sizeof(bh), 1, ftrace_);
+}
+
+void Gtrace::AddGtraceRecord(int filenum, int procnum, uint32_t cycle, uint32_t pid,
+ int is_exit)
+{
+ trace_entry entry;
+
+ if (current_pid_ != pid) {
+ current_pid_ = pid;
+
+ // We are switching to a new process id, so pad the current block
+ // with zeros.
+ int num_zeros = (kGtraceEntriesPerBlock - num_entries_) * sizeof(entry);
+ fwrite(zeros, num_zeros, 1, ftrace_);
+ WriteBlockHeader(cycle, pid);
+ num_entries_ = 4;
+ }
+
+ // If the current block is full, write out a new block header
+ if (num_entries_ == kGtraceEntriesPerBlock) {
+ WriteBlockHeader(cycle, pid);
+ num_entries_ = 4;
+ }
+
+ entry.cycle = cycle + kBaseTic;
+ entry.event = (filenum << 13) | (procnum << 1) | is_exit;
+ fwrite(&entry, sizeof(entry), 1, ftrace_);
+ num_entries_ += 1;
+}
+
+void Gtrace::AddProcEntry(int filenum, int procnum, uint32_t cycle, uint32_t pid)
+{
+ AddGtraceRecord(filenum, procnum, cycle, pid, 0);
+}
+
+void Gtrace::AddProcExit(int filenum, int procnum, uint32_t cycle, uint32_t pid)
+{
+ AddGtraceRecord(filenum, procnum, cycle, pid, 1);
+}
+
+void Gtrace::AddProcedure(int filenum, int procnum, const char *proc_name)
+{
+ fprintf(fnames_, "%d %d %d %s\n", filenum, procnum, procnum, proc_name);
+}