opd_events.c

Go to the documentation of this file.
00001 
00012 #include "config.h"
00013  
00014 #include "opd_events.h"
00015 #include "opd_printf.h"
00016 #include "opd_extended.h"
00017 #include "oprofiled.h"
00018 
00019 #include "op_string.h"
00020 #include "op_config.h"
00021 #include "op_cpufreq.h"
00022 #include "op_cpu_type.h"
00023 #include "op_libiberty.h"
00024 #include "op_hw_config.h"
00025 #include "op_sample_file.h"
00026 #include "op_events.h"
00027 
00028 #include <stdlib.h>
00029 #include <stdio.h>
00030 
00031 extern op_cpu cpu_type;
00032 
00033 struct opd_event opd_events[OP_MAX_COUNTERS];
00034 
00035 static double cpu_speed;
00036 
00037 static void malformed_events(void)
00038 {
00039     fprintf(stderr, "oprofiled: malformed events passed "
00040         "on the command line\n");
00041     exit(EXIT_FAILURE);
00042 }
00043 
00044 
00045 static char * copy_token(char ** c, char delim)
00046 {
00047     char * tmp = *c;
00048     char * tmp2 = *c;
00049     char * str;
00050 
00051     if (!**c)
00052         return NULL;
00053 
00054     while (*tmp2 && *tmp2 != delim)
00055         ++tmp2;
00056 
00057     if (tmp2 == tmp)
00058         return NULL;
00059 
00060     str = op_xstrndup(tmp, tmp2 - tmp);
00061     *c = tmp2;
00062     if (**c)
00063         ++*c;
00064     return str;
00065 }
00066 
00067 
00068 static unsigned long copy_ulong(char ** c, char delim)
00069 {
00070     unsigned long val = 0;
00071     char * str = copy_token(c, delim);
00072     if (!str)
00073         malformed_events();
00074     val = strtoul(str, NULL, 0);
00075     free(str);
00076     return val;
00077 }
00078 
00079 
00080 void opd_parse_events(char const * events)
00081 {
00082     char * ev = xstrdup(events);
00083     char * c;
00084     size_t cur = 0;
00085 
00086     cpu_speed = op_cpu_frequency();
00087 
00088     if (cpu_type == CPU_TIMER_INT) {
00089         struct opd_event * event = &opd_events[0];
00090         event->name = xstrdup("TIMER");
00091         event->value = event->counter
00092             = event->count = event->um = 0;
00093         event->kernel = 1;
00094         event->user = 1;
00095         return;
00096     }
00097 
00098     if (!ev || !strlen(ev)) {
00099         fprintf(stderr, "oprofiled: no events passed.\n");
00100         exit(EXIT_FAILURE);
00101     }
00102 
00103     verbprintf(vmisc, "Events: %s\n", ev);
00104 
00105     c = ev;
00106 
00107     while (*c && cur < op_nr_counters) {
00108         struct opd_event * event = &opd_events[cur];
00109 
00110         if (!(event->name = copy_token(&c, ':')))
00111             malformed_events();
00112         event->value = copy_ulong(&c, ':');
00113         event->counter = copy_ulong(&c, ':');
00114         event->count = copy_ulong(&c, ':');
00115         event->um = copy_ulong(&c, ':');
00116         event->kernel = copy_ulong(&c, ':');
00117         event->user = copy_ulong(&c, ',');
00118         ++cur;
00119     }
00120 
00121     if (*c) {
00122         fprintf(stderr, "oprofiled: too many events passed.\n");
00123         exit(EXIT_FAILURE);
00124     }
00125 
00126     free(ev);
00127 }
00128 
00129 
00130 struct opd_event * find_counter_event(unsigned long counter)
00131 {
00132     size_t i;
00133     struct opd_event * ret = NULL;
00134 
00135     if (counter >= OP_MAX_COUNTERS) {
00136         if((ret = opd_ext_find_counter_event(counter)) != NULL)
00137             return ret;
00138     }
00139 
00140     /*
00141      *  The kernel modules will put a 0 as counter number into the
00142      *  samples when timer based sampling is used.  So this
00143      *  theoretically might get confused here with the first
00144      *  hardware counter also having number zero.  However, TIMER
00145      *  is never allowed to be used together with other events.
00146      *  So it is safe to map this to the timer event without
00147      *  actually doing the lookup.
00148      */
00149     if (op_cpu_has_timer_fs()
00150         && strcmp(opd_events[0].name, TIMER_EVENT_NAME) == 0
00151         && !opd_events[1].name) {
00152         return &opd_events[0];
00153 
00154     }
00155 
00156     for (i = 0; i < op_nr_counters && opd_events[i].name; ++i) {
00157         if (counter == opd_events[i].counter)
00158             return &opd_events[i];
00159     }
00160 
00161     fprintf(stderr, "Unknown event for counter %lu\n", counter);
00162     abort();
00163     return NULL;
00164 }
00165 
00166 
00167 void fill_header(struct opd_header * header, unsigned long counter,
00168          vma_t anon_start, vma_t cg_to_anon_start,
00169          int is_kernel, int cg_to_is_kernel,
00170          int spu_samples, uint64_t embed_offset, time_t mtime)
00171 {
00172     struct opd_event * event = find_counter_event(counter);
00173 
00174     memset(header, '\0', sizeof(struct opd_header));
00175     header->version = OPD_VERSION;
00176     memcpy(header->magic, OPD_MAGIC, sizeof(header->magic));
00177     header->cpu_type = cpu_type;
00178     header->ctr_event = event->value;
00179     header->ctr_count = event->count;
00180     header->ctr_um = event->um;
00181     header->is_kernel = is_kernel;
00182     header->cg_to_is_kernel = cg_to_is_kernel;
00183     header->cpu_speed = cpu_speed;
00184     header->mtime = mtime;
00185     header->anon_start = anon_start;
00186     header->spu_profile = spu_samples;
00187     header->embedded_offset = embed_offset;
00188     header->cg_to_anon_start = cg_to_anon_start;
00189 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1