2 * Copyright (c) 2008 Mellanox Technologies Ltd. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <linux/proc_fs.h>
34 #include <rdma/sdp_socket.h>
39 #define PROC_SDP_STATS "sdpstats"
40 #define PROC_SDP_PERF "sdpprf"
42 /* just like TCP fs */
43 struct sdp_seq_afinfo {
47 int (*seq_show) (struct seq_file *m, void *v);
48 struct file_operations *seq_fops;
51 struct sdp_iter_state {
54 struct seq_operations seq_ops;
57 static void *sdp_get_idx(struct seq_file *seq, loff_t pos)
62 if (!list_empty(&sock_list))
63 list_for_each_entry(ssk, &sock_list, sock_list) {
72 static void *sdp_seq_start(struct seq_file *seq, loff_t *pos)
75 struct sdp_iter_state *st = seq->private;
80 return SEQ_START_TOKEN;
82 spin_lock_irq(&sock_list_lock);
83 start = sdp_get_idx(seq, *pos - 1);
85 sock_hold((struct socket *)start, SOCK_REF_SEQ);
86 spin_unlock_irq(&sock_list_lock);
91 static void *sdp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
93 struct sdp_iter_state *st = seq->private;
96 spin_lock_irq(&sock_list_lock);
97 if (v == SEQ_START_TOKEN)
98 next = sdp_get_idx(seq, 0);
100 next = sdp_get_idx(seq, *pos);
102 sock_hold((struct socket *)next, SOCK_REF_SEQ);
103 spin_unlock_irq(&sock_list_lock);
111 static void sdp_seq_stop(struct seq_file *seq, void *v)
117 static int sdp_seq_show(struct seq_file *seq, void *v)
119 struct sdp_iter_state *st;
120 struct socket *sk = v;
121 char tmpbuf[TMPSZ + 1];
128 __u32 rx_queue, tx_queue;
130 if (v == SEQ_START_TOKEN) {
131 seq_printf(seq, "%-*s\n", TMPSZ - 1,
132 " sl local_address rem_address "
133 "uid inode rx_queue tx_queue state");
139 dest = inet_sk(sk)->daddr;
140 src = inet_sk(sk)->rcv_saddr;
141 destp = ntohs(inet_sk(sk)->dport);
142 srcp = ntohs(inet_sk(sk)->sport);
143 uid = sock_i_uid(sk);
144 inode = sock_i_ino(sk);
145 rx_queue = rcv_nxt(sdp_sk(sk)) - sdp_sk(sk)->copied_seq;
146 tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq;
148 sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %5d %lu %08X:%08X %X",
149 st->num, src, srcp, dest, destp, uid, inode,
150 rx_queue, tx_queue, sk->sk_state);
152 seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);
154 sock_put(sk, SOCK_REF_SEQ);
159 static int sdp_seq_open(struct inode *inode, struct file *file)
161 struct sdp_seq_afinfo *afinfo = PDE(inode)->data;
162 struct seq_file *seq;
163 struct sdp_iter_state *s;
166 if (unlikely(afinfo == NULL))
169 /* Workaround bogus warning by memtrack */
170 #define _kzalloc(size,flags) kzalloc(size,flags)
172 s = kzalloc(sizeof(*s), GFP_KERNEL);
173 #define kzalloc(s,f) _kzalloc(s,f)
176 s->family = afinfo->family;
177 s->seq_ops.start = sdp_seq_start;
178 s->seq_ops.next = sdp_seq_next;
179 s->seq_ops.show = afinfo->seq_show;
180 s->seq_ops.stop = sdp_seq_stop;
182 rc = seq_open(file, &s->seq_ops);
185 seq = file->private_data;
195 static struct file_operations sdp_seq_fops;
196 static struct sdp_seq_afinfo sdp_seq_afinfo = {
197 .owner = THIS_MODULE,
199 .family = AF_INET_SDP,
200 .seq_show = sdp_seq_show,
201 .seq_fops = &sdp_seq_fops,
205 DEFINE_PER_CPU(struct sdpstats, sdpstats);
207 static void sdpstats_seq_hist(struct seq_file *seq, char *str, u32 *h, int n,
213 seq_printf(seq, "%s:\n", str);
215 for (i = 0; i < n; i++) {
221 seq_printf(seq, " - all values are 0\n");
225 for (i = 0; i < n; i++) {
227 int j = 50 * h[i] / max;
228 int val = is_log ? (i == n-1 ? 0 : 1<<i) : i;
232 seq_printf(seq, "%10d | %-50s - %d\n", val, s, h[i]);
236 #define SDPSTATS_COUNTER_GET(var) ({ \
239 for_each_possible_cpu(__i) \
240 __val += per_cpu(sdpstats, __i).var; \
244 #define SDPSTATS_HIST_GET(hist, hist_len, sum) ({ \
246 for_each_possible_cpu(__i) { \
248 u32 *h = per_cpu(sdpstats, __i).hist; \
249 for (__j = 0; __j < hist_len; __j++) { \
250 sum[__j] += h[__j]; \
255 #define __sdpstats_seq_hist(seq, msg, hist, is_log) ({ \
256 u32 tmp_hist[SDPSTATS_MAX_HIST_SIZE]; \
257 int hist_len = ARRAY_SIZE(__get_cpu_var(sdpstats).hist);\
258 memset(tmp_hist, 0, sizeof(tmp_hist)); \
259 SDPSTATS_HIST_GET(hist, hist_len, tmp_hist); \
260 sdpstats_seq_hist(seq, msg, tmp_hist, hist_len, is_log);\
263 static int sdpstats_seq_show(struct seq_file *seq, void *v)
267 seq_printf(seq, "SDP statistics:\n");
269 __sdpstats_seq_hist(seq, "sendmsg_seglen", sendmsg_seglen, 1);
270 __sdpstats_seq_hist(seq, "send_size", send_size, 1);
271 __sdpstats_seq_hist(seq, "credits_before_update",
272 credits_before_update, 0);
274 seq_printf(seq, "sdp_sendmsg() calls\t\t: %d\n",
275 SDPSTATS_COUNTER_GET(sendmsg));
276 seq_printf(seq, "bcopy segments \t\t: %d\n",
277 SDPSTATS_COUNTER_GET(sendmsg_bcopy_segment));
278 seq_printf(seq, "bzcopy segments \t\t: %d\n",
279 SDPSTATS_COUNTER_GET(sendmsg_bzcopy_segment));
280 seq_printf(seq, "zcopy segments \t\t: %d\n",
281 SDPSTATS_COUNTER_GET(sendmsg_zcopy_segment));
282 seq_printf(seq, "post_send_credits \t\t: %d\n",
283 SDPSTATS_COUNTER_GET(post_send_credits));
284 seq_printf(seq, "memcpy_count \t\t: %u\n",
285 SDPSTATS_COUNTER_GET(memcpy_count));
287 for (i = 0; i < ARRAY_SIZE(__get_cpu_var(sdpstats).post_send); i++) {
289 seq_printf(seq, "post_send %-20s\t: %d\n",
291 SDPSTATS_COUNTER_GET(post_send[i]));
295 seq_printf(seq, "\n");
296 seq_printf(seq, "post_recv \t\t: %d\n",
297 SDPSTATS_COUNTER_GET(post_recv));
298 seq_printf(seq, "BZCopy poll miss \t\t: %d\n",
299 SDPSTATS_COUNTER_GET(bzcopy_poll_miss));
300 seq_printf(seq, "send_wait_for_mem \t\t: %d\n",
301 SDPSTATS_COUNTER_GET(send_wait_for_mem));
302 seq_printf(seq, "send_miss_no_credits\t\t: %d\n",
303 SDPSTATS_COUNTER_GET(send_miss_no_credits));
305 seq_printf(seq, "rx_poll_miss \t\t: %d\n", SDPSTATS_COUNTER_GET(rx_poll_miss));
306 seq_printf(seq, "tx_poll_miss \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_miss));
307 seq_printf(seq, "tx_poll_busy \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_busy));
308 seq_printf(seq, "tx_poll_hit \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_hit));
310 seq_printf(seq, "CQ stats:\n");
311 seq_printf(seq, "- RX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(rx_int_count));
312 seq_printf(seq, "- TX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(tx_int_count));
314 seq_printf(seq, "ZCopy stats:\n");
315 seq_printf(seq, "- TX timeout\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_timeout));
316 seq_printf(seq, "- TX cross send\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_cross_send));
317 seq_printf(seq, "- TX aborted by peer\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_aborted));
318 seq_printf(seq, "- TX error\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_error));
322 static ssize_t sdpstats_write(struct file *file, const char __user *buf,
323 size_t count, loff_t *offs)
327 for_each_possible_cpu(i)
328 memset(&per_cpu(sdpstats, i), 0, sizeof(struct sdpstats));
329 printk(KERN_WARNING "Cleared sdp statistics\n");
334 static int sdpstats_seq_open(struct inode *inode, struct file *file)
336 return single_open(file, sdpstats_seq_show, NULL);
339 static struct file_operations sdpstats_fops = {
340 .owner = THIS_MODULE,
341 .open = sdpstats_seq_open,
343 .write = sdpstats_write,
345 .release = single_release,
351 struct sdpprf_log sdpprf_log[SDPPRF_LOG_SIZE];
352 int sdpprf_log_count;
354 static unsigned long long start_t;
356 static int sdpprf_show(struct seq_file *m, void *v)
358 struct sdpprf_log *l = v;
359 unsigned long nsec_rem, t;
361 if (!sdpprf_log_count) {
362 seq_printf(m, "No performance logs\n");
366 t = l->time - start_t;
367 nsec_rem = do_div(t, 1000000000);
369 seq_printf(m, "%-6d: [%5lu.%06lu] %-50s - [%d{%d} %d:%d] "
371 l->idx, (unsigned long)t, nsec_rem/1000,
372 l->msg, l->pid, l->cpu, l->sk_num, l->sk_dport,
373 l->mb, l->func, l->line);
378 static void *sdpprf_start(struct seq_file *p, loff_t *pos)
383 if (!sdpprf_log_count)
384 return SEQ_START_TOKEN;
387 if (*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1))
390 if (sdpprf_log_count >= SDPPRF_LOG_SIZE - 1) {
391 int off = sdpprf_log_count & (SDPPRF_LOG_SIZE - 1);
392 idx = (idx + off) & (SDPPRF_LOG_SIZE - 1);
397 start_t = sdpprf_log[idx].time;
398 return &sdpprf_log[idx];
401 static void *sdpprf_next(struct seq_file *p, void *v, loff_t *pos)
403 struct sdpprf_log *l = v;
405 if (++*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1))
409 if (l - &sdpprf_log[0] >= SDPPRF_LOG_SIZE - 1)
410 return &sdpprf_log[0];
415 static void sdpprf_stop(struct seq_file *p, void *v)
419 static struct seq_operations sdpprf_ops = {
420 .start = sdpprf_start,
426 static int sdpprf_open(struct inode *inode, struct file *file)
430 res = seq_open(file, &sdpprf_ops);
435 static ssize_t sdpprf_write(struct file *file, const char __user *buf,
436 size_t count, loff_t *offs)
438 sdpprf_log_count = 0;
439 printk(KERN_INFO "Cleared sdpprf statistics\n");
444 static struct file_operations sdpprf_fops = {
448 .release = seq_release,
449 .write = sdpprf_write,
451 #endif /* SDP_PROFILING */
453 int __init sdp_proc_init(void)
455 struct proc_dir_entry *p = NULL;
457 struct proc_dir_entry *stats = NULL;
460 struct proc_dir_entry *prof = NULL;
463 sdp_seq_afinfo.seq_fops->owner = sdp_seq_afinfo.owner;
464 sdp_seq_afinfo.seq_fops->open = sdp_seq_open;
465 sdp_seq_afinfo.seq_fops->read = seq_read;
466 sdp_seq_afinfo.seq_fops->llseek = seq_lseek;
467 sdp_seq_afinfo.seq_fops->release = seq_release_private;
469 p = proc_net_fops_create(&init_net, sdp_seq_afinfo.name, S_IRUGO,
470 sdp_seq_afinfo.seq_fops);
472 p->data = &sdp_seq_afinfo;
478 stats = proc_net_fops_create(&init_net, PROC_SDP_STATS,
479 S_IRUGO | S_IWUGO, &sdpstats_fops);
486 prof = proc_net_fops_create(&init_net, PROC_SDP_PERF,
487 S_IRUGO | S_IWUGO, &sdpprf_fops);
499 proc_net_remove(&init_net, PROC_SDP_STATS);
503 proc_net_remove(&init_net, sdp_seq_afinfo.name);
509 void sdp_proc_unregister(void)
511 proc_net_remove(&init_net, sdp_seq_afinfo.name);
512 memset(sdp_seq_afinfo.seq_fops, 0, sizeof(*sdp_seq_afinfo.seq_fops));
515 proc_net_remove(&init_net, PROC_SDP_STATS);
518 proc_net_remove(&init_net, PROC_SDP_PERF);
522 #else /* CONFIG_PROC_FS */
524 int __init sdp_proc_init(void)
529 void sdp_proc_unregister(void)
533 #endif /* CONFIG_PROC_FS */