Whamcloud - gitweb
- all stats gatherd in OSC debugging time (cache loading, etc.) moved to proc. Added...
[fs/lustre-release.git] / lustre / osc / lproc_osc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22 #define DEBUG_SUBSYSTEM S_CLASS
23
24 #include <linux/version.h>
25 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
26 #include <asm/statfs.h>
27 #endif
28 #include <linux/obd_class.h>
29 #include <linux/lprocfs_status.h>
30 #include <linux/seq_file.h>
31 #include "osc_internal.h"
32
33 #ifndef LPROCFS
34 static struct lprocfs_vars lprocfs_obd_vars[]  = { {0} };
35 static struct lprocfs_vars lprocfs_module_vars[] = { {0} };
36 #else
37
38 int osc_rd_max_pages_per_rpc(char *page, char **start, off_t off, int count,
39                              int *eof, void *data)
40 {
41         struct obd_device *dev = data;
42         struct client_obd *cli = &dev->u.cli;
43         int rc;
44
45         spin_lock(&cli->cl_loi_list_lock);
46         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
47         spin_unlock(&cli->cl_loi_list_lock);
48         return rc;
49 }
50
51 int osc_wr_max_pages_per_rpc(struct file *file, const char *buffer,
52                              unsigned long count, void *data)
53 {
54         struct obd_device *dev = data;
55         struct client_obd *cli = &dev->u.cli;
56         int val, rc;
57
58         rc = lprocfs_write_helper(buffer, count, &val);
59         if (rc)
60                 return rc;
61
62         if (val < 1 || val > PTLRPC_MAX_BRW_PAGES)
63                 return -ERANGE;
64
65         spin_lock(&cli->cl_loi_list_lock);
66         cli->cl_max_pages_per_rpc = val;
67         spin_unlock(&cli->cl_loi_list_lock);
68
69         return count;
70 }
71
72 int osc_rd_max_rpcs_in_flight(char *page, char **start, off_t off, int count,
73                               int *eof, void *data)
74 {
75         struct obd_device *dev = data;
76         struct client_obd *cli = &dev->u.cli;
77         int rc;
78
79         spin_lock(&cli->cl_loi_list_lock);
80         rc = snprintf(page, count, "%u\n", cli->cl_max_rpcs_in_flight);
81         spin_unlock(&cli->cl_loi_list_lock);
82         return rc;
83 }
84
85 int osc_wr_max_rpcs_in_flight(struct file *file, const char *buffer,
86                               unsigned long count, void *data)
87 {
88         struct obd_device *dev = data;
89         struct client_obd *cli = &dev->u.cli;
90         int val, rc;
91
92         rc = lprocfs_write_helper(buffer, count, &val);
93         if (rc)
94                 return rc;
95
96         if (val < 1 || val > OSC_MAX_RIF_MAX)
97                 return -ERANGE;
98
99         spin_lock(&cli->cl_loi_list_lock);
100         cli->cl_max_rpcs_in_flight = val;
101         spin_unlock(&cli->cl_loi_list_lock);
102
103         return count;
104 }
105
106 int osc_rd_max_dirty_mb(char *page, char **start, off_t off, int count,
107                         int *eof, void *data)
108 {
109         struct obd_device *dev = data;
110         struct client_obd *cli = &dev->u.cli;
111         unsigned val;
112
113         spin_lock(&cli->cl_loi_list_lock);
114         val = cli->cl_dirty_max >> 20;
115         spin_unlock(&cli->cl_loi_list_lock);
116
117         return snprintf(page, count, "%u\n", val);
118 }
119
120 int osc_wr_max_dirty_mb(struct file *file, const char *buffer,
121                         unsigned long count, void *data)
122 {
123         struct obd_device *dev = data;
124         struct client_obd *cli = &dev->u.cli;
125         int val, rc;
126
127         rc = lprocfs_write_helper(buffer, count, &val);
128         if (rc)
129                 return rc;
130
131         if (val < 0 || val > OSC_MAX_DIRTY_MB_MAX ||
132             val > num_physpages >> (20 - PAGE_SHIFT - 2)) /* 1/4 of RAM */
133                 return -ERANGE;
134
135         spin_lock(&cli->cl_loi_list_lock);
136         cli->cl_dirty_max = (obd_count)val * 1024 * 1024;
137         osc_wake_cache_waiters(cli);
138         spin_unlock(&cli->cl_loi_list_lock);
139
140         return count;
141 }
142
143 int osc_rd_cur_dirty_bytes(char *page, char **start, off_t off, int count,
144                            int *eof, void *data)
145 {
146         struct obd_device *dev = data;
147         struct client_obd *cli = &dev->u.cli;
148         int rc;
149
150         spin_lock(&cli->cl_loi_list_lock);
151         rc = snprintf(page, count, "%lu\n", cli->cl_dirty);
152         spin_unlock(&cli->cl_loi_list_lock);
153         return rc;
154 }
155
156 int osc_rd_cur_grant_bytes(char *page, char **start, off_t off, int count,
157                            int *eof, void *data)
158 {
159         struct obd_device *dev = data;
160         struct client_obd *cli = &dev->u.cli;
161         int rc;
162
163         spin_lock(&cli->cl_loi_list_lock);
164         rc = snprintf(page, count, "%lu\n", cli->cl_avail_grant);
165         spin_unlock(&cli->cl_loi_list_lock);
166         return rc;
167 }
168
169 static struct lprocfs_vars lprocfs_obd_vars[] = {
170         { "uuid",            lprocfs_rd_uuid,        0, 0 },
171         { "blocksize",       lprocfs_rd_blksize,     0, 0 },
172         { "kbytestotal",     lprocfs_rd_kbytestotal, 0, 0 },
173         { "kbytesfree",      lprocfs_rd_kbytesfree,  0, 0 },
174         { "kbytesavail",     lprocfs_rd_kbytesavail, 0, 0 },
175         { "filestotal",      lprocfs_rd_filestotal,  0, 0 },
176         { "filesfree",       lprocfs_rd_filesfree,   0, 0 },
177         //{ "filegroups",      lprocfs_rd_filegroups,  0, 0 },
178         { "ost_server_uuid", lprocfs_rd_server_uuid, 0, 0 },
179         { "ost_conn_uuid",   lprocfs_rd_conn_uuid, 0, 0 },
180         { "max_pages_per_rpc", osc_rd_max_pages_per_rpc,
181                                osc_wr_max_pages_per_rpc, 0 },
182         { "max_rpcs_in_flight", osc_rd_max_rpcs_in_flight,
183                                 osc_wr_max_rpcs_in_flight, 0 },
184         { "max_dirty_mb", osc_rd_max_dirty_mb, osc_wr_max_dirty_mb, 0 },
185         { "cur_dirty_bytes", osc_rd_cur_dirty_bytes, 0, 0 },
186         { "cur_grant_bytes", osc_rd_cur_grant_bytes, 0, 0 },
187         { 0 }
188 };
189
190 static struct lprocfs_vars lprocfs_module_vars[] = {
191         { "num_refs",        lprocfs_rd_numrefs,     0, 0 },
192         { 0 }
193 };
194
195 #define pct(a,b) (b ? a * 100 / b : 0)
196
197 #define PRINTF_STIME(stime) (unsigned long)(stime)->st_num,     \
198         lprocfs_stime_avg_ms(stime), lprocfs_stime_avg_us(stime)
199
200 static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
201 {
202         unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
203         struct obd_device *dev = seq->private;
204         struct client_obd *cli = &dev->u.cli;
205         unsigned long gap_av, wait_av;
206         unsigned long flags;
207         struct timeval now;
208         int i;
209
210         do_gettimeofday(&now);
211
212         spin_lock_irqsave(&cli->cl_loi_list_lock, flags);
213
214         wait_av = cli->cl_cache_wait_num ?
215                 cli->cl_cache_wait_sum / cli->cl_cache_wait_num : 0;
216         
217         gap_av = cli->cl_write_gaps ?
218                 cli->cl_write_gap_sum / cli->cl_write_gaps : 0;
219
220         seq_printf(seq, "snapshot_time:        %lu.%lu (secs.usecs)\n",
221                    now.tv_sec, now.tv_usec);
222
223         seq_printf(seq, "read RPCs in flight:  %d\n",
224                    cli->cl_r_in_flight);
225         seq_printf(seq, "write RPCs in flight: %d\n",
226                    cli->cl_w_in_flight);
227         seq_printf(seq, "pending write pages:  %d\n",
228                    cli->cl_pending_w_pages);
229         seq_printf(seq, "pending read pages:   %d\n",
230                    cli->cl_pending_r_pages);
231
232         /* cache or grant waiting stats */
233         seq_printf(seq, "write waits num:      %lu\n",
234                    cli->cl_cache_wait_num);
235         seq_printf(seq, "av. wait time:        %lu (usec)\n",
236                    wait_av);
237
238         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
239         seq_printf(seq, "pages per RPC         RPCs   %% cum %% |");
240         seq_printf(seq, "       RPCs   %% cum %%\n");
241
242         read_tot = lprocfs_oh_sum(&cli->cl_read_page_hist);
243         write_tot = lprocfs_oh_sum(&cli->cl_write_page_hist);
244
245         read_cum = 0;
246         write_cum = 0;
247         for (i = 0; i < OBD_HIST_MAX; i++) {
248                 unsigned long r = cli->cl_read_page_hist.oh_buckets[i];
249                 unsigned long w = cli->cl_write_page_hist.oh_buckets[i];
250                 read_cum += r;
251                 write_cum += w;
252                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n",
253                                  1 << i, r, pct(r, read_tot),
254                                  pct(read_cum, read_tot), w,
255                                  pct(w, write_tot),
256                                  pct(write_cum, write_tot));
257                 if (read_cum == read_tot && write_cum == write_tot)
258                         break;
259         }
260
261         /* different RPC related stats like av gap time between two write RPCs,
262          * number of sync RPCs, etc. */
263         seq_printf(seq, "\nsync RPCs:            %lu\n", cli->cl_sync_rpcs);
264         seq_printf(seq, "write gaps:           %lu\n", cli->cl_write_gaps);
265         seq_printf(seq, "av. gap time:         %lu (usec)\n", gap_av);
266         
267         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
268         seq_printf(seq, "RPCs in flight        RPCs   %% cum %% |");
269         seq_printf(seq, "       RPCs   %% cum %%\n");
270
271         read_tot = lprocfs_oh_sum(&cli->cl_read_rpc_hist);
272         write_tot = lprocfs_oh_sum(&cli->cl_write_rpc_hist);
273
274         read_cum = 0;
275         write_cum = 0;
276         for (i = 0; i < OBD_HIST_MAX; i++) {
277                 unsigned long r = cli->cl_read_rpc_hist.oh_buckets[i];
278                 unsigned long w = cli->cl_write_rpc_hist.oh_buckets[i];
279                 read_cum += r;
280                 write_cum += w;
281                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n",
282                                  i, r, pct(r, read_tot),
283                                  pct(read_cum, read_tot), w,
284                                  pct(w, write_tot),
285                                  pct(write_cum, write_tot));
286                 if (read_cum == read_tot && write_cum == write_tot)
287                         break;
288         }
289
290         seq_printf(seq, "\nRPC service time: (RPCs, average ms)\n");
291         seq_printf(seq, "\tread\t%lu\t%lu.%04lu\n",
292                         PRINTF_STIME(&cli->cl_read_stime));
293         seq_printf(seq, "\twrite\t%lu\t%lu.%04lu\n\n",
294                         PRINTF_STIME(&cli->cl_write_stime));
295
296         seq_printf(seq, "app waiting: (num, average ms)\n");
297         seq_printf(seq, "\tenter cache\t%lu\t%lu.%04lu\n",
298                         PRINTF_STIME(&cli->cl_enter_stime));
299
300         spin_unlock_irqrestore(&cli->cl_loi_list_lock, flags);
301
302         return 0;
303 }
304
305 static void *osc_rpc_stats_seq_start(struct seq_file *p, loff_t *pos)
306 {
307         if (*pos == 0)
308                 return (void *)1;
309         return NULL;
310 }
311 static void *osc_rpc_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
312 {
313         ++*pos;
314         return NULL;
315 }
316 static void osc_rpc_stats_seq_stop(struct seq_file *p, void *v)
317 {
318 }
319
320 struct seq_operations osc_rpc_stats_seq_sops = {
321         .start = osc_rpc_stats_seq_start,
322         .stop = osc_rpc_stats_seq_stop,
323         .next = osc_rpc_stats_seq_next,
324         .show = osc_rpc_stats_seq_show,
325 };
326
327 static int osc_rpc_stats_seq_open(struct inode *inode, struct file *file)
328 {
329         struct proc_dir_entry *dp = PDE(inode);
330         struct seq_file *seq;
331         int rc;
332
333         rc = seq_open(file, &osc_rpc_stats_seq_sops);
334         if (rc)
335                 return rc;
336         seq = file->private_data;
337         seq->private = dp->data;
338         return 0;
339 }
340
341 static ssize_t osc_rpc_stats_seq_write(struct file *file, const char *buf,
342                                        size_t len, loff_t *off)
343 {
344         struct seq_file *seq = file->private_data;
345         struct obd_device *dev = seq->private;
346         struct client_obd *cli = &dev->u.cli;
347
348         lprocfs_oh_clear(&cli->cl_read_rpc_hist);
349         lprocfs_oh_clear(&cli->cl_write_rpc_hist);
350         lprocfs_oh_clear(&cli->cl_read_page_hist);
351         lprocfs_oh_clear(&cli->cl_write_page_hist);
352
353         memset(&cli->cl_read_stime, 0, sizeof(cli->cl_read_stime));
354         memset(&cli->cl_write_stime, 0, sizeof(cli->cl_write_stime));
355         memset(&cli->cl_enter_stime, 0, sizeof(cli->cl_enter_stime));
356
357         cli->cl_cache_wait_num = 0;
358         cli->cl_cache_wait_sum = 0;
359         cli->cl_write_gap_sum = 0;
360         cli->cl_write_gaps = 0;
361         cli->cl_write_num = 0;
362         cli->cl_read_num = 0;
363
364         return len;
365 }
366
367 struct file_operations osc_rpc_stats_fops = {
368         .owner   = THIS_MODULE,
369         .open    = osc_rpc_stats_seq_open,
370         .read    = seq_read,
371         .write   = osc_rpc_stats_seq_write,
372         .llseek  = seq_lseek,
373         .release = seq_release,
374 };
375
376 /* cache stats */
377 static int osc_cache_stats_seq_show(struct seq_file *seq, void *v)
378 {
379         struct obd_device *dev = seq->private;
380         struct client_obd *cli = &dev->u.cli;
381         unsigned long flags;
382         struct timeval now;
383
384         do_gettimeofday(&now);
385
386         spin_lock_irqsave(&cli->cl_loi_list_lock, flags);
387
388         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
389                    now.tv_sec, now.tv_usec);
390
391         seq_printf(seq, "cache size:            %lu (b)\n", cli->cl_dirty_max);
392         seq_printf(seq, "max loading:           %lu (b)\n", cli->cl_dirty_dmax);
393         seq_printf(seq, "min loading:           %lu (b)\n", cli->cl_dirty_dmin);
394         seq_printf(seq, "av. cache loading:     %lu (b)\n", cli->cl_dirty_av);
395
396         seq_printf(seq, "\nav. loading ratio:     %lu%%\n",
397                    pct(cli->cl_dirty_av, cli->cl_dirty_max));
398         seq_printf(seq, "max loading ratio:     %lu%%\n",
399                    pct(cli->cl_dirty_dmax, cli->cl_dirty_max));
400
401         spin_unlock_irqrestore(&cli->cl_loi_list_lock, flags);
402         
403         return 0;
404 }
405 #undef pct
406
407 static void *osc_cache_stats_seq_start(struct seq_file *p, loff_t *pos)
408 {
409         if (*pos == 0)
410                 return (void *)1;
411         return NULL;
412 }
413 static void *osc_cache_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
414 {
415         ++*pos;
416         return NULL;
417 }
418 static void osc_cache_stats_seq_stop(struct seq_file *p, void *v)
419 {
420 }
421
422 struct seq_operations osc_cache_stats_seq_sops = {
423         .start = osc_cache_stats_seq_start,
424         .stop = osc_cache_stats_seq_stop,
425         .next = osc_cache_stats_seq_next,
426         .show = osc_cache_stats_seq_show,
427 };
428
429 static int osc_cache_stats_seq_open(struct inode *inode, struct file *file)
430 {
431         struct proc_dir_entry *dp = PDE(inode);
432         struct seq_file *seq;
433         int rc;
434
435         rc = seq_open(file, &osc_cache_stats_seq_sops);
436         if (rc)
437                 return rc;
438         seq = file->private_data;
439         seq->private = dp->data;
440         return 0;
441 }
442
443 static ssize_t osc_cache_stats_seq_write(struct file *file, const char *buf,
444                                          size_t len, loff_t *off)
445 {
446         struct seq_file *seq = file->private_data;
447         struct obd_device *dev = seq->private;
448         struct client_obd *cli = &dev->u.cli;
449
450         cli->cl_dirty_num = 0;
451         cli->cl_dirty_sum = 0;
452         cli->cl_dirty_av = 0;
453         cli->cl_dirty_dmax = 0;
454         cli->cl_dirty_dmin = 0;
455
456         return len;
457 }
458
459 struct file_operations osc_cache_stats_fops = {
460         .owner   = THIS_MODULE,
461         .open    = osc_cache_stats_seq_open,
462         .read    = seq_read,
463         .write   = osc_cache_stats_seq_write,
464         .llseek  = seq_lseek,
465         .release = seq_release,
466 };
467
468 int lproc_osc_attach_seqstat(struct obd_device *dev)
469 {
470         int rc;
471         
472         rc = lprocfs_obd_seq_create(dev, "rpc_stats", 0444,
473                                     &osc_rpc_stats_fops, dev);
474         if (rc) {
475                 CERROR("can't init \"rpc_stats\", err %d\n", rc);
476                 return rc;
477         }
478
479         rc = lprocfs_obd_seq_create(dev, "cache_stats", 0444,
480                                     &osc_cache_stats_fops, dev);
481         if (rc)
482                 CERROR("can't init \"cache_stats\", err %d\n", rc);
483
484         return rc;
485 }
486
487 #endif /* LPROCFS */
488 LPROCFS_INIT_VARS(osc, lprocfs_module_vars, lprocfs_obd_vars)