Current Path : /sys/ofed/drivers/infiniband/ulp/sdp/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //sys/ofed/drivers/infiniband/ulp/sdp/sdp_proc.c |
/* * Copyright (c) 2008 Mellanox Technologies Ltd. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <linux/proc_fs.h> #include <rdma/sdp_socket.h> #include "sdp.h" #ifdef CONFIG_PROC_FS #define PROC_SDP_STATS "sdpstats" #define PROC_SDP_PERF "sdpprf" /* just like TCP fs */ struct sdp_seq_afinfo { struct module *owner; char *name; sa_family_t family; int (*seq_show) (struct seq_file *m, void *v); struct file_operations *seq_fops; }; struct sdp_iter_state { sa_family_t family; int num; struct seq_operations seq_ops; }; static void *sdp_get_idx(struct seq_file *seq, loff_t pos) { int i = 0; struct sdp_sock *ssk; if (!list_empty(&sock_list)) list_for_each_entry(ssk, &sock_list, sock_list) { if (i == pos) return ssk; i++; } return NULL; } static void *sdp_seq_start(struct seq_file *seq, loff_t *pos) { void *start = NULL; struct sdp_iter_state *st = seq->private; st->num = 0; if (!*pos) return SEQ_START_TOKEN; spin_lock_irq(&sock_list_lock); start = sdp_get_idx(seq, *pos - 1); if (start) sock_hold((struct socket *)start, SOCK_REF_SEQ); spin_unlock_irq(&sock_list_lock); return start; } static void *sdp_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct sdp_iter_state *st = seq->private; void *next = NULL; spin_lock_irq(&sock_list_lock); if (v == SEQ_START_TOKEN) next = sdp_get_idx(seq, 0); else next = sdp_get_idx(seq, *pos); if (next) sock_hold((struct socket *)next, SOCK_REF_SEQ); spin_unlock_irq(&sock_list_lock); *pos += 1; st->num++; return next; } static void sdp_seq_stop(struct seq_file *seq, void *v) { } #define TMPSZ 150 static int sdp_seq_show(struct seq_file *seq, void *v) { struct sdp_iter_state *st; struct socket *sk = v; char tmpbuf[TMPSZ + 1]; unsigned int dest; unsigned int src; int uid; unsigned long inode; __u16 destp; __u16 srcp; __u32 rx_queue, tx_queue; if (v == SEQ_START_TOKEN) { seq_printf(seq, "%-*s\n", TMPSZ - 1, " sl local_address rem_address " "uid inode rx_queue tx_queue state"); goto out; } st = seq->private; dest = inet_sk(sk)->daddr; src = inet_sk(sk)->rcv_saddr; destp = ntohs(inet_sk(sk)->dport); srcp = ntohs(inet_sk(sk)->sport); uid = sock_i_uid(sk); inode = sock_i_ino(sk); rx_queue = rcv_nxt(sdp_sk(sk)) - sdp_sk(sk)->copied_seq; tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq; sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %5d %lu %08X:%08X %X", st->num, src, srcp, dest, destp, uid, inode, rx_queue, tx_queue, sk->sk_state); seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf); sock_put(sk, SOCK_REF_SEQ); out: return 0; } static int sdp_seq_open(struct inode *inode, struct file *file) { struct sdp_seq_afinfo *afinfo = PDE(inode)->data; struct seq_file *seq; struct sdp_iter_state *s; int rc; if (unlikely(afinfo == NULL)) return -EINVAL; /* Workaround bogus warning by memtrack */ #define _kzalloc(size,flags) kzalloc(size,flags) #undef kzalloc s = kzalloc(sizeof(*s), GFP_KERNEL); #define kzalloc(s,f) _kzalloc(s,f) if (!s) return -ENOMEM; s->family = afinfo->family; s->seq_ops.start = sdp_seq_start; s->seq_ops.next = sdp_seq_next; s->seq_ops.show = afinfo->seq_show; s->seq_ops.stop = sdp_seq_stop; rc = seq_open(file, &s->seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s; out: return rc; out_kfree: kfree(s); goto out; } static struct file_operations sdp_seq_fops; static struct sdp_seq_afinfo sdp_seq_afinfo = { .owner = THIS_MODULE, .name = "sdp", .family = AF_INET_SDP, .seq_show = sdp_seq_show, .seq_fops = &sdp_seq_fops, }; #ifdef SDPSTATS_ON DEFINE_PER_CPU(struct sdpstats, sdpstats); static void sdpstats_seq_hist(struct seq_file *seq, char *str, u32 *h, int n, int is_log) { int i; u32 max = 0; seq_printf(seq, "%s:\n", str); for (i = 0; i < n; i++) { if (h[i] > max) max = h[i]; } if (max == 0) { seq_printf(seq, " - all values are 0\n"); return; } for (i = 0; i < n; i++) { char s[51]; int j = 50 * h[i] / max; int val = is_log ? (i == n-1 ? 0 : 1<<i) : i; memset(s, '*', j); s[j] = '\0'; seq_printf(seq, "%10d | %-50s - %d\n", val, s, h[i]); } } #define SDPSTATS_COUNTER_GET(var) ({ \ u32 __val = 0; \ unsigned int __i; \ for_each_possible_cpu(__i) \ __val += per_cpu(sdpstats, __i).var; \ __val; \ }) #define SDPSTATS_HIST_GET(hist, hist_len, sum) ({ \ unsigned int __i; \ for_each_possible_cpu(__i) { \ unsigned int __j; \ u32 *h = per_cpu(sdpstats, __i).hist; \ for (__j = 0; __j < hist_len; __j++) { \ sum[__j] += h[__j]; \ } \ } \ }) #define __sdpstats_seq_hist(seq, msg, hist, is_log) ({ \ u32 tmp_hist[SDPSTATS_MAX_HIST_SIZE]; \ int hist_len = ARRAY_SIZE(__get_cpu_var(sdpstats).hist);\ memset(tmp_hist, 0, sizeof(tmp_hist)); \ SDPSTATS_HIST_GET(hist, hist_len, tmp_hist); \ sdpstats_seq_hist(seq, msg, tmp_hist, hist_len, is_log);\ }) static int sdpstats_seq_show(struct seq_file *seq, void *v) { int i; seq_printf(seq, "SDP statistics:\n"); __sdpstats_seq_hist(seq, "sendmsg_seglen", sendmsg_seglen, 1); __sdpstats_seq_hist(seq, "send_size", send_size, 1); __sdpstats_seq_hist(seq, "credits_before_update", credits_before_update, 0); seq_printf(seq, "sdp_sendmsg() calls\t\t: %d\n", SDPSTATS_COUNTER_GET(sendmsg)); seq_printf(seq, "bcopy segments \t\t: %d\n", SDPSTATS_COUNTER_GET(sendmsg_bcopy_segment)); seq_printf(seq, "bzcopy segments \t\t: %d\n", SDPSTATS_COUNTER_GET(sendmsg_bzcopy_segment)); seq_printf(seq, "zcopy segments \t\t: %d\n", SDPSTATS_COUNTER_GET(sendmsg_zcopy_segment)); seq_printf(seq, "post_send_credits \t\t: %d\n", SDPSTATS_COUNTER_GET(post_send_credits)); seq_printf(seq, "memcpy_count \t\t: %u\n", SDPSTATS_COUNTER_GET(memcpy_count)); for (i = 0; i < ARRAY_SIZE(__get_cpu_var(sdpstats).post_send); i++) { if (mid2str(i)) { seq_printf(seq, "post_send %-20s\t: %d\n", mid2str(i), SDPSTATS_COUNTER_GET(post_send[i])); } } seq_printf(seq, "\n"); seq_printf(seq, "post_recv \t\t: %d\n", SDPSTATS_COUNTER_GET(post_recv)); seq_printf(seq, "BZCopy poll miss \t\t: %d\n", SDPSTATS_COUNTER_GET(bzcopy_poll_miss)); seq_printf(seq, "send_wait_for_mem \t\t: %d\n", SDPSTATS_COUNTER_GET(send_wait_for_mem)); seq_printf(seq, "send_miss_no_credits\t\t: %d\n", SDPSTATS_COUNTER_GET(send_miss_no_credits)); seq_printf(seq, "rx_poll_miss \t\t: %d\n", SDPSTATS_COUNTER_GET(rx_poll_miss)); seq_printf(seq, "tx_poll_miss \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_miss)); seq_printf(seq, "tx_poll_busy \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_busy)); seq_printf(seq, "tx_poll_hit \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_hit)); seq_printf(seq, "CQ stats:\n"); seq_printf(seq, "- RX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(rx_int_count)); seq_printf(seq, "- TX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(tx_int_count)); seq_printf(seq, "ZCopy stats:\n"); seq_printf(seq, "- TX timeout\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_timeout)); seq_printf(seq, "- TX cross send\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_cross_send)); seq_printf(seq, "- TX aborted by peer\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_aborted)); seq_printf(seq, "- TX error\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_error)); return 0; } static ssize_t sdpstats_write(struct file *file, const char __user *buf, size_t count, loff_t *offs) { int i; for_each_possible_cpu(i) memset(&per_cpu(sdpstats, i), 0, sizeof(struct sdpstats)); printk(KERN_WARNING "Cleared sdp statistics\n"); return count; } static int sdpstats_seq_open(struct inode *inode, struct file *file) { return single_open(file, sdpstats_seq_show, NULL); } static struct file_operations sdpstats_fops = { .owner = THIS_MODULE, .open = sdpstats_seq_open, .read = seq_read, .write = sdpstats_write, .llseek = seq_lseek, .release = single_release, }; #endif #ifdef SDP_PROFILING struct sdpprf_log sdpprf_log[SDPPRF_LOG_SIZE]; int sdpprf_log_count; static unsigned long long start_t; static int sdpprf_show(struct seq_file *m, void *v) { struct sdpprf_log *l = v; unsigned long nsec_rem, t; if (!sdpprf_log_count) { seq_printf(m, "No performance logs\n"); goto out; } t = l->time - start_t; nsec_rem = do_div(t, 1000000000); seq_printf(m, "%-6d: [%5lu.%06lu] %-50s - [%d{%d} %d:%d] " "mb: %p %s:%d\n", l->idx, (unsigned long)t, nsec_rem/1000, l->msg, l->pid, l->cpu, l->sk_num, l->sk_dport, l->mb, l->func, l->line); out: return 0; } static void *sdpprf_start(struct seq_file *p, loff_t *pos) { int idx = *pos; if (!*pos) { if (!sdpprf_log_count) return SEQ_START_TOKEN; } if (*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1)) return NULL; if (sdpprf_log_count >= SDPPRF_LOG_SIZE - 1) { int off = sdpprf_log_count & (SDPPRF_LOG_SIZE - 1); idx = (idx + off) & (SDPPRF_LOG_SIZE - 1); } if (!start_t) start_t = sdpprf_log[idx].time; return &sdpprf_log[idx]; } static void *sdpprf_next(struct seq_file *p, void *v, loff_t *pos) { struct sdpprf_log *l = v; if (++*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1)) return NULL; ++l; if (l - &sdpprf_log[0] >= SDPPRF_LOG_SIZE - 1) return &sdpprf_log[0]; return l; } static void sdpprf_stop(struct seq_file *p, void *v) { } static struct seq_operations sdpprf_ops = { .start = sdpprf_start, .stop = sdpprf_stop, .next = sdpprf_next, .show = sdpprf_show, }; static int sdpprf_open(struct inode *inode, struct file *file) { int res; res = seq_open(file, &sdpprf_ops); return res; } static ssize_t sdpprf_write(struct file *file, const char __user *buf, size_t count, loff_t *offs) { sdpprf_log_count = 0; printk(KERN_INFO "Cleared sdpprf statistics\n"); return count; } static struct file_operations sdpprf_fops = { .open = sdpprf_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, .write = sdpprf_write, }; #endif /* SDP_PROFILING */ int __init sdp_proc_init(void) { struct proc_dir_entry *p = NULL; #ifdef SDPSTATS_ON struct proc_dir_entry *stats = NULL; #endif #ifdef SDP_PROFILING struct proc_dir_entry *prof = NULL; #endif sdp_seq_afinfo.seq_fops->owner = sdp_seq_afinfo.owner; sdp_seq_afinfo.seq_fops->open = sdp_seq_open; sdp_seq_afinfo.seq_fops->read = seq_read; sdp_seq_afinfo.seq_fops->llseek = seq_lseek; sdp_seq_afinfo.seq_fops->release = seq_release_private; p = proc_net_fops_create(&init_net, sdp_seq_afinfo.name, S_IRUGO, sdp_seq_afinfo.seq_fops); if (p) p->data = &sdp_seq_afinfo; else goto no_mem; #ifdef SDPSTATS_ON stats = proc_net_fops_create(&init_net, PROC_SDP_STATS, S_IRUGO | S_IWUGO, &sdpstats_fops); if (!stats) goto no_mem_stats; #endif #ifdef SDP_PROFILING prof = proc_net_fops_create(&init_net, PROC_SDP_PERF, S_IRUGO | S_IWUGO, &sdpprf_fops); if (!prof) goto no_mem_prof; #endif return 0; #ifdef SDP_PROFILING no_mem_prof: #endif #ifdef SDPSTATS_ON proc_net_remove(&init_net, PROC_SDP_STATS); no_mem_stats: #endif proc_net_remove(&init_net, sdp_seq_afinfo.name); no_mem: return -ENOMEM; } void sdp_proc_unregister(void) { proc_net_remove(&init_net, sdp_seq_afinfo.name); memset(sdp_seq_afinfo.seq_fops, 0, sizeof(*sdp_seq_afinfo.seq_fops)); #ifdef SDPSTATS_ON proc_net_remove(&init_net, PROC_SDP_STATS); #endif #ifdef SDP_PROFILING proc_net_remove(&init_net, PROC_SDP_PERF); #endif } #else /* CONFIG_PROC_FS */ int __init sdp_proc_init(void) { return 0; } void sdp_proc_unregister(void) { } #endif /* CONFIG_PROC_FS */