/** * Print the recorded profiling information to the specified file. */ void profile_print_info(FILE* f) { typedef std::vector< std::pair<Key, size_t> > BacktraceVector; CountGreater is_greater; // Grab both locks for the duration of the print operation, // to ensure the output is a consistent snapshot of a single point in time Guard generic_calls_guard(generic_calls_mutex); Guard virtual_calls_guard(virtual_calls_mutex); // print the info from generic_calls, sorted by frequency // // We print the generic_calls info ahead of virtual_calls, since it is more // useful in some cases. All T_GENERIC_PROTOCOL calls can be eliminated // from most programs. Not all T_VIRTUAL_CALLs will be eliminated by // converting to templates. BacktraceVector gp_sorted(generic_calls.begin(), generic_calls.end()); std::sort(gp_sorted.begin(), gp_sorted.end(), is_greater); for (BacktraceVector::const_iterator it = gp_sorted.begin(); it != gp_sorted.end(); ++it) { Key const &key = it->first; size_t const count = it->second; fprintf(f, "T_GENERIC_PROTOCOL: %zu calls to %s with a %s:\n", count, key.getTypeName(), key.getTypeName2()); key.getBacktrace()->print(f, 2); fprintf(f, "\n"); } // print the info from virtual_calls, sorted by frequency BacktraceVector vc_sorted(virtual_calls.begin(), virtual_calls.end()); std::sort(vc_sorted.begin(), vc_sorted.end(), is_greater); for (BacktraceVector::const_iterator it = vc_sorted.begin(); it != vc_sorted.end(); ++it) { Key const &key = it->first; size_t const count = it->second; fprintf(f, "T_VIRTUAL_CALL: %zu calls on %s:\n", count, key.getTypeName()); key.getBacktrace()->print(f, 2); fprintf(f, "\n"); } }
/** * Write a BacktraceMap as Google CPU profiler binary data. */ static void profile_write_pprof_file(FILE* f, BacktraceMap const& map) { // Write the header uintptr_t header[5] = { 0, 3, 0, 0, 0 }; fwrite(&header, sizeof(header), 1, f); // Write the profile records for (BacktraceMap::const_iterator it = map.begin(); it != map.end(); ++it) { uintptr_t count = it->second; fwrite(&count, sizeof(count), 1, f); Backtrace const* bt = it->first.getBacktrace(); uintptr_t num_pcs = bt->getDepth(); fwrite(&num_pcs, sizeof(num_pcs), 1, f); for (uintptr_t n = 0; n < num_pcs; ++n) { void* pc = bt->getFrame(n); fwrite(&pc, sizeof(pc), 1, f); } } // Write the trailer uintptr_t trailer[3] = { 0, 1, 0 }; fwrite(&trailer, sizeof(trailer), 1, f); // Write /proc/self/maps // TODO(simpkins): This only works on linux FILE *proc_maps = fopen("/proc/self/maps", "r"); if (proc_maps) { uint8_t buf[4096]; while (true) { size_t bytes_read = fread(buf, 1, sizeof(buf), proc_maps); if (bytes_read == 0) { break; } fwrite(buf, 1, bytes_read, f); } fclose(proc_maps); } }