debug.c 13.1 KB
Newer Older
J
Jaegeuk Kim 已提交
1
/*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * f2fs debugging statistics
 *
 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
 *             http://www.samsung.com/
 * Copyright (c) 2012 Linux Foundation
 * Copyright (c) 2012 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/fs.h>
#include <linux/backing-dev.h>
#include <linux/f2fs_fs.h>
#include <linux/blkdev.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>

#include "f2fs.h"
#include "node.h"
#include "segment.h"
#include "gc.h"

static LIST_HEAD(f2fs_stat_list);
27
static struct dentry *f2fs_debugfs_root;
28
static DEFINE_MUTEX(f2fs_stat_mutex);
29

30
static void update_general_status(struct f2fs_sb_info *sbi)
31
{
32
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
33 34
	int i;

A
arter97 已提交
35
	/* validation check of the segment numbers */
36 37
	si->hit_ext = sbi->read_hit_ext;
	si->total_ext = sbi->total_hit_ext;
38 39
	si->ext_tree = sbi->total_ext_tree;
	si->ext_node = atomic_read(&sbi->total_ext_node);
40 41 42 43
	si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
	si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
	si->ndirty_dirs = sbi->n_dirty_dirs;
	si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
44
	si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
45
	si->wb_pages = get_pages(sbi, F2FS_WRITEBACK);
46 47 48 49 50 51
	si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
	si->rsvd_segs = reserved_segments(sbi);
	si->overp_segs = overprovision_segments(sbi);
	si->valid_count = valid_user_blocks(sbi);
	si->valid_node_count = valid_node_count(sbi);
	si->valid_inode_count = valid_inode_count(sbi);
52 53
	si->inline_inode = atomic_read(&sbi->inline_inode);
	si->inline_dir = atomic_read(&sbi->inline_dir);
54 55 56 57 58 59
	si->utilization = utilization(sbi);

	si->free_segs = free_segments(sbi);
	si->free_secs = free_sections(sbi);
	si->prefree_count = prefree_segments(sbi);
	si->dirty_count = dirty_segments(sbi);
60
	si->node_pages = NODE_MAPPING(sbi)->nrpages;
G
Gu Zheng 已提交
61
	si->meta_pages = META_MAPPING(sbi)->nrpages;
62
	si->nats = NM_I(sbi)->nat_cnt;
63 64 65
	si->dirty_nats = NM_I(sbi)->dirty_nat_cnt;
	si->sits = MAIN_SEGS(sbi);
	si->dirty_sits = SIT_I(sbi)->dirty_sentries;
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
	si->fnids = NM_I(sbi)->fcnt;
	si->bg_gc = sbi->bg_gc;
	si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
		* 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
		/ 2;
	si->util_valid = (int)(written_block_count(sbi) >>
						sbi->log_blocks_per_seg)
		* 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
		/ 2;
	si->util_invalid = 50 - si->util_free - si->util_valid;
	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) {
		struct curseg_info *curseg = CURSEG_I(sbi, i);
		si->curseg[i] = curseg->segno;
		si->cursec[i] = curseg->segno / sbi->segs_per_sec;
		si->curzone[i] = si->cursec[i] / sbi->secs_per_zone;
	}

	for (i = 0; i < 2; i++) {
		si->segment_count[i] = sbi->segment_count[i];
		si->block_count[i] = sbi->block_count[i];
	}
87 88

	si->inplace_count = atomic_read(&sbi->inplace_count);
89 90
}

J
Jaegeuk Kim 已提交
91
/*
92 93 94 95
 * This function calculates BDF of every segments
 */
static void update_sit_info(struct f2fs_sb_info *sbi)
{
96
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
97 98 99 100 101 102 103 104
	unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist;
	unsigned int segno, vblocks;
	int ndirty = 0;

	bimodal = 0;
	total_vblocks = 0;
	blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg);
	hblks_per_sec = blks_per_sec / 2;
105
	for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
106 107 108 109 110 111 112 113 114
		vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
		dist = abs(vblocks - hblks_per_sec);
		bimodal += dist * dist;

		if (vblocks > 0 && vblocks < blks_per_sec) {
			total_vblocks += vblocks;
			ndirty++;
		}
	}
115
	dist = MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec / 100;
116 117 118 119 120 121 122
	si->bimodal = bimodal / dist;
	if (si->dirty_count)
		si->avg_vblocks = total_vblocks / ndirty;
	else
		si->avg_vblocks = 0;
}

