@@ -70,3 +70,23 @@ void btrfs_perf_end(struct btrfs_fs_info *fs_info, u64 eb_owner, u64 start_ns)
i = BTRFS_PERF_TREE_LOCK_OTHER;
percpu_counter_add(&profiler->perf_counters[i], end_ns - start_ns);
}
+
+void btrfs_perf_report(struct btrfs_fs_info *fs_info,
+ struct btrfs_perf_result *result)
+{
+ struct btrfs_perf_profiler *profiler = fs_info->profiler;
+ u64 end_ns = ktime_get_ns();
+ int i;
+
+ if (!profiler || !result)
+ return;
+
+ for (i = 0; i < BTRFS_PERF_LAST; i++) {
+ result->results_ns[i] =
+ percpu_counter_sum(&profiler->perf_counters[i]);
+ percpu_counter_set(&profiler->perf_counters[i], 0);
+ }
+ result->current_ns = end_ns;
+ result->duration_ns = end_ns - profiler->last_sample;
+ profiler->last_sample = end_ns;
+}
@@ -22,6 +22,12 @@ struct btrfs_perf_profiler {
struct percpu_counter perf_counters[BTRFS_PERF_LAST];
};
+struct btrfs_perf_result {
+ u64 current_ns;
+ u64 duration_ns;
+ u64 results_ns[BTRFS_PERF_LAST];
+};
+
struct btrfs_perf_profiler *btrfs_perf_alloc_profiler(void);
void btrfs_perf_free_profiler(struct btrfs_fs_info *fs_info);
void btrfs_perf_update_lock(struct btrfs_fs_info *fs_info,
@@ -32,4 +38,7 @@ static inline u64 btrfs_perf_start(void)
}
void btrfs_perf_end(struct btrfs_fs_info *fs_info, u64 eb_owner, u64 start_ns);
+
+void btrfs_perf_report(struct btrfs_fs_info *fs_info,
+ struct btrfs_perf_result *result);
#endif
@@ -16,6 +16,7 @@
#include "transaction.h"
#include "sysfs.h"
#include "volumes.h"
+#include "perf.h"
static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj);
@@ -456,6 +457,43 @@ static ssize_t btrfs_sectorsize_show(struct kobject *kobj,
BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show);
+#define print_one_result(name) \
+({ \
+ tmp = result.results_ns[BTRFS_PERF_##name]; \
+ size += snprintf(buf + size, PAGE_SIZE - size, \
+ "%s = %lluns (%llu.%02llu%%)\n", \
+ #name, tmp, tmp * 100 / duration, \
+ (tmp * 10000 / duration) % 100); \
+})
+
+static ssize_t btrfs_profiler_show(struct kobject *kobj,
+ struct kobj_attribute *a, char *buf)
+{
+ struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+ struct btrfs_perf_result result = { 0 };
+ u64 tmp;
+ u64 duration;
+ ssize_t size = 0;
+
+ btrfs_perf_report(fs_info, &result);
+ if (result.duration_ns == 0)
+ return snprintf(buf, PAGE_SIZE, "profiler not running\n");
+
+ duration = result.duration_ns;
+ size += snprintf(buf + size, PAGE_SIZE - size, "timestamp = %lluns\n",
+ result.current_ns);
+ size += snprintf(buf + size, PAGE_SIZE - size, "duration = %lluns\n",
+ duration);
+ print_one_result(TREE_LOCK_FS);
+ print_one_result(TREE_LOCK_EXTENT);
+ print_one_result(TREE_LOCK_ROOT);
+ print_one_result(TREE_LOCK_OTHER);
+ return size;
+}
+#undef print_one_result
+
+BTRFS_ATTR(, profiler, btrfs_profiler_show);
+
static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
struct kobj_attribute *a, char *buf)
{
@@ -525,6 +563,7 @@ static const struct attribute *btrfs_attrs[] = {
BTRFS_ATTR_PTR(, clone_alignment),
BTRFS_ATTR_PTR(, quota_override),
BTRFS_ATTR_PTR(, metadata_uuid),
+ BTRFS_ATTR_PTR(, profiler),
NULL,
};
This patch adds a new sys fs interface, 'profiler', for user to get real time performance data. The content of /sys/fs/btrfs/<FDID>/profiler is generated at the time of read, so user could have full control of the duration resolution. The output example would be: timestamp = 16364075995092ns duration = 1025342515ns TREE_LOCK_FS = 417160165ns (40.68%) TREE_LOCK_EXTENT = 45087670ns (4.39%) TREE_LOCK_ROOT = 1555506ns (0.15%) TREE_LOCK_OTHER = 20387436ns (1.98%) The 'timestamp' content is directly from ktime_get_ns(), which starts from kernel boot, and doesn't count hibernation/suspension. The 'duration' content is the time difference between last sample, in nanoseconds. Doesn't count hibernation or suspension either. The 'TREE_LOCK_*' content is the time spent on sleepable tree lock. The percentage in the round brackets is the sleep time compared to duration, which can be larger than 100%. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/perf.c | 20 ++++++++++++++++++++ fs/btrfs/perf.h | 9 +++++++++ fs/btrfs/sysfs.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+)