struct rb_root root;
struct bmap_rb_extent **wcursor;
struct bmap_rb_extent **rcursor;
+#ifdef BMAP_STATS_OPS
+ __u64 mark_hit;
+ __u64 test_hit;
+#endif
};
static int rb_insert_extent(__u64 start, __u64 count,
*bp->rcursor = NULL;
*bp->wcursor = NULL;
+#ifdef BMAP_STATS_OPS
+ bp->test_hit = 0;
+ bp->mark_hit = 0;
+#endif
+
bitmap->private = (void *) bp;
return 0;
}
if (!rcursor)
goto search_tree;
- if (bit >= rcursor->start && bit < rcursor->start + rcursor->count)
+ if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) {
+#ifdef BMAP_STATS_OPS
+ bp->test_hit++;
+#endif
return 1;
+ }
rcursor = *bp->wcursor;
if (!rcursor)
ext = *bp->wcursor;
if (ext) {
if (start >= ext->start &&
- start <= (ext->start + ext->count))
+ start <= (ext->start + ext->count)) {
+#ifdef BMAP_STATS_OPS
+ bp->mark_hit++;
+#endif
goto got_extent;
+ }
}
while (*n) {
*bp->wcursor = NULL;
}
+#ifdef BMAP_STATS
+static void rb_print_stats(ext2fs_generic_bitmap bitmap)
+{
+ struct ext2fs_rb_private *bp;
+ struct rb_node *node = NULL;
+ struct bmap_rb_extent *ext;
+ __u64 count = 0;
+ __u64 max_size = 0;
+ __u64 min_size = ULONG_MAX;
+ __u64 size = 0, avg_size = 0;
+ __u64 mark_all, test_all;
+ double eff, m_hit = 0.0, t_hit = 0.0;
+
+ bp = (struct ext2fs_rb_private *) bitmap->private;
+
+ node = ext2fs_rb_first(&bp->root);
+ for (node = ext2fs_rb_first(&bp->root); node != NULL;
+ node = ext2fs_rb_next(node)) {
+ ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
+ count++;
+ if (ext->count > max_size)
+ max_size = ext->count;
+ if (ext->count < min_size)
+ min_size = ext->count;
+ size += ext->count;
+ }
+
+ if (count)
+ avg_size = size / count;
+ if (min_size == ULONG_MAX)
+ min_size = 0;
+ eff = (double)((count * sizeof(struct bmap_rb_extent)) << 3) /
+ (bitmap->real_end - bitmap->start);
+#ifdef BMAP_STATS_OPS
+ mark_all = bitmap->stats.mark_count + bitmap->stats.mark_ext_count;
+ test_all = bitmap->stats.test_count + bitmap->stats.test_ext_count;
+ if (mark_all)
+ m_hit = ((double)bp->mark_hit / mark_all) * 100;
+ if (test_all)
+ t_hit = ((double)bp->test_hit / test_all) * 100;
+
+ fprintf(stderr, "%16llu cache hits on test (%.2f%%)\n"
+ "%16llu cache hits on mark (%.2f%%)\n",
+ bp->test_hit, t_hit, bp->mark_hit, m_hit);
+#endif
+ fprintf(stderr, "%16llu extents (%llu bytes)\n",
+ count, ((count * sizeof(struct bmap_rb_extent)) +
+ sizeof(struct ext2fs_rb_private)));
+ fprintf(stderr, "%16llu bits minimum size\n",
+ min_size);
+ fprintf(stderr, "%16llu bits maximum size\n"
+ "%16llu bits average size\n",
+ max_size, avg_size);
+ fprintf(stderr, "%16llu bits set in bitmap (out of %llu)\n", size,
+ bitmap->real_end - bitmap->start);
+ fprintf(stderr,
+ "%16.4lf memory / bitmap bit memory ratio (bitarray = 1)\n",
+ eff);
+}
+#else
+static void rb_print_stats(ext2fs_generic_bitmap bitmap){}
+#endif
+
struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
.type = EXT2FS_BMAP64_RBTREE,
.new_bmap = rb_new_bmap,
.set_bmap_range = rb_set_bmap_range,
.get_bmap_range = rb_get_bmap_range,
.clear_bmap = rb_clear_bmap,
+ .print_stats = rb_print_stats,
};
#endif
}
+#ifdef BMAP_STATS_OPS
+#define INC_STAT(map, name) map->stats.name
+#else
+#define INC_STAT(map, name) ;;
+#endif
+
errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
int type, __u64 start, __u64 end,
return EINVAL;
}
- retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
- &bitmap);
+ retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap),
+ &bitmap);
if (retval)
return retval;
+#ifdef BMAP_STATS
+ if (gettimeofday(&bitmap->stats.created,
+ (struct timezone *) NULL) == -1) {
+ perror("gettimeofday");
+ return 1;
+ }
+ bitmap->stats.type = type;
+#endif
+
/* XXX factor out, repeated in copy_bmap */
bitmap->magic = magic;
bitmap->fs = fs;
return 0;
}
+#ifdef BMAP_STATS
+void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
+{
+ struct ext2_bmap_statistics *stats = &bitmap->stats;
+ float mark_seq_perc = 0.0, test_seq_perc = 0.0;
+ float mark_back_perc = 0.0, test_back_perc = 0.0;
+ double inuse;
+ struct timeval now;
+
+#ifdef BMAP_STATS_OPS
+ if (stats->test_count) {
+ test_seq_perc = ((float)stats->test_seq /
+ stats->test_count) * 100;
+ test_back_perc = ((float)stats->test_back /
+ stats->test_count) * 100;
+ }
+
+ if (stats->mark_count) {
+ mark_seq_perc = ((float)stats->mark_seq /
+ stats->mark_count) * 100;
+ mark_back_perc = ((float)stats->mark_back /
+ stats->mark_count) * 100;
+ }
+#endif
+
+ if (gettimeofday(&now, (struct timezone *) NULL) == -1) {
+ perror("gettimeofday");
+ return;
+ }
+
+ inuse = (double) now.tv_sec + \
+ (((double) now.tv_usec) * 0.000001);
+ inuse -= (double) stats->created.tv_sec + \
+ (((double) stats->created.tv_usec) * 0.000001);
+
+ fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description,
+ stats->type);
+ fprintf(stderr, "=================================================\n");
+#ifdef BMAP_STATS_OPS
+ fprintf(stderr, "%16llu bits long\n",
+ bitmap->real_end - bitmap->start);
+ fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n",
+ stats->copy_count, stats->resize_count);
+ fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n",
+ stats->mark_count, stats->unmark_count);
+ fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n",
+ stats->test_count, stats->mark_ext_count);
+ fprintf(stderr, "%16lu unmark_bmap_extent\n"
+ "%16lu test_clear_bmap_extent\n",
+ stats->unmark_ext_count, stats->test_ext_count);
+ fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n",
+ stats->set_range_count, stats->get_range_count);
+ fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n",
+ stats->clear_count, stats->test_seq, test_seq_perc);
+ fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n"
+ "%16llu bits tested backwards (%.2f%%)\n",
+ stats->mark_seq, mark_seq_perc,
+ stats->test_back, test_back_perc);
+ fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n"
+ "%16.2f seconds in use\n",
+ stats->mark_back, mark_back_perc, inuse);
+#endif /* BMAP_STATS_OPS */
+}
+#endif
+
void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap)
{
if (!bmap)
if (!EXT2FS_IS_64_BITMAP(bmap))
return;
+#ifdef BMAP_STATS
+ if (getenv("E2FSPROGS_BITMAP_STATS")) {
+ ext2fs_print_bmap_statistics(bmap);
+ bmap->bitmap_ops->print_stats(bmap);
+ }
+#endif
+
bmap->bitmap_ops->free_bmap(bmap);
if (bmap->description) {
return EINVAL;
/* Allocate a new bitmap struct */
- retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
- &new_bmap);
+ retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap),
+ &new_bmap);
if (retval)
return retval;
+
+#ifdef BMAP_STATS_OPS
+ src->stats.copy_count++;
+#endif
+#ifdef BMAP_STATS
+ if (gettimeofday(&new_bmap->stats.created,
+ (struct timezone *) NULL) == -1) {
+ perror("gettimeofday");
+ return 1;
+ }
+ new_bmap->stats.type = src->stats.type;
+#endif
+
/* Copy all the high-level parts over */
new_bmap->magic = src->magic;
new_bmap->fs = src->fs;
if (!EXT2FS_IS_64_BITMAP(bmap))
return EINVAL;
+ INC_STAT(bmap, resize_count);
+
return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
}
arg >>= bitmap->cluster_bits;
+#ifdef BMAP_STATS_OPS
+ if (arg == bitmap->stats.last_marked + 1)
+ bitmap->stats.mark_seq++;
+ if (arg < bitmap->stats.last_marked)
+ bitmap->stats.mark_back++;
+ bitmap->stats.last_marked = arg;
+ bitmap->stats.mark_count++;
+#endif
+
if ((arg < bitmap->start) || (arg > bitmap->end)) {
warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
return 0;
arg >>= bitmap->cluster_bits;
+ INC_STAT(bitmap, unmark_count);
+
if ((arg < bitmap->start) || (arg > bitmap->end)) {
warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
return 0;
arg >>= bitmap->cluster_bits;
+#ifdef BMAP_STATS_OPS
+ bitmap->stats.test_count++;
+ if (arg == bitmap->stats.last_tested + 1)
+ bitmap->stats.test_seq++;
+ if (arg < bitmap->stats.last_tested)
+ bitmap->stats.test_back++;
+ bitmap->stats.last_tested = arg;
+#endif
+
if ((arg < bitmap->start) || (arg > bitmap->end)) {
warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
return 0;
if (!EXT2FS_IS_64_BITMAP(bmap))
return EINVAL;
+ INC_STAT(bmap, set_range_count);
+
return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
}
if (!EXT2FS_IS_64_BITMAP(bmap))
return EINVAL;
+ INC_STAT(bmap, get_range_count);
+
return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
}
if (!EXT2FS_IS_64_BITMAP(bmap))
return EINVAL;
+ INC_STAT(bmap, test_ext_count);
+
return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
}
if (!EXT2FS_IS_64_BITMAP(bmap))
return;
+ INC_STAT(bmap, mark_ext_count);
+
if ((block < bmap->start) || (block+num-1 > bmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
bmap->description);
if (!EXT2FS_IS_64_BITMAP(bmap))
return;
+ INC_STAT(bmap, unmark_ext_count);
+
if ((block < bmap->start) || (block+num-1 > bmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
bmap->description);