J
Jaegeuk Kim 已提交
123
/*
124 125 126 127
 * This function calculates memory footprint.
 */
static void update_mem_info(struct f2fs_sb_info *sbi)
{
128
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
129
	unsigned npages;
130
	int i;
131 132 133 134 135 136 137 138 139 140 141 142 143

	if (si->base_mem)
		goto get_cache;

	si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
	si->base_mem += 2 * sizeof(struct f2fs_inode_info);
	si->base_mem += sizeof(*sbi->ckpt);

	/* build sm */
	si->base_mem += sizeof(struct f2fs_sm_info);

	/* build sit */
	si->base_mem += sizeof(struct sit_info);
144 145 146
	si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry);
	si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
	si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
J
Jaegeuk Kim 已提交
147
	si->base_mem += SIT_VBLOCK_MAP_SIZE;
148
	if (sbi->segs_per_sec > 1)
149
		si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry);
150 151 152 153
	si->base_mem += __bitmap_size(sbi, SIT_BITMAP);

	/* build free segmap */
	si->base_mem += sizeof(struct free_segmap_info);
154 155
	si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
	si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
156 157 158 159 160 161 162

	/* build curseg */
	si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE;
	si->base_mem += PAGE_CACHE_SIZE * NR_CURSEG_TYPE;

	/* build dirty segmap */
	si->base_mem += sizeof(struct dirty_seglist_info);
163 164
	si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(MAIN_SEGS(sbi));
	si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
165

A
arter97 已提交
166
	/* build nm */
167 168 169
	si->base_mem += sizeof(struct f2fs_nm_info);
	si->base_mem += __bitmap_size(sbi, NAT_BITMAP);

170 171 172
get_cache:
	si->cache_mem = 0;

173
	/* build gc */
174 175 176 177 178 179
	if (sbi->gc_thread)
		si->cache_mem += sizeof(struct f2fs_gc_kthread);

	/* build merge flush thread */
	if (SM_I(sbi)->cmd_control_info)
		si->cache_mem += sizeof(struct flush_cmd_control);
180 181

	/* free nids */
182 183
	si->cache_mem += NM_I(sbi)->fcnt * sizeof(struct free_nid);
	si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry);
184 185 186
	si->cache_mem += NM_I(sbi)->dirty_nat_cnt *
					sizeof(struct nat_entry_set);
	si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
187
	si->cache_mem += sbi->n_dirty_dirs * sizeof(struct inode_entry);
188
	for (i = 0; i <= UPDATE_INO; i++)
189
		si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
190 191 192
	si->cache_mem += sbi->total_ext_tree * sizeof(struct extent_tree);
	si->cache_mem += atomic_read(&sbi->total_ext_node) *
						sizeof(struct extent_node);
193 194 195 196 197 198

	si->page_mem = 0;
	npages = NODE_MAPPING(sbi)->nrpages;
	si->page_mem += npages << PAGE_CACHE_SHIFT;
	npages = META_MAPPING(sbi)->nrpages;
	si->page_mem += npages << PAGE_CACHE_SHIFT;
199 200 201 202
}

