debug.c 14 KB
Newer Older
Jaegeuk Kim's avatar
Jaegeuk Kim committed
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;

arter97's avatar
arter97 committed
35
	/* validation check of the segment numbers */
36
37
38
	si->hit_largest = atomic64_read(&sbi->read_hit_largest);
	si->hit_cached = atomic64_read(&sbi->read_hit_cached);
	si->hit_rbtree = atomic64_read(&sbi->read_hit_rbtree);
39
	si->hit_total = si->hit_largest + si->hit_cached + si->hit_rbtree;
40
	si->total_ext = atomic64_read(&sbi->total_hit_ext);
41
42
	si->ext_tree = sbi->total_ext_tree;
	si->ext_node = atomic_read(&sbi->total_ext_node);
43
44
45
46
	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);
47
	si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
48
	si->wb_pages = get_pages(sbi, F2FS_WRITEBACK);
49
50
51
52
53
54
	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);
Chao Yu's avatar
Chao Yu committed
55
	si->inline_xattr = atomic_read(&sbi->inline_xattr);
56
57
	si->inline_inode = atomic_read(&sbi->inline_inode);
	si->inline_dir = atomic_read(&sbi->inline_dir);
58
59
60
61
62
63
	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);
64
	si->node_pages = NODE_MAPPING(sbi)->nrpages;
65
	si->meta_pages = META_MAPPING(sbi)->nrpages;
66
	si->nats = NM_I(sbi)->nat_cnt;
67
68
69
	si->dirty_nats = NM_I(sbi)->dirty_nat_cnt;
	si->sits = MAIN_SEGS(sbi);
	si->dirty_sits = SIT_I(sbi)->dirty_sentries;
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
	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];
	}
91
92

	si->inplace_count = atomic_read(&sbi->inplace_count);
93
94
}

Jaegeuk Kim's avatar
Jaegeuk Kim committed
95
/*
96
97
98
99
 * This function calculates BDF of every segments
 */
static void update_sit_info(struct f2fs_sb_info *sbi)
{
100
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
101
102
	unsigned long long blks_per_sec, hblks_per_sec, total_vblocks;
	unsigned long long bimodal, dist;
103
104
105
106
107
108
109
	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;
110
	for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
111
112
113
114
115
116
117
118
119
		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++;
		}
	}
120
	dist = div_u64(MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec, 100);
121
	si->bimodal = div64_u64(bimodal, dist);
122
	if (si->dirty_count)
123
		si->avg_vblocks = div_u64(total_vblocks, ndirty);
124
125
126
127
	else
		si->avg_vblocks = 0;
}

Jaegeuk Kim's avatar
Jaegeuk Kim committed
128
/*
129
130
131
132
 * This function calculates memory footprint.
 */
static void update_mem_info(struct f2fs_sb_info *sbi)
{
133
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
134
	unsigned npages;
135
	int i;
136
137
138
139
140
141
142
143
144
145
146
147
148

	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);
149
150
	si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry);
	si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
151
	si->base_mem += 3 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
152
	si->base_mem += SIT_VBLOCK_MAP_SIZE;
153
	if (sbi->segs_per_sec > 1)
154
		si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry);
155
156
157
158
	si->base_mem += __bitmap_size(sbi, SIT_BITMAP);

	/* build free segmap */
	si->base_mem += sizeof(struct free_segmap_info);
159
160
	si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
	si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
161
162
163
164
165
166
167

	/* 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);
168
169
	si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(MAIN_SEGS(sbi));
	si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
170

arter97's avatar
arter97 committed
171
	/* build nm */
172
173
174
	si->base_mem += sizeof(struct f2fs_nm_info);
	si->base_mem += __bitmap_size(sbi, NAT_BITMAP);

175
176
177
get_cache:
	si->cache_mem = 0;

178
	/* build gc */
179
180
181
182
183
184
	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);
185
186

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

	si->page_mem = 0;
	npages = NODE_MAPPING(sbi)->nrpages;
201
	si->page_mem += (unsigned long long)npages << PAGE_CACHE_SHIFT;
202
	npages = META_MAPPING(sbi)->nrpages;
203
	si->page_mem += (unsigned long long)npages << PAGE_CACHE_SHIFT;
204
205
206
207
}

static int stat_show(struct seq_file *s, void *v)
{
208
	struct f2fs_stat_info *si;
209
210
211
	int i = 0;
	int j;

212
	mutex_lock(&f2fs_stat_mutex);
213
	list_for_each_entry(si, &f2fs_stat_list, stat_list) {
majianpeng's avatar
majianpeng committed
214
		char devname[BDEVNAME_SIZE];
215
216
217

		update_general_status(si->sbi);

majianpeng's avatar
majianpeng committed
218
219
		seq_printf(s, "\n=====[ partition info(%s). #%d ]=====\n",
			bdevname(si->sbi->sb->s_bdev, devname), i++);
220
221
		seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
			   si->sit_area_segs, si->nat_area_segs);
222
223
224
225
226
227
228
229
230
231
232
		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);
Chao Yu's avatar
Chao Yu committed
233
234
		seq_printf(s, "  - Inline_xattr Inode: %u\n",
			   si->inline_xattr);
235
236
		seq_printf(s, "  - Inline_data Inode: %u\n",
			   si->inline_inode);
