blob: 384b05db9f42987caf25738687dccba527b8acb7 [file] [log] [blame]
/*
* @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;
}