Loading arch/x86/kernel/ds.c +80 −62 Original line number Diff line number Diff line Loading @@ -19,44 +19,53 @@ * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009 */ #include <asm/ds.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/kernel.h> #include <asm/ds.h> #include "ds_selftest.h" /* * The configuration for a particular DS hardware implementation. * The configuration for a particular DS hardware implementation: */ struct ds_configuration { /* The name of the configuration. */ /* The name of the configuration: */ const char *name; /* The size of pointer-typed fields in DS, BTS, and PEBS. */ /* The size of pointer-typed fields in DS, BTS, and PEBS: */ unsigned char sizeof_ptr_field; /* The size of a BTS/PEBS record in bytes. */ /* The size of a BTS/PEBS record in bytes: */ unsigned char sizeof_rec[2]; /* Control bit-masks indexed by enum ds_feature. */ /* Control bit-masks indexed by enum ds_feature: */ unsigned long ctl[dsf_ctl_max]; }; static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array); #define ds_cfg per_cpu(ds_cfg_array, smp_processor_id()) #define MAX_SIZEOF_DS (12 * 8) /* Maximal size of a DS configuration. */ #define MAX_SIZEOF_BTS (3 * 8) /* Maximal size of a BTS record. */ #define DS_ALIGNMENT (1 << 3) /* BTS and PEBS buffer alignment. */ /* Maximal size of a DS configuration: */ #define MAX_SIZEOF_DS (12 * 8) /* Maximal size of a BTS record: */ #define MAX_SIZEOF_BTS (3 * 8) /* BTS and PEBS buffer alignment: */ #define DS_ALIGNMENT (1 << 3) /* Mask of control bits in the DS MSR register: */ #define BTS_CONTROL \ (ds_cfg.ctl[dsf_bts] | ds_cfg.ctl[dsf_bts_kernel] | ds_cfg.ctl[dsf_bts_user] |\ ( ds_cfg.ctl[dsf_bts] | \ ds_cfg.ctl[dsf_bts_kernel] | \ ds_cfg.ctl[dsf_bts_user] | \ ds_cfg.ctl[dsf_bts_overflow] ) /* * A BTS or PEBS tracer. * Loading @@ -72,20 +81,24 @@ struct ds_tracer { }; struct bts_tracer { /* The common DS part. */ /* The common DS part: */ struct ds_tracer ds; /* The trace including the DS configuration. */ /* The trace including the DS configuration: */ struct bts_trace trace; /* Buffer overflow notification function. */ /* Buffer overflow notification function: */ bts_ovfl_callback_t ovfl; }; struct pebs_tracer { /* The common DS part. */ /* The common DS part: */ struct ds_tracer ds; /* The trace including the DS configuration. */ /* The trace including the DS configuration: */ struct pebs_trace trace; /* Buffer overflow notification function. */ /* Buffer overflow notification function: */ pebs_ovfl_callback_t ovfl; }; Loading @@ -95,6 +108,7 @@ struct pebs_tracer { * * The DS configuration consists of the following fields; different * architetures vary in the size of those fields. * * - double-word aligned base linear address of the BTS buffer * - write pointer into the BTS buffer * - end linear address of the BTS buffer (one byte beyond the end of Loading Loading @@ -137,15 +151,16 @@ enum ds_qualifier { ds_pebs }; static inline unsigned long ds_get(const unsigned char *base, enum ds_qualifier qual, enum ds_field field) static inline unsigned long ds_get(const unsigned char *base, enum ds_qualifier qual, enum ds_field field) { base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); return *(unsigned long *)base; } static inline void ds_set(unsigned char *base, enum ds_qualifier qual, enum ds_field field, unsigned long value) static inline void ds_set(unsigned char *base, enum ds_qualifier qual, enum ds_field field, unsigned long value) { base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); (*(unsigned long *)base) = value; Loading @@ -157,7 +172,6 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual, */ static DEFINE_SPINLOCK(ds_lock); /* * We either support (system-wide) per-cpu or per-thread allocation. * We distinguish the two based on the task_struct pointer, where a Loading Loading @@ -211,16 +225,20 @@ static inline int check_tracer(struct task_struct *task) * deallocated when the last user puts the context. */ struct ds_context { /* The DS configuration; goes into MSR_IA32_DS_AREA. */ /* The DS configuration; goes into MSR_IA32_DS_AREA: */ unsigned char ds[MAX_SIZEOF_DS]; /* The owner of the BTS and PEBS configuration, respectively. */ /* The owner of the BTS and PEBS configuration, respectively: */ struct bts_tracer *bts_master; struct pebs_tracer *pebs_master; /* Use count. */ /* Use count: */ unsigned long count; /* Pointer to the context pointer field. */ /* Pointer to the context pointer field: */ struct ds_context **this; /* The traced task; NULL for current cpu. */ /* The traced task; NULL for current cpu: */ struct task_struct *task; }; Loading Loading @@ -461,8 +479,8 @@ static inline void bts_set(char *base, enum bts_field field, unsigned long val) * * return: bytes read/written on success; -Eerrno, otherwise */ static int bts_read(struct bts_tracer *tracer, const void *at, struct bts_struct *out) static int bts_read(struct bts_tracer *tracer, const void *at, struct bts_struct *out) { if (!tracer) return -EINVAL; Loading arch/x86/kernel/ds_selftest.h +1 −1 Original line number Diff line number Diff line Loading @@ -12,4 +12,4 @@ extern int ds_selftest_pebs(void); #else static inline int ds_selftest_bts(void) { return 0; } static inline int ds_selftest_pebs(void) { return 0; } #endif /* CONFIG_X86_DS_SELFTEST */ #endif kernel/trace/trace_hw_branches.c +3 −3 Original line number Diff line number Diff line /* * h/w branch tracer for x86 based on bts * h/w branch tracer for x86 based on BTS * * Copyright (C) 2008-2009 Intel Corporation. * Markus Metzger <markus.t.metzger@gmail.com>, 2008-2009 Loading @@ -15,8 +15,8 @@ #include <asm/ds.h> #include "trace.h" #include "trace_output.h" #include "trace.h" #define BTS_BUFFER_SIZE (1 << 13) Loading Loading @@ -197,10 +197,10 @@ static void bts_trace_print_header(struct seq_file *m) static enum print_line_t bts_trace_print_line(struct trace_iterator *iter) { unsigned long symflags = TRACE_ITER_SYM_OFFSET; struct trace_entry *entry = iter->ent; struct trace_seq *seq = &iter->seq; struct hw_branch_entry *it; unsigned long symflags = TRACE_ITER_SYM_OFFSET; trace_assign_type(it, entry); Loading kernel/trace/trace_selftest.c +3 −2 Original line number Diff line number Diff line Loading @@ -189,6 +189,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, #else # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; }) #endif /* CONFIG_DYNAMIC_FTRACE */ /* * Simple verification test of ftrace function tracer. * Enable ftrace, sleep 1/10 second, and then read the trace Loading Loading @@ -698,10 +699,10 @@ int trace_selftest_startup_hw_branches(struct tracer *trace, struct trace_array *tr) { unsigned long count; int ret; struct trace_iterator iter; struct tracer tracer; unsigned long count; int ret; if (!trace->open) { printk(KERN_CONT "missing open function..."); Loading Loading
arch/x86/kernel/ds.c +80 −62 Original line number Diff line number Diff line Loading @@ -19,44 +19,53 @@ * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009 */ #include <asm/ds.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/kernel.h> #include <asm/ds.h> #include "ds_selftest.h" /* * The configuration for a particular DS hardware implementation. * The configuration for a particular DS hardware implementation: */ struct ds_configuration { /* The name of the configuration. */ /* The name of the configuration: */ const char *name; /* The size of pointer-typed fields in DS, BTS, and PEBS. */ /* The size of pointer-typed fields in DS, BTS, and PEBS: */ unsigned char sizeof_ptr_field; /* The size of a BTS/PEBS record in bytes. */ /* The size of a BTS/PEBS record in bytes: */ unsigned char sizeof_rec[2]; /* Control bit-masks indexed by enum ds_feature. */ /* Control bit-masks indexed by enum ds_feature: */ unsigned long ctl[dsf_ctl_max]; }; static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array); #define ds_cfg per_cpu(ds_cfg_array, smp_processor_id()) #define MAX_SIZEOF_DS (12 * 8) /* Maximal size of a DS configuration. */ #define MAX_SIZEOF_BTS (3 * 8) /* Maximal size of a BTS record. */ #define DS_ALIGNMENT (1 << 3) /* BTS and PEBS buffer alignment. */ /* Maximal size of a DS configuration: */ #define MAX_SIZEOF_DS (12 * 8) /* Maximal size of a BTS record: */ #define MAX_SIZEOF_BTS (3 * 8) /* BTS and PEBS buffer alignment: */ #define DS_ALIGNMENT (1 << 3) /* Mask of control bits in the DS MSR register: */ #define BTS_CONTROL \ (ds_cfg.ctl[dsf_bts] | ds_cfg.ctl[dsf_bts_kernel] | ds_cfg.ctl[dsf_bts_user] |\ ( ds_cfg.ctl[dsf_bts] | \ ds_cfg.ctl[dsf_bts_kernel] | \ ds_cfg.ctl[dsf_bts_user] | \ ds_cfg.ctl[dsf_bts_overflow] ) /* * A BTS or PEBS tracer. * Loading @@ -72,20 +81,24 @@ struct ds_tracer { }; struct bts_tracer { /* The common DS part. */ /* The common DS part: */ struct ds_tracer ds; /* The trace including the DS configuration. */ /* The trace including the DS configuration: */ struct bts_trace trace; /* Buffer overflow notification function. */ /* Buffer overflow notification function: */ bts_ovfl_callback_t ovfl; }; struct pebs_tracer { /* The common DS part. */ /* The common DS part: */ struct ds_tracer ds; /* The trace including the DS configuration. */ /* The trace including the DS configuration: */ struct pebs_trace trace; /* Buffer overflow notification function. */ /* Buffer overflow notification function: */ pebs_ovfl_callback_t ovfl; }; Loading @@ -95,6 +108,7 @@ struct pebs_tracer { * * The DS configuration consists of the following fields; different * architetures vary in the size of those fields. * * - double-word aligned base linear address of the BTS buffer * - write pointer into the BTS buffer * - end linear address of the BTS buffer (one byte beyond the end of Loading Loading @@ -137,15 +151,16 @@ enum ds_qualifier { ds_pebs }; static inline unsigned long ds_get(const unsigned char *base, enum ds_qualifier qual, enum ds_field field) static inline unsigned long ds_get(const unsigned char *base, enum ds_qualifier qual, enum ds_field field) { base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); return *(unsigned long *)base; } static inline void ds_set(unsigned char *base, enum ds_qualifier qual, enum ds_field field, unsigned long value) static inline void ds_set(unsigned char *base, enum ds_qualifier qual, enum ds_field field, unsigned long value) { base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); (*(unsigned long *)base) = value; Loading @@ -157,7 +172,6 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual, */ static DEFINE_SPINLOCK(ds_lock); /* * We either support (system-wide) per-cpu or per-thread allocation. * We distinguish the two based on the task_struct pointer, where a Loading Loading @@ -211,16 +225,20 @@ static inline int check_tracer(struct task_struct *task) * deallocated when the last user puts the context. */ struct ds_context { /* The DS configuration; goes into MSR_IA32_DS_AREA. */ /* The DS configuration; goes into MSR_IA32_DS_AREA: */ unsigned char ds[MAX_SIZEOF_DS]; /* The owner of the BTS and PEBS configuration, respectively. */ /* The owner of the BTS and PEBS configuration, respectively: */ struct bts_tracer *bts_master; struct pebs_tracer *pebs_master; /* Use count. */ /* Use count: */ unsigned long count; /* Pointer to the context pointer field. */ /* Pointer to the context pointer field: */ struct ds_context **this; /* The traced task; NULL for current cpu. */ /* The traced task; NULL for current cpu: */ struct task_struct *task; }; Loading Loading @@ -461,8 +479,8 @@ static inline void bts_set(char *base, enum bts_field field, unsigned long val) * * return: bytes read/written on success; -Eerrno, otherwise */ static int bts_read(struct bts_tracer *tracer, const void *at, struct bts_struct *out) static int bts_read(struct bts_tracer *tracer, const void *at, struct bts_struct *out) { if (!tracer) return -EINVAL; Loading
arch/x86/kernel/ds_selftest.h +1 −1 Original line number Diff line number Diff line Loading @@ -12,4 +12,4 @@ extern int ds_selftest_pebs(void); #else static inline int ds_selftest_bts(void) { return 0; } static inline int ds_selftest_pebs(void) { return 0; } #endif /* CONFIG_X86_DS_SELFTEST */ #endif
kernel/trace/trace_hw_branches.c +3 −3 Original line number Diff line number Diff line /* * h/w branch tracer for x86 based on bts * h/w branch tracer for x86 based on BTS * * Copyright (C) 2008-2009 Intel Corporation. * Markus Metzger <markus.t.metzger@gmail.com>, 2008-2009 Loading @@ -15,8 +15,8 @@ #include <asm/ds.h> #include "trace.h" #include "trace_output.h" #include "trace.h" #define BTS_BUFFER_SIZE (1 << 13) Loading Loading @@ -197,10 +197,10 @@ static void bts_trace_print_header(struct seq_file *m) static enum print_line_t bts_trace_print_line(struct trace_iterator *iter) { unsigned long symflags = TRACE_ITER_SYM_OFFSET; struct trace_entry *entry = iter->ent; struct trace_seq *seq = &iter->seq; struct hw_branch_entry *it; unsigned long symflags = TRACE_ITER_SYM_OFFSET; trace_assign_type(it, entry); Loading
kernel/trace/trace_selftest.c +3 −2 Original line number Diff line number Diff line Loading @@ -189,6 +189,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, #else # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; }) #endif /* CONFIG_DYNAMIC_FTRACE */ /* * Simple verification test of ftrace function tracer. * Enable ftrace, sleep 1/10 second, and then read the trace Loading Loading @@ -698,10 +699,10 @@ int trace_selftest_startup_hw_branches(struct tracer *trace, struct trace_array *tr) { unsigned long count; int ret; struct trace_iterator iter; struct tracer tracer; unsigned long count; int ret; if (!trace->open) { printk(KERN_CONT "missing open function..."); Loading