op_alloc_counter.c

Go to the documentation of this file.
00001 
00014 #include <stdlib.h>
00015 #include <ctype.h>
00016 #include <dirent.h>
00017 
00018 #include "op_events.h"
00019 #include "op_libiberty.h"
00020 
00021 
00022 typedef struct counter_arc_head {
00024     struct list_head next;
00025 } counter_arc_head;
00026 
00027 
00028 typedef struct counter_arc {
00030     int counter;
00032     struct list_head next;
00033 } counter_arc;
00034 
00035 
00044 static counter_arc_head *
00045 build_counter_arc(struct op_event const * pev[], int nr_events)
00046 {
00047     counter_arc_head * ctr_arc;
00048     int i;
00049 
00050     ctr_arc = xmalloc(nr_events * sizeof(*ctr_arc));
00051 
00052     for (i = 0; i < nr_events; ++i) {
00053         int j;
00054         u32 mask = pev[i]->counter_mask;
00055 
00056         list_init(&ctr_arc[i].next);
00057         for (j = 0; mask; ++j) {
00058             if (mask & (1 << j)) {
00059                 counter_arc * arc = 
00060                     xmalloc(sizeof(counter_arc));
00061                 arc->counter = j;
00062                 /* we are looping by increasing counter number,
00063                  * allocation use a left to right tree walking
00064                  * so we add at end to ensure counter will
00065                  * be allocated by increasing number: it's not
00066                  * required but a bit less surprising when
00067                  * debugging code
00068                  */
00069                 list_add_tail(&arc->next, &ctr_arc[i].next);
00070                 mask &= ~(1 << j);
00071             }
00072         }
00073     }
00074 
00075     return ctr_arc;
00076 }
00077 
00078 
00085 static void delete_counter_arc(counter_arc_head * ctr_arc, int nr_events)
00086 {
00087     int i;
00088     for (i = 0; i < nr_events; ++i) {
00089         struct list_head * pos, * pos2;
00090         list_for_each_safe(pos, pos2, &ctr_arc[i].next) {
00091             counter_arc * arc = list_entry(pos, counter_arc, next);
00092             list_del(&arc->next);
00093             free(arc);
00094         }
00095     }
00096     free(ctr_arc);
00097 }
00098 
00099 
00125 static int
00126 allocate_counter(counter_arc_head const * ctr_arc, int max_depth, int depth,
00127          u32 allocated_mask, size_t * counter_map)
00128 {
00129     struct list_head * pos;
00130 
00131     if (depth == max_depth)
00132         return 1;
00133 
00134     /* If ctr_arc is not available, counter_map is -1 */
00135     if((&ctr_arc[depth].next)->next == &ctr_arc[depth].next) {
00136         counter_map[depth] = -1;
00137         if (allocate_counter(ctr_arc, max_depth, depth + 1,
00138                              allocated_mask,
00139                              counter_map))
00140             return 1;
00141     } else {
00142         list_for_each(pos, &ctr_arc[depth].next) {
00143             counter_arc const * arc = list_entry(pos, counter_arc, next);
00144 
00145             if (allocated_mask & (1 << arc->counter))
00146                 continue;
00147 
00148             counter_map[depth] = arc->counter;
00149 
00150             if (allocate_counter(ctr_arc, max_depth, depth + 1,
00151                          allocated_mask | (1 << arc->counter),
00152                          counter_map))
00153                 return 1;
00154         }
00155     }
00156 
00157     return 0;
00158 }
00159 
00160 /* determine which directories are counter directories
00161  */
00162 static int perfcounterdir(const struct dirent * entry)
00163 {
00164     return (isdigit(entry->d_name[0]));
00165 }
00166 
00167 
00175 static int op_get_counter_mask(u32 * mask)
00176 {
00177     struct dirent **counterlist;
00178     int count, i;
00179     /* assume nothing is available */
00180     u32 available=0;
00181 
00182     count = scandir("/dev/oprofile", &counterlist, perfcounterdir,
00183             alphasort);
00184     if (count < 0)
00185         /* unable to determine bit mask */
00186         return -1;
00187     /* convert to bit map (0 where counter exists) */
00188     for (i=0; i<count; ++i) {
00189         available |= 1 << atoi(counterlist[i]->d_name);
00190         free(counterlist[i]);
00191     }
00192     /* Append the timer counter to the mask of hardware counters.  */
00193     if (op_cpu_has_timer_fs()) {
00194         available |= 1 << (op_get_nr_counters(op_get_cpu_type()) - 1);
00195         count++;
00196     }
00197     *mask=~available;
00198     free(counterlist);
00199     return count;
00200 }
00201 
00202 size_t * map_event_to_counter(struct op_event const * pev[], int nr_events,
00203                               op_cpu cpu_type)
00204 {
00205     counter_arc_head * ctr_arc;
00206     size_t * counter_map;
00207     int i, nr_counters, nr_pmc_events;
00208     op_cpu curr_cpu_type;
00209     u32 unavailable_counters = 0;
00210 
00211     /* Either ophelp or one of the libop tests may invoke this
00212      * function with a non-native cpu_type.  If so, we should not
00213      * call op_get_counter_mask because that will look for real counter
00214      * information in oprofilefs.
00215      */
00216     curr_cpu_type = op_get_cpu_type();
00217     if (cpu_type != curr_cpu_type)
00218         nr_counters = op_get_nr_counters(cpu_type);
00219     else
00220         nr_counters = op_get_counter_mask(&unavailable_counters);
00221 
00222     /* no counters then probably perfmon managing perfmon hw */
00223     if (nr_counters <= 0) {
00224         nr_counters = op_get_nr_counters(cpu_type);
00225         unavailable_counters = (~0) << nr_counters;
00226     }
00227 
00228     /* Check to see if we have enough physical counters to map events*/
00229     for (i = 0, nr_pmc_events = 0; i < nr_events; i++)
00230         if(pev[i]->ext == NULL)
00231             if (++nr_pmc_events > nr_counters)
00232                 return 0;
00233 
00234     ctr_arc = build_counter_arc(pev, nr_events);
00235 
00236     counter_map = xmalloc(nr_events * sizeof(size_t));
00237 
00238     if (!allocate_counter(ctr_arc, nr_events, 0, unavailable_counters,
00239                   counter_map)) {
00240         free(counter_map);
00241         counter_map = 0;
00242     }
00243 
00244     delete_counter_arc(ctr_arc, nr_events);
00245     return counter_map;
00246 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1