1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <inttypes.h> 4 #include "gtrace.h" 5 6 // A buffer of zeros 7 static char zeros[Gtrace::kGtraceEntriesPerBlock * sizeof(Gtrace::trace_entry)]; 8 9 Gtrace::Gtrace() { 10 gtrace_file_ = NULL; 11 ftrace_ = NULL; 12 fnames_ = NULL; 13 start_sec_ = 0; 14 pdate_ = 0; 15 ptime_ = 0; 16 num_entries_ = 0; 17 blockno_ = 1; 18 current_pid_ = 0; 19 } 20 21 Gtrace::~Gtrace() { 22 if (ftrace_) { 23 // Extend the trace file to a multiple of 8k. Otherwise gtracepost64 24 // complains. 25 long pos = ftell(ftrace_); 26 long pos_end = (pos + 0x1fff) & ~0x1fff; 27 if (pos_end > pos) { 28 char ch = 0; 29 fseek(ftrace_, pos_end - 1, SEEK_SET); 30 fwrite(&ch, 1, 1, ftrace_); 31 } 32 fclose(ftrace_); 33 } 34 if (fnames_) 35 fclose(fnames_); 36 } 37 38 void Gtrace::Open(const char *gtrace_file, uint32_t pdate, uint32_t ptime) 39 { 40 ftrace_ = fopen(gtrace_file, "w"); 41 if (ftrace_ == NULL) { 42 perror(gtrace_file); 43 exit(1); 44 } 45 gtrace_file_ = gtrace_file; 46 47 pdate_ = pdate; 48 ptime_ = ptime; 49 sprintf(gname_file_, "gname_%x_%06x.txt", pdate, ptime); 50 fnames_ = fopen(gname_file_, "w"); 51 if (fnames_ == NULL) { 52 perror(gname_file_); 53 exit(1); 54 } 55 fprintf(fnames_, "# File# Proc# Line# Name\n"); 56 } 57 58 void Gtrace::WriteFirstHeader(uint32_t start_sec, uint32_t pid) 59 { 60 first_header fh; 61 current_pid_ = pid; 62 start_sec_ = start_sec; 63 FillFirstHeader(start_sec, pid, &fh); 64 fwrite(&fh, sizeof(fh), 1, ftrace_); 65 num_entries_ = 8; 66 } 67 68 void Gtrace::FillFirstHeader(uint32_t start_sec, uint32_t pid, 69 first_header *fh) { 70 int cpu = 0; 71 int max_files = 16; 72 int max_procedures = 12; 73 74 fh->common.blockno = 0; 75 fh->common.entry_width = 8; 76 fh->common.block_tic = kBaseTic; 77 fh->common.block_time = start_sec; 78 //fh->common.usec_cpu = (start_usec << 8) | (cpu & 0xff); 79 fh->common.usec_cpu = cpu & 0xff; 80 fh->common.pid = pid; 81 fh->common.bug_count = 0; 82 fh->common.zero_count = 0; 83 84 fh->tic = kBaseTic + 1; 85 fh->one = 1; 86 fh->tics_per_second = kTicsPerSecond; 87 fh->trace_time = start_sec; 88 fh->version = 5; 89 fh->file_proc = (max_files << 8) | max_procedures; 90 fh->pdate = pdate_; 91 fh->ptime = ptime_; 92 } 93 94 void Gtrace::WriteBlockHeader(uint32_t cycle, uint32_t pid) 95 { 96 int cpu = 0; 97 block_header bh; 98 99 bh.blockno = blockno_++; 100 bh.entry_width = 8; 101 bh.block_tic = cycle + kBaseTic; 102 bh.block_time = start_sec_ + cycle / kTicsPerSecond; 103 //bh.usec_cpu = (start_usec << 8) | (cpu & 0xff); 104 bh.usec_cpu = cpu & 0xff; 105 bh.pid = pid; 106 bh.bug_count = 0; 107 bh.zero_count = 0; 108 fwrite(&bh, sizeof(bh), 1, ftrace_); 109 } 110 111 void Gtrace::AddGtraceRecord(int filenum, int procnum, uint32_t cycle, uint32_t pid, 112 int is_exit) 113 { 114 trace_entry entry; 115 116 if (current_pid_ != pid) { 117 current_pid_ = pid; 118 119 // We are switching to a new process id, so pad the current block 120 // with zeros. 121 int num_zeros = (kGtraceEntriesPerBlock - num_entries_) * sizeof(entry); 122 fwrite(zeros, num_zeros, 1, ftrace_); 123 WriteBlockHeader(cycle, pid); 124 num_entries_ = 4; 125 } 126 127 // If the current block is full, write out a new block header 128 if (num_entries_ == kGtraceEntriesPerBlock) { 129 WriteBlockHeader(cycle, pid); 130 num_entries_ = 4; 131 } 132 133 entry.cycle = cycle + kBaseTic; 134 entry.event = (filenum << 13) | (procnum << 1) | is_exit; 135 fwrite(&entry, sizeof(entry), 1, ftrace_); 136 num_entries_ += 1; 137 } 138 139 void Gtrace::AddProcEntry(int filenum, int procnum, uint32_t cycle, uint32_t pid) 140 { 141 AddGtraceRecord(filenum, procnum, cycle, pid, 0); 142 } 143 144 void Gtrace::AddProcExit(int filenum, int procnum, uint32_t cycle, uint32_t pid) 145 { 146 AddGtraceRecord(filenum, procnum, cycle, pid, 1); 147 } 148 149 void Gtrace::AddProcedure(int filenum, int procnum, const char *proc_name) 150 { 151 fprintf(fnames_, "%d %d %d %s\n", filenum, procnum, procnum, proc_name); 152 } 153