debug.c 12.6 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 38 39 40 41
	si->hit_ext = sbi->read_hit_ext;
	si->total_ext = sbi->total_hit_ext;
	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);
42
	si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
43
	si->wb_pages = get_pages(sbi, F2FS_WRITEBACK);
44 45 46 47 48 49
	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);
50 51
	si->inline_inode = atomic_read(&sbi->inline_inode);
	si->inline_dir = atomic_read(&sbi->inline_dir);
52 53 54 55 56 57
	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);
58
	si->node_pages = NODE_MAPPING(sbi)->nrpages;
G
Gu Zheng 已提交
59
	si->meta_pages = META_MAPPING(sbi)->nrpages;
60
	si->nats = NM_I(sbi)->nat_cnt;
61 62 63
	si->dirty_nats = NM_I(sbi)->dirty_nat_cnt;
	si->sits = MAIN_SEGS(sbi);
	si->dirty_sits = SIT_I(sbi)->dirty_sentries;
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
	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];
	}
85 86

	si->inplace_count = atomic_read(&sbi->inplace_count);
87 88
}

J
Jaegeuk Kim 已提交
89
/*
90 91 92 93
 * This function calculates BDF of every segments
 */
static void update_sit_info(struct f2fs_sb_info *sbi)
{
94
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
95 96 97 98 99 100 101 102
	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;
103
	for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
104 105 106 107 108 109 110 111 112
		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++;
		}
	}
113
	dist = MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec / 100;
114 115 116 117 118 119 120
	si->bimodal = bimodal / dist;
	if (si->dirty_count)
		si->avg_vblocks = total_vblocks / ndirty;
	else
		si->avg_vblocks = 0;
}

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

	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);
142 143 144
	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 已提交
145
	si->base_mem += SIT_VBLOCK_MAP_SIZE;
146
	if (sbi->segs_per_sec > 1)
147
		si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry);
148 149 150 151
	si->base_mem += __bitmap_size(sbi, SIT_BITMAP);

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

	/* 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);
161 162
	si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(MAIN_SEGS(sbi));
	si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
163

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

168 169 170
get_cache:
	si->cache_mem = 0;

171
	/* build gc */
172 173 174 175 176 177
	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);
178 179

	/* free nids */
180 181
	si->cache_mem += NM_I(sbi)->fcnt * sizeof(struct free_nid);
	si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry);
182 183 184
	si->cache_mem += NM_I(sbi)->dirty_nat_cnt *
					sizeof(struct nat_entry_set);
	si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
185
	si->cache_mem += sbi->n_dirty_dirs * sizeof(struct inode_entry);
186
	for (i = 0; i <= UPDATE_INO; i++)
187
		si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
188 189 190 191 192 193

	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;
194 195 196 197
}

static int stat_show(struct seq_file *s, void *v)
{
198
	struct f2fs_stat_info *si;
199 200 201
	int i = 0;
	int j;

202
	mutex_lock(&f2fs_stat_mutex);
203
	list_for_each_entry(si, &f2fs_stat_list, stat_list) {
M
majianpeng 已提交
204
		char devname[BDEVNAME_SIZE];
205 206 207

		update_general_status(si->sbi);

M
majianpeng 已提交
208 209
		seq_printf(s, "\n=====[ partition info(%s). #%d ]=====\n",
			bdevname(si->sbi->sb->s_bdev, devname), i++);
210 211
		seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
			   si->sit_area_segs, si->nat_area_segs);
212 213 214 215 216 217 218 219 220 221 222
		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);
223 224
		seq_printf(s, "  - Inline_data Inode: %u\n",
			   si->inline_inode);
225 226
		seq_printf(s, "  - Inline_dentry Inode: %u\n",
			   si->inline_dir);
227 228 229 230 231 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
		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);
260
		seq_printf(s, "CP calls: %d\n", si->cp_count);
