| /* |
| * @file pe_profiling/operf_mangling.cpp |
| * This file is based on daemon/opd_mangling and is used for |
| * mangling and opening of sample files for operf. |
| * |
| * @remark Copyright 2011 OProfile authors |
| * @remark Read the file COPYING |
| * |
| * Created on: Dec 15, 2011 |
| * @author Maynard Johnson |
| * (C) Copyright IBM Corp. 2011 |
| */ |
| |
| #include <sys/types.h> |
| #include <iostream> |
| |
| #include "operf_utils.h" |
| #include "operf_mangling.h" |
| #include "operf_kernel.h" |
| #include "operf_sfile.h" |
| #include "operf_counter.h" |
| #include "op_file.h" |
| #include "op_sample_file.h" |
| #include "op_mangle.h" |
| #include "op_events.h" |
| #include "op_libiberty.h" |
| #include "cverb.h" |
| |
| #include <limits.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| extern operf_read operfRead; |
| extern op_cpu cpu_type; |
| extern double cpu_speed; |
| |
| using namespace std; |
| |
| static const char * mangle_anon(struct operf_sfile const * anon) |
| { |
| char * name = (char *)xmalloc(PATH_MAX); |
| |
| snprintf(name, 1024, "%u.0x%llx.0x%llx", (unsigned int)anon->tgid, |
| anon->start_addr, anon->end_addr); |
| |
| return (const char *)name; |
| } |
| |
| static char * |
| mangle_filename(struct operf_sfile * last, struct operf_sfile const * sf, int counter, int cg) |
| { |
| char * mangled; |
| struct mangle_values values = {0, NULL, NULL, NULL, NULL, NULL, 0, 0, -1, -1, -1}; |
| const struct operf_event * event = operfRead.get_event_by_counter(counter); |
| |
| values.anon_name = NULL; |
| values.flags = 0; |
| |
| if (sf->kernel) { |
| values.image_name = sf->kernel->name; |
| values.flags |= MANGLE_KERNEL; |
| } else if (sf->is_anon) { |
| values.flags |= MANGLE_ANON; |
| values.image_name = mangle_anon(sf); |
| values.anon_name = sf->image_name; |
| } else { |
| values.image_name = sf->image_name; |
| } |
| values.dep_name = sf->app_filename; |
| if (operf_options::separate_thread) { |
| values.flags |= MANGLE_TGID | MANGLE_TID; |
| values.tid = sf->tid; |
| values.tgid = sf->tgid; |
| } |
| |
| if (operf_options::separate_cpu) { |
| values.flags |= MANGLE_CPU; |
| values.cpu = sf->cpu; |
| } |
| |
| if (cg) { |
| values.flags |= MANGLE_CALLGRAPH; |
| if (last->kernel) { |
| values.cg_image_name = last->kernel->name; |
| } else if (last->is_anon) { |
| values.flags |= MANGLE_CG_ANON; |
| values.cg_image_name = mangle_anon((struct operf_sfile const *)last); |
| values.anon_name = "anon"; |
| } else { |
| values.cg_image_name = last->image_name; |
| } |
| } |
| |
| values.event_name = event->name; |
| values.count = event->count; |
| values.unit_mask = event->evt_um; |
| |
| mangled = op_mangle_filename(&values); |
| |
| if (values.flags & MANGLE_ANON) |
| free((char *)values.image_name); |
| if (values.flags & MANGLE_CG_ANON) |
| free((char *)values.cg_image_name); |
| return mangled; |
| } |
| |
| static void fill_header(struct opd_header * header, unsigned long counter, |
| vma_t anon_start, vma_t cg_to_anon_start, |
| int is_kernel, int cg_to_is_kernel, |
| int spu_samples, uint64_t embed_offset, time_t mtime) |
| { |
| const operf_event_t * event = operfRead.get_event_by_counter(counter); |
| |
| memset(header, '\0', sizeof(struct opd_header)); |
| header->version = OPD_VERSION; |
| memcpy(header->magic, OPD_MAGIC, sizeof(header->magic)); |
| header->cpu_type = cpu_type; |
| header->ctr_event = event->op_evt_code; |
| header->ctr_count = event->count; |
| header->ctr_um = event->evt_um; |
| header->is_kernel = is_kernel; |
| header->cg_to_is_kernel = cg_to_is_kernel; |
| header->cpu_speed = cpu_speed; |
| header->mtime = mtime; |
| header->anon_start = anon_start; |
| header->spu_profile = spu_samples; |
| header->embedded_offset = embed_offset; |
| header->cg_to_anon_start = cg_to_anon_start; |
| } |
| |
| int operf_open_sample_file(odb_t *file, struct operf_sfile *last, |
| struct operf_sfile * sf, int counter, int cg) |
| { |
| char * mangled; |
| char const * binary; |
| vma_t last_start = 0; |
| int err; |
| |
| mangled = mangle_filename(last, sf, counter, cg); |
| |
| if (!mangled) |
| return EINVAL; |
| |
| cverb << vsfile << "Opening \"" << mangled << "\"" << endl; |
| |
| err = create_path(mangled); |
| if (err) { |
| cerr << "operf: create path for " << mangled << " failed: " << strerror(err) << endl; |
| goto out; |
| } |
| |
| /* locking sf will lock associated cg files too */ |
| operf_sfile_get(sf); |
| if (sf != last) |
| operf_sfile_get(last); |
| |
| retry: |
| err = odb_open(file, mangled, ODB_RDWR, sizeof(struct opd_header)); |
| |
| /* This should never happen unless someone is clearing out sample data dir. */ |
| if (err) { |
| if (err == EMFILE) { |
| if (operf_sfile_lru_clear()) { |
| cerr << "LRU cleared but odb_open() fails for " << mangled << endl; |
| abort(); |
| } |
| goto retry; |
| } |
| if (err == EINTR) { |
| cverb << vsfile << "operf: open of " << mangled << " was interrupted. Trying again." << endl; |
| goto retry; |
| } |
| |
| cerr << "operf: open of " << mangled << " failed: " << strerror(err) << endl; |
| goto out; |
| } |
| |
| if (!sf->kernel) |
| binary = sf->image_name; |
| else |
| binary = sf->kernel->name; |
| |
| if (last && last->is_anon) |
| last_start = last->start_addr; |
| |
| fill_header((struct opd_header *)odb_get_data(file), counter, |
| sf->is_anon ? sf->start_addr : 0, last_start, |
| !!sf->kernel, last ? !!last->kernel : 0, |
| 0, 0, |
| binary ? op_get_mtime(binary) : 0); |
| |
| out: |
| operf_sfile_put(sf); |
| if (sf != last) |
| operf_sfile_put(last); |
| free(mangled); |
| return err; |
| } |