diff options
Diffstat (limited to 'drivers/oprofile')
| -rw-r--r-- | drivers/oprofile/buffer_sync.c | 3 | ||||
| -rw-r--r-- | drivers/oprofile/cpu_buffer.c | 16 | ||||
| -rw-r--r-- | drivers/oprofile/oprof.c | 71 | ||||
| -rw-r--r-- | drivers/oprofile/oprof.h | 3 | ||||
| -rw-r--r-- | drivers/oprofile/oprofile_files.c | 46 | ||||
| -rw-r--r-- | drivers/oprofile/oprofile_stats.c | 5 | ||||
| -rw-r--r-- | drivers/oprofile/oprofile_stats.h | 1 | ||||
| -rw-r--r-- | drivers/oprofile/oprofilefs.c | 2 |
8 files changed, 142 insertions, 5 deletions
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 8574622e36a5..c9e2ae90f195 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c | |||
| @@ -154,9 +154,8 @@ int sync_start(void) | |||
| 154 | { | 154 | { |
| 155 | int err; | 155 | int err; |
| 156 | 156 | ||
| 157 | if (!alloc_cpumask_var(&marked_cpus, GFP_KERNEL)) | 157 | if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL)) |
| 158 | return -ENOMEM; | 158 | return -ENOMEM; |
| 159 | cpumask_clear(marked_cpus); | ||
| 160 | 159 | ||
| 161 | start_cpu_work(); | 160 | start_cpu_work(); |
| 162 | 161 | ||
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 242257b19441..a7aae24f2889 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 23 | #include <linux/oprofile.h> | 23 | #include <linux/oprofile.h> |
| 24 | #include <linux/vmalloc.h> | ||
| 25 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
| 26 | 25 | ||
| 27 | #include "event_buffer.h" | 26 | #include "event_buffer.h" |
| @@ -407,6 +406,21 @@ int oprofile_add_data(struct op_entry *entry, unsigned long val) | |||
| 407 | return op_cpu_buffer_add_data(entry, val); | 406 | return op_cpu_buffer_add_data(entry, val); |
| 408 | } | 407 | } |
| 409 | 408 | ||
| 409 | int oprofile_add_data64(struct op_entry *entry, u64 val) | ||
| 410 | { | ||
| 411 | if (!entry->event) | ||
| 412 | return 0; | ||
| 413 | if (op_cpu_buffer_get_size(entry) < 2) | ||
| 414 | /* | ||
| 415 | * the function returns 0 to indicate a too small | ||
| 416 | * buffer, even if there is some space left | ||
| 417 | */ | ||
| 418 | return 0; | ||
| 419 | if (!op_cpu_buffer_add_data(entry, (u32)val)) | ||
| 420 | return 0; | ||
| 421 | return op_cpu_buffer_add_data(entry, (u32)(val >> 32)); | ||
| 422 | } | ||
| 423 | |||
| 410 | int oprofile_write_commit(struct op_entry *entry) | 424 | int oprofile_write_commit(struct op_entry *entry) |
| 411 | { | 425 | { |
| 412 | if (!entry->event) | 426 | if (!entry->event) |
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 3cffce90f82a..dc8a0428260d 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/oprofile.h> | 13 | #include <linux/oprofile.h> |
| 14 | #include <linux/moduleparam.h> | 14 | #include <linux/moduleparam.h> |
| 15 | #include <linux/workqueue.h> | ||
| 16 | #include <linux/time.h> | ||
| 15 | #include <asm/mutex.h> | 17 | #include <asm/mutex.h> |
| 16 | 18 | ||
| 17 | #include "oprof.h" | 19 | #include "oprof.h" |
| @@ -87,6 +89,69 @@ out: | |||
| 87 | return err; | 89 | return err; |
| 88 | } | 90 | } |
| 89 | 91 | ||
| 92 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX | ||
| 93 | |||
| 94 | static void switch_worker(struct work_struct *work); | ||
| 95 | static DECLARE_DELAYED_WORK(switch_work, switch_worker); | ||
| 96 | |||
| 97 | static void start_switch_worker(void) | ||
| 98 | { | ||
| 99 | if (oprofile_ops.switch_events) | ||
| 100 | schedule_delayed_work(&switch_work, oprofile_time_slice); | ||
| 101 | } | ||
| 102 | |||
| 103 | static void stop_switch_worker(void) | ||
| 104 | { | ||
| 105 | cancel_delayed_work_sync(&switch_work); | ||
| 106 | } | ||
| 107 | |||
| 108 | static void switch_worker(struct work_struct *work) | ||
| 109 | { | ||
| 110 | if (oprofile_ops.switch_events()) | ||
| 111 | return; | ||
| 112 | |||
| 113 | atomic_inc(&oprofile_stats.multiplex_counter); | ||
| 114 | start_switch_worker(); | ||
| 115 | } | ||
| 116 | |||
| 117 | /* User inputs in ms, converts to jiffies */ | ||
| 118 | int oprofile_set_timeout(unsigned long val_msec) | ||
| 119 | { | ||
| 120 | int err = 0; | ||
| 121 | unsigned long time_slice; | ||
| 122 | |||
| 123 | mutex_lock(&start_mutex); | ||
| 124 | |||
| 125 | if (oprofile_started) { | ||
| 126 | err = -EBUSY; | ||
| 127 | goto out; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (!oprofile_ops.switch_events) { | ||
| 131 | err = -EINVAL; | ||
| 132 | goto out; | ||
| 133 | } | ||
| 134 | |||
| 135 | time_slice = msecs_to_jiffies(val_msec); | ||
| 136 | if (time_slice == MAX_JIFFY_OFFSET) { | ||
| 137 | err = -EINVAL; | ||
| 138 | goto out; | ||
| 139 | } | ||
| 140 | |||
| 141 | oprofile_time_slice = time_slice; | ||
| 142 | |||
| 143 | out: | ||
| 144 | mutex_unlock(&start_mutex); | ||
| 145 | return err; | ||
| 146 | |||
| 147 | } | ||
| 148 | |||
| 149 | #else | ||
| 150 | |||
| 151 | static inline void start_switch_worker(void) { } | ||
| 152 | static inline void stop_switch_worker(void) { } | ||
| 153 | |||
| 154 | #endif | ||
| 90 | 155 | ||
| 91 | /* Actually start profiling (echo 1>/dev/oprofile/enable) */ | 156 | /* Actually start profiling (echo 1>/dev/oprofile/enable) */ |
| 92 | int oprofile_start(void) | 157 | int oprofile_start(void) |
| @@ -108,6 +173,8 @@ int oprofile_start(void) | |||
| 108 | if ((err = oprofile_ops.start())) | 173 | if ((err = oprofile_ops.start())) |
| 109 | goto out; | 174 | goto out; |
| 110 | 175 | ||
| 176 | start_switch_worker(); | ||
| 177 | |||
| 111 | oprofile_started = 1; | 178 | oprofile_started = 1; |
| 112 | out: | 179 | out: |
| 113 | mutex_unlock(&start_mutex); | 180 | mutex_unlock(&start_mutex); |
| @@ -123,6 +190,9 @@ void oprofile_stop(void) | |||
| 123 | goto out; | 190 | goto out; |
| 124 | oprofile_ops.stop(); | 191 | oprofile_ops.stop(); |
| 125 | oprofile_started = 0; | 192 | oprofile_started = 0; |
| 193 | |||
| 194 | stop_switch_worker(); | ||
| 195 | |||
| 126 | /* wake up the daemon to read what remains */ | 196 | /* wake up the daemon to read what remains */ |
| 127 | wake_up_buffer_waiter(); | 197 | wake_up_buffer_waiter(); |
| 128 | out: | 198 | out: |
| @@ -155,7 +225,6 @@ post_sync: | |||
| 155 | mutex_unlock(&start_mutex); | 225 | mutex_unlock(&start_mutex); |
| 156 | } | 226 | } |
| 157 | 227 | ||
| 158 | |||
| 159 | int oprofile_set_backtrace(unsigned long val) | 228 | int oprofile_set_backtrace(unsigned long val) |
| 160 | { | 229 | { |
| 161 | int err = 0; | 230 | int err = 0; |
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index c288d3c24b50..cb92f5c98c1a 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h | |||
| @@ -24,6 +24,8 @@ struct oprofile_operations; | |||
| 24 | extern unsigned long oprofile_buffer_size; | 24 | extern unsigned long oprofile_buffer_size; |
| 25 | extern unsigned long oprofile_cpu_buffer_size; | 25 | extern unsigned long oprofile_cpu_buffer_size; |
| 26 | extern unsigned long oprofile_buffer_watershed; | 26 | extern unsigned long oprofile_buffer_watershed; |
| 27 | extern unsigned long oprofile_time_slice; | ||
| 28 | |||
| 27 | extern struct oprofile_operations oprofile_ops; | 29 | extern struct oprofile_operations oprofile_ops; |
| 28 | extern unsigned long oprofile_started; | 30 | extern unsigned long oprofile_started; |
| 29 | extern unsigned long oprofile_backtrace_depth; | 31 | extern unsigned long oprofile_backtrace_depth; |
| @@ -35,5 +37,6 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root); | |||
| 35 | void oprofile_timer_init(struct oprofile_operations *ops); | 37 | void oprofile_timer_init(struct oprofile_operations *ops); |
| 36 | 38 | ||
| 37 | int oprofile_set_backtrace(unsigned long depth); | 39 | int oprofile_set_backtrace(unsigned long depth); |
| 40 | int oprofile_set_timeout(unsigned long time); | ||
| 38 | 41 | ||
| 39 | #endif /* OPROF_H */ | 42 | #endif /* OPROF_H */ |
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 5d36ffc30dd5..bbd7516e0869 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
| 11 | #include <linux/oprofile.h> | 11 | #include <linux/oprofile.h> |
| 12 | #include <linux/jiffies.h> | ||
| 12 | 13 | ||
| 13 | #include "event_buffer.h" | 14 | #include "event_buffer.h" |
| 14 | #include "oprofile_stats.h" | 15 | #include "oprofile_stats.h" |
| @@ -17,10 +18,51 @@ | |||
| 17 | #define BUFFER_SIZE_DEFAULT 131072 | 18 | #define BUFFER_SIZE_DEFAULT 131072 |
| 18 | #define CPU_BUFFER_SIZE_DEFAULT 8192 | 19 | #define CPU_BUFFER_SIZE_DEFAULT 8192 |
| 19 | #define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ | 20 | #define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ |
| 21 | #define TIME_SLICE_DEFAULT 1 | ||
| 20 | 22 | ||
| 21 | unsigned long oprofile_buffer_size; | 23 | unsigned long oprofile_buffer_size; |
| 22 | unsigned long oprofile_cpu_buffer_size; | 24 | unsigned long oprofile_cpu_buffer_size; |
| 23 | unsigned long oprofile_buffer_watershed; | 25 | unsigned long oprofile_buffer_watershed; |
| 26 | unsigned long oprofile_time_slice; | ||
| 27 | |||
| 28 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX | ||
| 29 | |||
| 30 | static ssize_t timeout_read(struct file *file, char __user *buf, | ||
| 31 | size_t count, loff_t *offset) | ||
| 32 | { | ||
| 33 | return oprofilefs_ulong_to_user(jiffies_to_msecs(oprofile_time_slice), | ||
| 34 | buf, count, offset); | ||
| 35 | } | ||
| 36 | |||
| 37 | |||
| 38 | static ssize_t timeout_write(struct file *file, char const __user *buf, | ||
| 39 | size_t count, loff_t *offset) | ||
| 40 | { | ||
| 41 | unsigned long val; | ||
| 42 | int retval; | ||
| 43 | |||
| 44 | if (*offset) | ||
| 45 | return -EINVAL; | ||
| 46 | |||
| 47 | retval = oprofilefs_ulong_from_user(&val, buf, count); | ||
| 48 | if (retval) | ||
| 49 | return retval; | ||
| 50 | |||
| 51 | retval = oprofile_set_timeout(val); | ||
| 52 | |||
| 53 | if (retval) | ||
| 54 | return retval; | ||
| 55 | return count; | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 59 | static const struct file_operations timeout_fops = { | ||
| 60 | .read = timeout_read, | ||
| 61 | .write = timeout_write, | ||
| 62 | }; | ||
| 63 | |||
| 64 | #endif | ||
| 65 | |||
| 24 | 66 | ||
| 25 | static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) | 67 | static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) |
| 26 | { | 68 | { |
| @@ -129,6 +171,7 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root) | |||
| 129 | oprofile_buffer_size = BUFFER_SIZE_DEFAULT; | 171 | oprofile_buffer_size = BUFFER_SIZE_DEFAULT; |
| 130 | oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT; | 172 | oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT; |
| 131 | oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; | 173 | oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; |
| 174 | oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); | ||
| 132 | 175 | ||
| 133 | oprofilefs_create_file(sb, root, "enable", &enable_fops); | 176 | oprofilefs_create_file(sb, root, "enable", &enable_fops); |
| 134 | oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); | 177 | oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); |
| @@ -139,6 +182,9 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root) | |||
| 139 | oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); | 182 | oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); |
| 140 | oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); | 183 | oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); |
| 141 | oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); | 184 | oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); |
| 185 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX | ||
| 186 | oprofilefs_create_file(sb, root, "time_slice", &timeout_fops); | ||
| 187 | #endif | ||
| 142 | oprofile_create_stats_files(sb, root); | 188 | oprofile_create_stats_files(sb, root); |
| 143 | if (oprofile_ops.create_files) | 189 | if (oprofile_ops.create_files) |
| 144 | oprofile_ops.create_files(sb, root); | 190 | oprofile_ops.create_files(sb, root); |
diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 3c2270a8300c..61689e814d46 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c | |||
| @@ -34,6 +34,7 @@ void oprofile_reset_stats(void) | |||
| 34 | atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); | 34 | atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); |
| 35 | atomic_set(&oprofile_stats.event_lost_overflow, 0); | 35 | atomic_set(&oprofile_stats.event_lost_overflow, 0); |
| 36 | atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); | 36 | atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); |
| 37 | atomic_set(&oprofile_stats.multiplex_counter, 0); | ||
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | 40 | ||
| @@ -76,4 +77,8 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root) | |||
| 76 | &oprofile_stats.event_lost_overflow); | 77 | &oprofile_stats.event_lost_overflow); |
| 77 | oprofilefs_create_ro_atomic(sb, dir, "bt_lost_no_mapping", | 78 | oprofilefs_create_ro_atomic(sb, dir, "bt_lost_no_mapping", |
| 78 | &oprofile_stats.bt_lost_no_mapping); | 79 | &oprofile_stats.bt_lost_no_mapping); |
| 80 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX | ||
| 81 | oprofilefs_create_ro_atomic(sb, dir, "multiplex_counter", | ||
| 82 | &oprofile_stats.multiplex_counter); | ||
| 83 | #endif | ||
| 79 | } | 84 | } |
diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h index 3da0d08dc1f9..0b54e46c3c14 100644 --- a/drivers/oprofile/oprofile_stats.h +++ b/drivers/oprofile/oprofile_stats.h | |||
| @@ -17,6 +17,7 @@ struct oprofile_stat_struct { | |||
| 17 | atomic_t sample_lost_no_mapping; | 17 | atomic_t sample_lost_no_mapping; |
| 18 | atomic_t bt_lost_no_mapping; | 18 | atomic_t bt_lost_no_mapping; |
| 19 | atomic_t event_lost_overflow; | 19 | atomic_t event_lost_overflow; |
| 20 | atomic_t multiplex_counter; | ||
| 20 | }; | 21 | }; |
| 21 | 22 | ||
| 22 | extern struct oprofile_stat_struct oprofile_stats; | 23 | extern struct oprofile_stat_struct oprofile_stats; |
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index b7e4cee24269..2766a6d3c2e9 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c | |||
| @@ -35,7 +35,7 @@ static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode) | |||
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | 37 | ||
| 38 | static struct super_operations s_ops = { | 38 | static const struct super_operations s_ops = { |
| 39 | .statfs = simple_statfs, | 39 | .statfs = simple_statfs, |
| 40 | .drop_inode = generic_delete_inode, | 40 | .drop_inode = generic_delete_inode, |
| 41 | }; | 41 | }; |