static int stat_show(struct seq_file *s, void *v)
{
203
	struct f2fs_stat_info *si;
204 205 206
	int i = 0;
	int j;

207
	mutex_lock(&f2fs_stat_mutex);
208
	list_for_each_entry(si, &f2fs_stat_list, stat_list) {
M
majianpeng 已提交
209
		char devname[BDEVNAME_SIZE];
210 211 212

		update_general_status(si->sbi);

M
majianpeng 已提交
213 214
		seq_printf(s, "\n=====[ partition info(%s). #%d ]=====\n",
			bdevname(si->sbi->sb->s_bdev, devname), i++);
215 216
		seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
			   si->sit_area_segs, si->nat_area_segs);
217 218 219 220 221 222 223 224 225 226 227
		seq_printf(s, "[SSA: %d] [MAIN: %d",
			   si->ssa_area_segs, si->main_area_segs);
		seq_printf(s, "(OverProv:%d Resv:%d)]\n\n",
			   si->overp_segs, si->rsvd_segs);
		seq_printf(s, "Utilization: %d%% (%d valid blocks)\n",
			   si->utilization, si->valid_count);
		seq_printf(s, "  - Node: %u (Inode: %u, ",
			   si->valid_node_count, si->valid_inode_count);
		seq_printf(s, "Other: %u)\n  - Data: %u\n",
			   si->valid_node_count - si->valid_inode_count,
			   si->valid_count - si->valid_node_count);
228 229
		seq_printf(s, "  - Inline_data Inode: %u\n",
			   si->inline_inode);
230 231
		seq_printf(s, "  - Inline_dentry Inode: %u\n",
			   si->inline_dir);
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
		seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
			   si->main_area_segs, si->main_area_sections,
			   si->main_area_zones);
		seq_printf(s, "  - COLD  data: %d, %d, %d\n",
			   si->curseg[CURSEG_COLD_DATA],
			   si->cursec[CURSEG_COLD_DATA],
			   si->curzone[CURSEG_COLD_DATA]);
		seq_printf(s, "  - WARM  data: %d, %d, %d\n",
			   si->curseg[CURSEG_WARM_DATA],
			   si->cursec[CURSEG_WARM_DATA],
			   si->curzone[CURSEG_WARM_DATA]);
		seq_printf(s, "  - HOT   data: %d, %d, %d\n",
			   si->curseg[CURSEG_HOT_DATA],
			   si->cursec[CURSEG_HOT_DATA],
			   si->curzone[CURSEG_HOT_DATA]);
		seq_printf(s, "  - Dir   dnode: %d, %d, %d\n",
			   si->curseg[CURSEG_HOT_NODE],
			   si->cursec[CURSEG_HOT_NODE],
			   si->curzone[CURSEG_HOT_NODE]);
		seq_printf(s, "  - File   dnode: %d, %d, %d\n",
			   si->curseg[CURSEG_WARM_NODE],
			   si->cursec[CURSEG_WARM_NODE],
			   si->curzone[CURSEG_WARM_NODE]);
		seq_printf(s, "  - Indir nodes: %d, %d, %d\n",
			   si->curseg[CURSEG_COLD_NODE],
			   si->cursec[CURSEG_COLD_NODE],
			   si->curzone[CURSEG_COLD_NODE]);
		seq_printf(s, "\n  - Valid: %d\n  - Dirty: %d\n",
			   si->main_area_segs - si->dirty_count -
			   si->prefree_count - si->free_segs,
			   si->dirty_count);
		seq_printf(s, "  - Prefree: %d\n  - Free: %d (%d)\n\n",
			   si->prefree_count, si->free_segs, si->free_secs);
265
		seq_printf(s, "CP calls: %d\n", si->cp_count);
266 267
		seq_printf(s, "GC calls: %d (BG: %d)\n",
			   si->call_count, si->bg_gc);
268 269 270 271 272 273 274 275 276 277
		seq_printf(s, "  - data segments : %d (%d)\n",
				si->data_segs, si->bg_data_segs);
		seq_printf(s, "  - node segments : %d (%d)\n",
				si->node_segs, si->bg_node_segs);
		seq_printf(s, "Try to move %d blocks (BG: %d)\n", si->tot_blks,
				si->bg_data_blks + si->bg_node_blks);
		seq_printf(s, "  - data blocks : %d (%d)\n", si->data_blks,
				si->bg_data_blks);
		seq_printf(s, "  - node blocks : %d (%d)\n", si->node_blks,
				si->bg_node_blks);
278 279
		seq_printf(s, "\nExtent Hit Ratio: %d / %d\n",
			   si->hit_ext, si->total_ext);
280 281
		seq_printf(s, "\nExtent Tree Count: %d\n", si->ext_tree);
		seq_printf(s, "\nExtent Node Count: %d\n", si->ext_node);
C
Chris Fries 已提交
282
		seq_puts(s, "\nBalancing F2FS Async:\n");
283 284
		seq_printf(s, "  - inmem: %4d, wb: %4d\n",
			   si->inmem_pages, si->wb_pages);
285
		seq_printf(s, "  - nodes: %4d in %4d\n",
286
			   si->ndirty_node, si->node_pages);
287
		seq_printf(s, "  - dents: %4d in dirs:%4d\n",
288
			   si->ndirty_dent, si->ndirty_dirs);
289
		seq_printf(s, "  - meta: %4d in %4d\n",
290
			   si->ndirty_meta, si->meta_pages);
