The Android Open Source Project | 52d4c30 | 2009-03-03 19:29:09 -0800 | [diff] [blame] | 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 | } |