Home | History | Annotate | Download | only in qtools
      1 // Copyright 2006 The Android Open Source Project
      2 
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <unistd.h>
      6 #include <inttypes.h>
      7 #include <string.h>
      8 #include <unistd.h>
      9 #include "dmtrace.h"
     10 
     11 static const short kVersion = 2;
     12 
     13 const DmTrace::Header DmTrace::header = {
     14     0x574f4c53, kVersion, sizeof(DmTrace::Header), 0LL
     15 };
     16 
     17 static char *keyHeader = "*version\n" "2\n" "clock=thread-cpu\n";
     18 static char *keyThreadHeader = "*threads\n";
     19 static char *keyFunctionHeader = "*methods\n";
     20 static char *keyEnd = "*end\n";
     21 
     22 DmTrace::DmTrace() {
     23     fData = NULL;
     24     fTrace = NULL;
     25     threads = new std::vector<ThreadRecord*>;
     26     functions = new std::vector<FunctionRecord*>;
     27 }
     28 
     29 DmTrace::~DmTrace() {
     30     delete threads;
     31     delete functions;
     32 }
     33 
     34 void DmTrace::open(const char *dmtrace_file, uint64_t start_time)
     35 {
     36     fTrace = fopen(dmtrace_file, "w");
     37     if (fTrace == NULL) {
     38         perror(dmtrace_file);
     39         exit(1);
     40     }
     41 
     42     // Make a temporary file to write the data into.
     43     char tmpData[32];
     44     strcpy(tmpData, "/tmp/dmtrace-data-XXXXXX");
     45     int data_fd = mkstemp(tmpData);
     46     if (data_fd < 0) {
     47         perror("Cannot create temporary file");
     48         exit(1);
     49     }
     50 
     51     // Ensure it goes away on exit.
     52     unlink(tmpData);
     53     fData = fdopen(data_fd, "w+");
     54     if (fData == NULL) {
     55         perror("Can't make temp data file");
     56         exit(1);
     57     }
     58 
     59     writeHeader(fData, start_time);
     60 }
     61 
     62 void DmTrace::close()
     63 {
     64     if (fTrace == NULL)
     65         return;
     66     writeKeyFile(fTrace);
     67 
     68     // Take down how much data we wrote to the temp data file.
     69     long size = ftell(fData);
     70     // Rewind the data file and append its contents to the trace file.
     71     rewind(fData);
     72     char *data = (char *)malloc(size);
     73     fread(data, size, 1, fData);
     74     fwrite(data, size, 1, fTrace);
     75     free(data);
     76     fclose(fData);
     77     fclose(fTrace);
     78 }
     79 
     80 /*
     81  * Write values to the binary data file.
     82  */
     83 void DmTrace::write2LE(FILE* fstream, unsigned short val)
     84 {
     85     putc(val & 0xff, fstream);
     86     putc(val >> 8, fstream);
     87 }
     88 
     89 void DmTrace::write4LE(FILE* fstream, unsigned int val)
     90 {
     91     putc(val & 0xff, fstream);
     92     putc((val >> 8) & 0xff, fstream);
     93     putc((val >> 16) & 0xff, fstream);
     94     putc((val >> 24) & 0xff, fstream);
     95 }
     96 
     97 void DmTrace::write8LE(FILE* fstream, unsigned long long val)
     98 {
     99     putc(val & 0xff, fstream);
    100     putc((val >> 8) & 0xff, fstream);
    101     putc((val >> 16) & 0xff, fstream);
    102     putc((val >> 24) & 0xff, fstream);
    103     putc((val >> 32) & 0xff, fstream);
    104     putc((val >> 40) & 0xff, fstream);
    105     putc((val >> 48) & 0xff, fstream);
    106     putc((val >> 56) & 0xff, fstream);
    107 }
    108 
    109 void DmTrace::writeHeader(FILE *fstream, uint64_t startTime)
    110 {
    111     write4LE(fstream, header.magic);
    112     write2LE(fstream, header.version);
    113     write2LE(fstream, header.offset);
    114     write8LE(fstream, startTime);
    115 }
    116 
    117 void DmTrace::writeDataRecord(FILE *fstream, int threadId,
    118                              unsigned int methodVal,
    119                              unsigned int elapsedTime)
    120 {
    121     write2LE(fstream, threadId);
    122     write4LE(fstream, methodVal);
    123     write4LE(fstream, elapsedTime);
    124 }
    125 
    126 void DmTrace::addFunctionEntry(int functionId, uint32_t cycle, uint32_t pid)
    127 {
    128     writeDataRecord(fData, pid, functionId, cycle);
    129 }
    130 
    131 void DmTrace::addFunctionExit(int functionId, uint32_t cycle, uint32_t pid)
    132 {
    133     writeDataRecord(fData, pid, functionId | 1, cycle);
    134 }
    135 
    136 void DmTrace::addFunction(int functionId, const char *name)
    137 {
    138     FunctionRecord *rec = new FunctionRecord;
    139     rec->id = functionId;
    140     rec->name = name;
    141     functions->push_back(rec);
    142 }
    143 
    144 void DmTrace::addFunction(int functionId, const char *clazz,
    145                           const char *method, const char *sig)
    146 {
    147     // Allocate space for all the strings, plus 2 tab separators plus null byte.
    148     // We currently don't reclaim this space.
    149     int len = strlen(clazz) + strlen(method) + strlen(sig) + 3;
    150     char *name = new char[len];
    151     sprintf(name, "%s\t%s\t%s", clazz, method, sig);
    152 
    153     addFunction(functionId, name);
    154 }
    155 
    156 void DmTrace::parseAndAddFunction(int functionId, const char *name)
    157 {
    158     // Parse the "name" string into "class", "method" and "signature".
    159     // The "name" string should look something like this:
    160     //   name = "java.util.LinkedList.size()I"
    161     // and it will be parsed into this:
    162     //   clazz = "java.util.LinkedList"
    163     //   method = "size"
    164     //   sig = "()I"
    165 
    166     // Find the first parenthesis, the start of the signature.
    167     char *paren = (char*)strchr(name, '(');
    168 
    169     // If not found, then add the original name.
    170     if (paren == NULL) {
    171         addFunction(functionId, name);
    172         return;
    173     }
    174 
    175     // Copy the signature
    176     int len = strlen(paren) + 1;
    177     char *sig = new char[len];
    178     strcpy(sig, paren);
    179 
    180     // Zero the parenthesis so that we can search backwards from the signature
    181     *paren = 0;
    182 
    183     // Search for the last period, the start of the method name
    184     char *dot = (char*)strrchr(name, '.');
    185 
    186     // If not found, then add the original name.
    187     if (dot == NULL || dot == name) {
    188         delete[] sig;
    189         *paren = '(';
    190         addFunction(functionId, name);
    191         return;
    192     }
    193 
    194     // Copy the method, not including the dot
    195     len = strlen(dot + 1) + 1;
    196     char *method = new char[len];
    197     strcpy(method, dot + 1);
    198 
    199     // Zero the dot to delimit the class name
    200     *dot = 0;
    201 
    202     addFunction(functionId, name, method, sig);
    203 
    204     // Free the space we allocated.
    205     delete[] sig;
    206     delete[] method;
    207 }
    208 
    209 void DmTrace::addThread(int threadId, const char *name)
    210 {
    211     ThreadRecord *rec = new ThreadRecord;
    212     rec->id = threadId;
    213     rec->name = name;
    214     threads->push_back(rec);
    215 }
    216 
    217 void DmTrace::updateName(int threadId, const char *name)
    218 {
    219     std::vector<ThreadRecord*>::iterator iter;
    220 
    221     for (iter = threads->begin(); iter != threads->end(); ++iter) {
    222         if ((*iter)->id == threadId) {
    223             (*iter)->name = name;
    224             return;
    225         }
    226     }
    227 }
    228 
    229 void DmTrace::writeKeyFile(FILE *fstream)
    230 {
    231     fwrite(keyHeader, strlen(keyHeader), 1, fstream);
    232     writeThreads(fstream);
    233     writeFunctions(fstream);
    234     fwrite(keyEnd, strlen(keyEnd), 1, fstream);
    235 }
    236 
    237 void DmTrace::writeThreads(FILE *fstream)
    238 {
    239     std::vector<ThreadRecord*>::iterator iter;
    240 
    241     fwrite(keyThreadHeader, strlen(keyThreadHeader), 1, fstream);
    242     for (iter = threads->begin(); iter != threads->end(); ++iter) {
    243         fprintf(fstream, "%d\t%s\n", (*iter)->id, (*iter)->name);
    244     }
    245 }
    246 
    247 void DmTrace::writeFunctions(FILE *fstream)
    248 {
    249     std::vector<FunctionRecord*>::iterator iter;
    250 
    251     fwrite(keyFunctionHeader, strlen(keyFunctionHeader), 1, fstream);
    252     for (iter = functions->begin(); iter != functions->end(); ++iter) {
    253         fprintf(fstream, "0x%x\t%s\n", (*iter)->id, (*iter)->name);
    254     }
    255 }
    256