237
238
		seq_printf(s, "  - Inline_dentry Inode: %u\n",
			   si->inline_dir);
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
265
266
267
268
269
270
271
		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);
272
		seq_printf(s, "CP calls: %d\n", si->cp_count);
273
274
		seq_printf(s, "GC calls: %d (BG: %d)\n",
			   si->call_count, si->bg_gc);
275
276
277
278
279
280
281
282
283
284
		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);
285
		seq_puts(s, "\nExtent Cache:\n");
286
		seq_printf(s, "  - Hit Count: L1-1:%llu L1-2:%llu L2:%llu\n",
287
				si->hit_largest, si->hit_cached,
288
				si->hit_rbtree);
289
		seq_printf(s, "  - Hit Ratio: %llu%% (%llu / %llu)\n",
290
				!si->total_ext ? 0 :
291
				div64_u64(si->hit_total * 100, si->total_ext),
292
293
294
				si->hit_total, si->total_ext);
		seq_printf(s, "  - Inner Struct Count: tree: %d, node: %d\n",
				si->ext_tree, si->ext_node);
Chris Fries's avatar
Chris Fries committed
295
		seq_puts(s, "\nBalancing F2FS Async:\n");
296
297
		seq_printf(s, "  - inmem: %4d, wb: %4d\n",
			   si->inmem_pages, si->wb_pages);
298
		seq_printf(s, "  - nodes: %4d in %4d\n",
299
			   si->ndirty_node, si->node_pages);
300
		seq_printf(s, "  - dents: %4d in dirs:%4d\n",
301
			   si->ndirty_dent, si->ndirty_dirs);
302
		seq_printf(s, "  - meta: %4d in %4d\n",
303
			   si->ndirty_meta, si->meta_pages);
304
305
		seq_printf(s, "  - NATs: %9d/%9d\n  - SITs: %9d/%9d\n",
			   si->dirty_nats, si->nats, si->dirty_sits, si->sits);
306
307
		seq_printf(s, "  - free_nids: %9d\n",
			   si->fnids);
308
309
310
		seq_puts(s, "\nDistribution of User Blocks:");
		seq_puts(s, " [ valid | invalid | free ]\n");
		seq_puts(s, "  [");
311
312

		for (j = 0; j < si->util_valid; j++)
313
314
			seq_putc(s, '-');
		seq_putc(s, '|');
315
316

		for (j = 0; j < si->util_invalid; j++)
317
318
			seq_putc(s, '-');
		seq_putc(s, '|');
319
320

		for (j = 0; j < si->util_free; j++)
321
322
			seq_putc(s, '-');
		seq_puts(s, "]\n\n");
323
		seq_printf(s, "IPU: %u blocks\n", si->inplace_count);
324
325
326
327
328
329
330
331
332
333
334
335
		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);
336
		seq_printf(s, "\nMemory: %llu KB\n",
337
			(si->base_mem + si->cache_mem + si->page_mem) >> 10);
338
		seq_printf(s, "  - static: %llu KB\n",
339
				si->base_mem >> 10);
340
		seq_printf(s, "  - cached: %llu KB\n",
341
				si->cache_mem >> 10);
342
		seq_printf(s, "  - paged : %llu KB\n",
343
				si->page_mem >> 10);
344
	}
345
	mutex_unlock(&f2fs_stat_mutex);
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
	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,
};

361
int f2fs_build_stats(struct f2fs_sb_info *sbi)
362
363
364
365
{
	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
	struct f2fs_stat_info *si;

366
367
	si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
	if (!si)
368
369
370
371
372
373
374
375
376
377
378
		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;
379
	sbi->stat_info = si;
380

381
382
383
384
	atomic64_set(&sbi->total_hit_ext, 0);
	atomic64_set(&sbi->read_hit_rbtree, 0);
	atomic64_set(&sbi->read_hit_largest, 0);
	atomic64_set(&sbi->read_hit_cached, 0);
385

Chao Yu's avatar
Chao Yu committed
386
	atomic_set(&sbi->inline_xattr, 0);
387
388
	atomic_set(&sbi->inline_inode, 0);
	atomic_set(&sbi->inline_dir, 0);
389
	atomic_set(&sbi->inplace_count, 0);
390

391
392
393
394
	mutex_lock(&f2fs_stat_mutex);
	list_add_tail(&si->stat_list, &f2fs_stat_list);
	mutex_unlock(&f2fs_stat_mutex);

395
396
397
398
399
	return 0;
}

void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
{
400
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
401

402
	mutex_lock(&f2fs_stat_mutex);
403
	list_del(&si->stat_list);
404
405
	mutex_unlock(&f2fs_stat_mutex);

406
	kfree(si);
407
408
}

409
int __init f2fs_create_root_stats(void)
410
{
411
412
	struct dentry *file;

413
414
	f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL);
	if (!f2fs_debugfs_root)
415
		return -ENOMEM;
416

417
	file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root,
418
			NULL, &stat_fops);
419
420
421
	if (!file) {
		debugfs_remove(f2fs_debugfs_root);
		f2fs_debugfs_root = NULL;
422
		return -ENOMEM;
423
	}
424
425

	return 0;
426
427
428
}

void f2fs_destroy_root_stats(void)
429
{
430
	if (!f2fs_debugfs_root)
431
432
		return;

433
434
	debugfs_remove_recursive(f2fs_debugfs_root);
	f2fs_debugfs_root = NULL;
435
}