From: Maynard J. <may...@us...> - 2008-08-28 21:57:37
|
Update of /cvsroot/oprofile/oprofile/libop In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv13690/libop Modified Files: op_cpu_type.c op_cpu_type.h op_events.c op_events.h Added Files: op_hw_specific.h Log Message: support for Intel arch perfmon --- NEW FILE: op_hw_specific.h --- /* * @file architecture specific interfaces * @remark Copyright 2008 Intel Corporation * @remark Read the file COPYING * @author Andi Kleen */ #if defined(__i386__) || defined(__x86_64__) /* Assume we run on the same host as the profilee */ #define num_to_mask(x) ((1U << (x)) - 1) static inline unsigned arch_get_filter(op_cpu cpu_type) { if (cpu_type == CPU_ARCH_PERFMON) { unsigned ebx, eax; asm("cpuid" : "=a" (eax), "=b" (ebx) : "0" (0xa) : "ecx","edx"); return ebx & num_to_mask(eax >> 24); } return 0; } static inline int arch_num_counters(op_cpu cpu_type) { if (cpu_type == CPU_ARCH_PERFMON) { unsigned v; asm("cpuid" : "=a" (v) : "0" (0xa) : "ebx","ecx","edx"); return (v >> 8) & 0xff; } return -1; } static inline unsigned arch_get_counter_mask(void) { unsigned v; asm("cpuid" : "=a" (v) : "0" (0xa) : "ebx","ecx","edx"); return num_to_mask((v >> 8) & 0xff); } #else static inline unsigned arch_get_filter(op_cpu cpu_type) { /* Do something with passed arg to shut up the compiler warning */ if (cpu_type != CPU_NO_GOOD) return 0; return 0; } static inline int arch_num_counters(op_cpu cpu_type) { /* Do something with passed arg to shut up the compiler warning */ if (cpu_type != CPU_NO_GOOD) return -1; return -1; } static inline unsigned arch_get_counter_mask(void) { return 0; } #endif Index: op_cpu_type.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/libop/op_cpu_type.c,v retrieving revision 1.48 retrieving revision 1.49 diff -u -p -d -r1.48 -r1.49 --- op_cpu_type.c 24 Jul 2008 22:17:15 -0000 1.48 +++ op_cpu_type.c 28 Aug 2008 21:57:46 -0000 1.49 @@ -14,6 +14,7 @@ #include <string.h> #include "op_cpu_type.h" +#include "op_hw_specific.h" struct cpu_descr { char const * pretty; @@ -75,6 +76,7 @@ static struct cpu_descr const cpu_descrs { "e300", "ppc/e300", CPU_PPC_E300, 4 }, { "AVR32", "avr32", CPU_AVR32, 3 }, { "ARM V7 PMNC", "arm/armv7", CPU_ARM_V7, 5 }, + { "Intel Architectural Perfmon", "i386/arch_perfmon", CPU_ARCH_PERFMON, 0}, }; static size_t const nr_cpu_descrs = sizeof(cpu_descrs) / sizeof(struct cpu_descr); @@ -152,8 +154,14 @@ char const * op_get_cpu_name(op_cpu cpu_ int op_get_nr_counters(op_cpu cpu_type) { + int cnt; + if (cpu_type <= CPU_NO_GOOD || cpu_type >= MAX_CPU_TYPE) return 0; + cnt = arch_num_counters(cpu_type); + if (cnt >= 0) + return cnt; + return cpu_descrs[cpu_type].nr_counters; } Index: op_cpu_type.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libop/op_cpu_type.h,v retrieving revision 1.41 retrieving revision 1.42 diff -u -p -d -r1.41 -r1.42 --- op_cpu_type.h 24 Jul 2008 22:17:15 -0000 1.41 +++ op_cpu_type.h 28 Aug 2008 21:57:46 -0000 1.42 @@ -73,6 +73,7 @@ typedef enum { CPU_PPC_E300, /**< e300 */ CPU_AVR32, /**< AVR32 */ CPU_ARM_V7, /**< ARM V7 */ + CPU_ARCH_PERFMON, /**< Intel architectural perfmon */ MAX_CPU_TYPE } op_cpu; Index: op_events.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/libop/op_events.c,v retrieving revision 1.87 retrieving revision 1.88 diff -u -p -d -r1.87 -r1.88 --- op_events.c 24 Jul 2008 22:17:15 -0000 1.87 +++ op_events.c 28 Aug 2008 21:57:46 -0000 1.88 @@ -16,6 +16,7 @@ #include "op_fileio.h" #include "op_string.h" #include "op_cpufreq.h" +#include "op_hw_specific.h" #include <string.h> #include <stdlib.h> @@ -27,6 +28,8 @@ static LIST_HEAD(um_list); static char const * filename; static unsigned int line_nr; +static void delete_event(struct op_event * event); + static void parse_error(char const * context) { fprintf(stderr, "oprofile: parse error in %s, line %u\n", @@ -329,7 +332,8 @@ static void read_events(char const * fil seen_um = 0; seen_minimum = 0; event = new_event(); - + event->filter = -1; + c = line; while (next_token(&c, &name, &value)) { if (strcmp(name, "name") == 0) { @@ -351,7 +355,10 @@ static void read_events(char const * fil if (seen_counters) parse_error("duplicate counters: tag"); seen_counters = 1; - event->counter_mask = parse_counter_mask(value); + if (!strcmp(value, "cpuid")) + event->counter_mask = arch_get_counter_mask(); + else + event->counter_mask = parse_counter_mask(value); free(value); } else if (strcmp(name, "um") == 0) { if (seen_um) @@ -368,6 +375,9 @@ static void read_events(char const * fil free(value); } else if (strcmp(name, "desc") == 0) { event->desc = value; + } else if (strcmp(name, "filter") == 0) { + event->filter = parse_int(value); + free(value); } else { parse_error("unknown tag"); } @@ -423,6 +433,18 @@ static void check_unit_mask(struct op_un } } +static void arch_filter_events(op_cpu cpu_type) +{ + struct list_head * pos, * pos2; + unsigned filter = arch_get_filter(cpu_type); + if (!filter) + return; + list_for_each_safe (pos, pos2, &events_list) { + struct op_event * event = list_entry(pos, struct op_event, event_next); + if (event->filter >= 0 && ((1U << event->filter) & filter)) + delete_event(event); + } +} static void load_events(op_cpu cpu_type) { @@ -459,6 +481,8 @@ static void load_events(op_cpu cpu_type) read_unit_masks(um_file); read_events(event_file); + arch_filter_events(cpu_type); + /* sanity check: all unit mask must be used */ list_for_each(pos, &um_list) { struct op_unit_mask * um = list_entry(pos, struct op_unit_mask, um_next); @@ -471,10 +495,10 @@ static void load_events(op_cpu cpu_type) free(event_dir); } - struct list_head * op_events(op_cpu cpu_type) { load_events(cpu_type); + arch_filter_events(cpu_type); return &events_list; } @@ -522,20 +546,24 @@ void op_free_events(void) } -static struct op_event * find_event(u32 nr) +static struct op_event * find_event_um(u32 nr, u32 um) { struct list_head * pos; + unsigned int i; list_for_each(pos, &events_list) { struct op_event * event = list_entry(pos, struct op_event, event_next); - if (event->val == nr) - return event; + if (event->val == nr) { + for (i = 0; i < event->unit->num; i++) { + if (event->unit->um[i].value == um) + return event; + } + } } return NULL; } - static FILE * open_event_mapping_file(char const * cpu_name) { char * ev_map_file; @@ -687,13 +715,13 @@ struct op_event * find_event_by_name(cha } -struct op_event * op_find_event(op_cpu cpu_type, u32 nr) +struct op_event * op_find_event(op_cpu cpu_type, u32 nr, u32 um) { struct op_event * event; load_events(cpu_type); - event = find_event(nr); + event = find_event_um(nr, um); return event; } @@ -701,38 +729,43 @@ struct op_event * op_find_event(op_cpu c int op_check_events(int ctr, u32 nr, u32 um, op_cpu cpu_type) { - int ret = OP_OK_EVENT; - struct op_event * event; + int ret = OP_INVALID_EVENT; size_t i; u32 ctr_mask = 1 << ctr; + struct list_head * pos; load_events(cpu_type); - event = find_event(nr); + list_for_each(pos, &events_list) { + struct op_event * event = list_entry(pos, struct op_event, event_next); + if (event->val != nr) + continue; - if (!event) { - ret |= OP_INVALID_EVENT; - return ret; - } + ret = OP_OK_EVENT; - if ((event->counter_mask & ctr_mask) == 0) - ret |= OP_INVALID_COUNTER; + if ((event->counter_mask & ctr_mask) == 0) + ret |= OP_INVALID_COUNTER; - if (event->unit->unit_type_mask == utm_bitmask) { - for (i = 0; i < event->unit->num; ++i) - um &= ~(event->unit->um[i].value); - - if (um) - ret |= OP_INVALID_UM; + if (event->unit->unit_type_mask == utm_bitmask) { + for (i = 0; i < event->unit->num; ++i) + um &= ~(event->unit->um[i].value); + + if (um) + ret |= OP_INVALID_UM; + + } else { + for (i = 0; i < event->unit->num; ++i) { + if (event->unit->um[i].value == um) + break; + } + + if (i == event->unit->num) + ret |= OP_INVALID_UM; - } else { - for (i = 0; i < event->unit->num; ++i) { - if (event->unit->um[i].value == um) - break; } - if (i == event->unit->num) - ret |= OP_INVALID_UM; + if (ret == OP_OK_EVENT) + return ret; } return ret; @@ -759,6 +792,7 @@ void op_default_event(op_cpu cpu_type, s case CPU_ATHLON: case CPU_HAMMER: case CPU_FAMILY10: + case CPU_ARCH_PERFMON: descr->name = "CPU_CLK_UNHALTED"; break; Index: op_events.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libop/op_events.h,v retrieving revision 1.27 retrieving revision 1.28 diff -u -p -d -r1.27 -r1.28 --- op_events.h 27 Aug 2006 00:10:12 -0000 1.27 +++ op_events.h 28 Aug 2008 21:57:46 -0000 1.28 @@ -56,6 +56,7 @@ struct op_event { char * name; /**< the event name */ char * desc; /**< the event description */ int min_count; /**< minimum counter value allowed */ + int filter; /**< architecture specific filter or -1 */ struct list_head event_next; /**< next event in list */ }; @@ -63,7 +64,7 @@ struct op_event { struct list_head * op_events(op_cpu cpu_type); /** Find a given event, returns NULL on error */ -struct op_event * op_find_event(op_cpu cpu_type, u32 nr); +struct op_event * op_find_event(op_cpu cpu_type, u32 nr, u32 um); /** Find a given event by name */ struct op_event * find_event_by_name(char const * name); |