261 262 263 264 265 266 267 268 269
		seq_printf(s, "GC calls: %d (BG: %d)\n",
			   si->call_count, si->bg_gc);
		seq_printf(s, "  - data segments : %d\n", si->data_segs);
		seq_printf(s, "  - node segments : %d\n", si->node_segs);
		seq_printf(s, "Try to move %d blocks\n", si->tot_blks);
		seq_printf(s, "  - data blocks : %d\n", si->data_blks);
		seq_printf(s, "  - node blocks : %d\n", si->node_blks);
		seq_printf(s, "\nExtent Hit Ratio: %d / %d\n",
			   si->hit_ext, si->total_ext);
C
Chris Fries 已提交
270
		seq_puts(s, "\nBalancing F2FS Async:\n");
271 272
		seq_printf(s, "  - inmem: %4d, wb: %4d\n",
			   si->inmem_pages, si->wb_pages);
273
		seq_printf(s, "  - nodes: %4d in %4d\n",
274
			   si->ndirty_node, si->node_pages);
275
		seq_printf(s, "  - dents: %4d in dirs:%4d\n",
276
			   si->ndirty_dent, si->ndirty_dirs);
277
		seq_printf(s, "  - meta: %4d in %4d\n",
278
			   si->ndirty_meta, si->meta_pages);
279 280
		seq_printf(s, "  - NATs: %9d/%9d\n  - SITs: %9d/%9d\n",
			   si->dirty_nats, si->nats, si->dirty_sits, si->sits);
J
Jaegeuk Kim 已提交
281 282
		seq_printf(s, "  - free_nids: %9d\n",
			   si->fnids);
283 284 285
		seq_puts(s, "\nDistribution of User Blocks:");
		seq_puts(s, " [ valid | invalid | free ]\n");
		seq_puts(s, "  [");
286 287

		for (j = 0; j < si->util_valid; j++)
288 289
			seq_putc(s, '-');
		seq_putc(s, '|');
290 291

		for (j = 0; j < si->util_invalid; j++)
292 293
			seq_putc(s, '-');
		seq_putc(s, '|');
294 295

		for (j = 0; j < si->util_free; j++)
296 297
			seq_putc(s, '-');
		seq_puts(s, "]\n\n");
298
		seq_printf(s, "IPU: %u blocks\n", si->inplace_count);
299 300 301 302 303 304 305 306 307 308 309 310
		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);
311 312 313 314 315 316 317 318
		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);
319
	}
320
	mutex_unlock(&f2fs_stat_mutex);
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
	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,
};

336
int f2fs_build_stats(struct f2fs_sb_info *sbi)
337 338 339 340
{
	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
	struct f2fs_stat_info *si;

341 342
	si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
	if (!si)
343 344 345 346 347 348 349 350 351 352 353
		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;
354
	sbi->stat_info = si;
355

356 357
	atomic_set(&sbi->inline_inode, 0);
	atomic_set(&sbi->inline_dir, 0);
358
	atomic_set(&sbi->inplace_count, 0);
359

360 361 362 363
	mutex_lock(&f2fs_stat_mutex);
	list_add_tail(&si->stat_list, &f2fs_stat_list);
	mutex_unlock(&f2fs_stat_mutex);

364 365 366 367 368
	return 0;
}

void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
{
369
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
370

371
	mutex_lock(&f2fs_stat_mutex);
372
	list_del(&si->stat_list);
373 374
	mutex_unlock(&f2fs_stat_mutex);

375
	kfree(si);
376 377
}

378 379
void __init f2fs_create_root_stats(void)
{
380 381
	struct dentry *file;

382 383
	f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL);
	if (!f2fs_debugfs_root)
384
		return;
385

386
	file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root,
387
			NULL, &stat_fops);
388 389 390 391
	if (!file) {
		debugfs_remove(f2fs_debugfs_root);
		f2fs_debugfs_root = NULL;
	}
392 393 394
}

void f2fs_destroy_root_stats(void)
395
{
396
	if (!f2fs_debugfs_root)
397 398
		return;

399 400
	debugfs_remove_recursive(f2fs_debugfs_root);
	f2fs_debugfs_root = NULL;
401
}