Home | History | Annotate | Download | only in qtools
      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