291 292
		seq_printf(s, "  - NATs: %9d/%9d\n  - SITs: %9d/%9d\n",
			   si->dirty_nats, si->nats, si->dirty_sits, si->sits);
J
Jaegeuk Kim 已提交
293 294
		seq_printf(s, "  - free_nids: %9d\n",
			   si->fnids);
295 296 297
		seq_puts(s, "\nDistribution of User Blocks:");
		seq_puts(s, " [ valid | invalid | free ]\n");
		seq_puts(s, "  [");
298 299

		for (j = 0; j < si->util_valid; j++)
300 301
			seq_putc(s, '-');
		seq_putc(s, '|');
302 303

		for (j = 0; j < si->util_invalid; j++)
304 305
			seq_putc(s, '-');
		seq_putc(s, '|');
306 307

		for (j = 0; j < si->util_free; j++)
308 309
			seq_putc(s, '-');
		seq_puts(s, "]\n\n");
310
		seq_printf(s, "IPU: %u blocks\n", si->inplace_count);
311 312 313 314 315 316 317 318 319 320 321 322
		seq_printf(s, "SSR: %u blocks in %u segments\n",
			   si->block_count[SSR], si->segment_count[SSR]);
		seq_printf(s, "LFS: %u blocks in %u segments\n",
			   si->block_count[LFS], si->segment_count[LFS]);

		/* segment usage info */
		update_sit_info(si->sbi);
		seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n",
			   si->bimodal, si->avg_vblocks);

		/* memory footprint */
		update_mem_info(si->sbi);
323 324 325 326 327 328 329 330
		seq_printf(s, "\nMemory: %u KB\n",
			(si->base_mem + si->cache_mem + si->page_mem) >> 10);
		seq_printf(s, "  - static: %u KB\n",
				si->base_mem >> 10);
		seq_printf(s, "  - cached: %u KB\n",
				si->cache_mem >> 10);
		seq_printf(s, "  - paged : %u KB\n",
				si->page_mem >> 10);
331
	}
332
	mutex_unlock(&f2fs_stat_mutex);
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
	return 0;
}

static int stat_open(struct inode *inode, struct file *file)
{
	return single_open(file, stat_show, inode->i_private);
}

static const struct file_operations stat_fops = {
	.open = stat_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
};

348
int f2fs_build_stats(struct f2fs_sb_info *sbi)
349 350 351 352
{
	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
	struct f2fs_stat_info *si;

353 354
	si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
	if (!si)
355 356 357 358 359 360 361 362 363 364 365
		return -ENOMEM;

	si->all_area_segs = le32_to_cpu(raw_super->segment_count);
	si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit);
	si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat);
	si->ssa_area_segs = le32_to_cpu(raw_super->segment_count_ssa);
	si->main_area_segs = le32_to_cpu(raw_super->segment_count_main);
	si->main_area_sections = le32_to_cpu(raw_super->section_count);
	si->main_area_zones = si->main_area_sections /
				le32_to_cpu(raw_super->secs_per_zone);
	si->sbi = sbi;
366
	sbi->stat_info = si;
367

368 369
	atomic_set(&sbi->inline_inode, 0);
	atomic_set(&sbi->inline_dir, 0);
370
	atomic_set(&sbi->inplace_count, 0);
371

372 373 374 375
	mutex_lock(&f2fs_stat_mutex);
	list_add_tail(&si->stat_list, &f2fs_stat_list);
	mutex_unlock(&f2fs_stat_mutex);

376 377 378 379 380
	return 0;
}

void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
{
381
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
382

383
	mutex_lock(&f2fs_stat_mutex);
384
	list_del(&si->stat_list);
385 386
	mutex_unlock(&f2fs_stat_mutex);

387
	kfree(si);
388 389
}

390 391
void __init f2fs_create_root_stats(void)
{
392 393
	struct dentry *file;

394 395
	f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL);
	if (!f2fs_debugfs_root)
396
		return;
397

398
	file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root,
399
			NULL, &stat_fops);
400 401 402 403
	if (!file) {
		debugfs_remove(f2fs_debugfs_root);
		f2fs_debugfs_root = NULL;
	}
404 405 406
}

void f2fs_destroy_root_stats(void)
407
{
408
	if (!f2fs_debugfs_root)
409 410
		return;

411 412
	debugfs_remove_recursive(f2fs_debugfs_root);
	f2fs_debugfs_root = NULL;
413
}