aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorFilipe David Borba Manana <fdmanana@gmail.com>2013-08-30 10:46:43 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 08:16:42 -0400
commitd7396f07358a7c6e22c238d36d1d85f9d652a414 (patch)
treedf344c7621c7df62d8adc4bb162d8b15d6cb845a /fs/btrfs/ctree.c
parent45d5fd14d22304c9a40d5aae75ec610f5d1cbb53 (diff)
Btrfs: optimize key searches in btrfs_search_slot
When the binary search returns 0 (exact match), the target key will necessarily be at slot 0 of all nodes below the current one, so in this case the binary search is not needed because it will always return 0, and we waste time doing it, holding node locks for longer than necessary, etc. Below follow histograms with the times spent on the current approach of doing a binary search when the previous binary search returned 0, and times for the new approach, which directly picks the first item/child node in the leaf/node. Current approach: Count: 6682 Range: 35.000 - 8370.000; Mean: 85.837; Median: 75.000; Stddev: 106.429 Percentiles: 90th: 124.000; 95th: 145.000; 99th: 206.000 35.000 - 61.080: 1235 ################ 61.080 - 106.053: 4207 ##################################################### 106.053 - 183.606: 1122 ############## 183.606 - 317.341: 111 # 317.341 - 547.959: 6 | 547.959 - 8370.000: 1 | Approach proposed by this patch: Count: 6682 Range: 6.000 - 135.000; Mean: 16.690; Median: 16.000; Stddev: 7.160 Percentiles: 90th: 23.000; 95th: 27.000; 99th: 40.000 6.000 - 8.418: 58 # 8.418 - 11.670: 1149 ######################### 11.670 - 16.046: 2418 ##################################################### 16.046 - 21.934: 2098 ############################################## 21.934 - 29.854: 744 ################ 29.854 - 40.511: 154 ### 40.511 - 54.848: 41 # 54.848 - 74.136: 5 | 74.136 - 100.087: 9 | 100.087 - 135.000: 6 | These samples were captured during a run of the btrfs tests 001, 002 and 004 in the xfstests, with a leaf/node size of 4Kb. Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c42
1 files changed, 40 insertions, 2 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 5fa521bec07b..64346721173f 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -2426,6 +2426,40 @@ done:
2426 return ret; 2426 return ret;
2427} 2427}
2428 2428
2429static void key_search_validate(struct extent_buffer *b,
2430 struct btrfs_key *key,
2431 int level)
2432{
2433#ifdef CONFIG_BTRFS_ASSERT
2434 struct btrfs_disk_key disk_key;
2435
2436 btrfs_cpu_key_to_disk(&disk_key, key);
2437
2438 if (level == 0)
2439 ASSERT(!memcmp_extent_buffer(b, &disk_key,
2440 offsetof(struct btrfs_leaf, items[0].key),
2441 sizeof(disk_key)));
2442 else
2443 ASSERT(!memcmp_extent_buffer(b, &disk_key,
2444 offsetof(struct btrfs_node, ptrs[0].key),
2445 sizeof(disk_key)));
2446#endif
2447}
2448
2449static int key_search(struct extent_buffer *b, struct btrfs_key *key,
2450 int level, int *prev_cmp, int *slot)
2451{
2452 if (*prev_cmp != 0) {
2453 *prev_cmp = bin_search(b, key, level, slot);
2454 return *prev_cmp;
2455 }
2456
2457 key_search_validate(b, key, level);
2458 *slot = 0;
2459
2460 return 0;
2461}
2462
2429/* 2463/*
2430 * look for key in the tree. path is filled in with nodes along the way 2464 * look for key in the tree. path is filled in with nodes along the way
2431 * if key is found, we return zero and you can find the item in the leaf 2465 * if key is found, we return zero and you can find the item in the leaf
@@ -2454,6 +2488,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
2454 int write_lock_level = 0; 2488 int write_lock_level = 0;
2455 u8 lowest_level = 0; 2489 u8 lowest_level = 0;
2456 int min_write_lock_level; 2490 int min_write_lock_level;
2491 int prev_cmp;
2457 2492
2458 lowest_level = p->lowest_level; 2493 lowest_level = p->lowest_level;
2459 WARN_ON(lowest_level && ins_len > 0); 2494 WARN_ON(lowest_level && ins_len > 0);
@@ -2484,6 +2519,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
2484 min_write_lock_level = write_lock_level; 2519 min_write_lock_level = write_lock_level;
2485 2520
2486again: 2521again:
2522 prev_cmp = -1;
2487 /* 2523 /*
2488 * we try very hard to do read locks on the root 2524 * we try very hard to do read locks on the root
2489 */ 2525 */
@@ -2584,7 +2620,7 @@ cow_done:
2584 if (!cow) 2620 if (!cow)
2585 btrfs_unlock_up_safe(p, level + 1); 2621 btrfs_unlock_up_safe(p, level + 1);
2586 2622
2587 ret = bin_search(b, key, level, &slot); 2623 ret = key_search(b, key, level, &prev_cmp, &slot);
2588 2624
2589 if (level != 0) { 2625 if (level != 0) {
2590 int dec = 0; 2626 int dec = 0;
@@ -2719,6 +2755,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
2719 int level; 2755 int level;
2720 int lowest_unlock = 1; 2756 int lowest_unlock = 1;
2721 u8 lowest_level = 0; 2757 u8 lowest_level = 0;
2758 int prev_cmp;
2722 2759
2723 lowest_level = p->lowest_level; 2760 lowest_level = p->lowest_level;
2724 WARN_ON(p->nodes[0] != NULL); 2761 WARN_ON(p->nodes[0] != NULL);
@@ -2729,6 +2766,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
2729 } 2766 }
2730 2767
2731again: 2768again:
2769 prev_cmp = -1;
2732 b = get_old_root(root, time_seq); 2770 b = get_old_root(root, time_seq);
2733 level = btrfs_header_level(b); 2771 level = btrfs_header_level(b);
2734 p->locks[level] = BTRFS_READ_LOCK; 2772 p->locks[level] = BTRFS_READ_LOCK;
@@ -2746,7 +2784,7 @@ again:
2746 */ 2784 */
2747 btrfs_unlock_up_safe(p, level + 1); 2785 btrfs_unlock_up_safe(p, level + 1);
2748 2786
2749 ret = bin_search(b, key, level, &slot); 2787 ret = key_search(b, key, level, &prev_cmp, &slot);
2750 2788
2751 if (level != 0) { 2789 if (level != 0) {
2752 int dec = 0; 2790 int dec = 0;