[ofa-general] [PATCH] sdp: add /proc/net/sdpstats + packets dump
Amir Vadai
amirv at mellanox.co.il
Mon Jun 22 01:18:41 PDT 2009
* statistics infrastructure for sdp
* RX/TX packets dumps
Signed-off-by: Amir Vadai <amirv at mellanox.co.il>
---
drivers/infiniband/ulp/sdp/Makefile | 2 +-
drivers/infiniband/ulp/sdp/sdp.h | 108 +++++++++-
drivers/infiniband/ulp/sdp/sdp_bcopy.c | 80 +++++++-
drivers/infiniband/ulp/sdp/sdp_cma.c | 36 +---
drivers/infiniband/ulp/sdp/sdp_main.c | 217 ++-----------------
drivers/infiniband/ulp/sdp/sdp_proc.c | 358 ++++++++++++++++++++++++++++++++
6 files changed, 569 insertions(+), 232 deletions(-)
create mode 100644 drivers/infiniband/ulp/sdp/sdp_proc.c
diff --git a/drivers/infiniband/ulp/sdp/Makefile b/drivers/infiniband/ulp/sdp/Makefile
index c889cce..5da4b7b 100644
--- a/drivers/infiniband/ulp/sdp/Makefile
+++ b/drivers/infiniband/ulp/sdp/Makefile
@@ -3,4 +3,4 @@ EXTRA_CFLAGS += -ggdb
obj-$(CONFIG_INFINIBAND_SDP) += ib_sdp.o
-ib_sdp-objs := sdp_main.o sdp_cma.o sdp_bcopy.o
+ib_sdp-objs := sdp_main.o sdp_cma.o sdp_bcopy.o sdp_proc.o
diff --git a/drivers/infiniband/ulp/sdp/sdp.h b/drivers/infiniband/ulp/sdp/sdp.h
index f9c2421..e36f786 100644
--- a/drivers/infiniband/ulp/sdp/sdp.h
+++ b/drivers/infiniband/ulp/sdp/sdp.h
@@ -7,9 +7,12 @@
#include <net/tcp.h> /* For urgent data flags */
#include <rdma/ib_verbs.h>
+#define SDPSTATS_ON
+
#define sdp_printk(level, sk, format, arg...) \
- printk(level "%s:%d sdp_sock(%d:%d): " format, \
+ printk(level "%s:%d sdp_sock(%d %d:%d): " format, \
__func__, __LINE__, \
+ current->pid, \
(sk) ? inet_sk(sk)->num : -1, \
(sk) ? ntohs(inet_sk(sk)->dport) : -1, ## arg)
#define sdp_warn(sk, format, arg...) \
@@ -50,15 +53,72 @@ extern int sdp_debug_level;
#endif /* CONFIG_INFINIBAND_SDP_DEBUG */
#ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA
+
extern int sdp_data_debug_level;
#define sdp_dbg_data(sk, format, arg...) \
do { \
- if (sdp_data_debug_level > 0) \
+ if (sdp_data_debug_level & 0x2) \
sdp_printk(KERN_DEBUG, sk, format , ## arg); \
} while (0)
+#define SDP_DUMP_PACKET(sk, str, skb, h) \
+ do { \
+ if (sdp_data_debug_level & 0x1) \
+ dump_packet(sk, str, skb, h); \
+ } while (0)
#else
-#define sdp_dbg_data(priv, format, arg...) \
- do { (void) (priv); } while (0)
+#define sdp_dbg_data(priv, format, arg...)
+// do { (void) (priv); } while (0)
+#define SDP_DUMP_PACKET(sk, str, skb, h)
+#endif
+
+#ifdef SDPSTATS_ON
+
+struct sdpstats {
+ u32 post_send[256];
+ u32 sendmsg_bcopy_segment;
+ u32 sendmsg_bzcopy_segment;
+ u32 sendmsg;
+ u32 post_send_credits;
+ u32 sendmsg_nagle_skip;
+ u32 sendmsg_seglen[25];
+ u32 send_size[25];
+ u32 post_recv;
+ u32 rx_int_count;
+ u32 tx_int_count;
+ u32 bzcopy_poll_miss;
+ u32 send_wait_for_mem;
+ u32 send_miss_no_credits;
+ u32 rx_poll_miss;
+ u32 tx_poll_miss;
+ u32 memcpy_count;
+ u32 credits_before_update[64];
+ u32 send_interval[25];
+};
+extern struct sdpstats sdpstats;
+
+static inline void sdpstats_hist(u32 *h, u32 val, u32 maxidx, int is_log)
+{
+ int idx = is_log ? ilog2(val) : val;
+ if (idx > maxidx)
+ idx = maxidx;
+
+ h[idx]++;
+}
+
+#define SDPSTATS_COUNTER_INC(stat) do {sdpstats.stat++;} while (0)
+#define SDPSTATS_COUNTER_ADD(stat, val) do {sdpstats.stat+=val;} while (0)
+#define SDPSTATS_COUNTER_MID_INC(stat, mid) do {sdpstats.stat[mid]++;} while (0)
+#define SDPSTATS_HIST(stat, size) \
+ sdpstats_hist(sdpstats.stat, size, ARRAY_SIZE(sdpstats.stat) - 1, 1)
+
+#define SDPSTATS_HIST_LINEAR(stat, size) \
+ sdpstats_hist(sdpstats.stat, size, ARRAY_SIZE(sdpstats.stat) - 1, 0)
+
+#else
+#define SDPSTATS_COUNTER_INC(stat)
+#define SDPSTATS_COUNTER_ADD(stat, val)
+#define SDPSTATS_COUNTER_MID_INC(stat, mid)
+#define SDPSTATS_HIST(stat, size)
#endif
#define SOCK_REF_RESET "RESET"
@@ -92,6 +152,9 @@ extern int sdp_data_debug_level;
#define SDP_OP_RECV 0x800000000LL
#define SDP_OP_SEND 0x400000000LL
+extern struct list_head sock_list;
+extern spinlock_t sock_list_lock;
+
enum sdp_mid {
SDP_MID_HELLO = 0x0,
SDP_MID_HELLO_ACK = 0x1,
@@ -129,6 +192,38 @@ struct sdp_bsdh {
__u32 mseq_ack;
};
+union cma_ip_addr {
+ struct in6_addr ip6;
+ struct {
+ __u32 pad[3];
+ __u32 addr;
+ } ip4;
+};
+
+/* TODO: too much? Can I avoid having the src/dst and port here? */
+struct sdp_hh {
+ struct sdp_bsdh bsdh;
+ u8 majv_minv;
+ u8 ipv_cap;
+ u8 rsvd1;
+ u8 max_adverts;
+ __u32 desremrcvsz;
+ __u32 localrcvsz;
+ __u16 port;
+ __u16 rsvd2;
+ union cma_ip_addr src_addr;
+ union cma_ip_addr dst_addr;
+};
+
+struct sdp_hah {
+ struct sdp_bsdh bsdh;
+ u8 majv_minv;
+ u8 ipv_cap;
+ u8 rsvd1;
+ u8 ext_max_adverts;
+ __u32 actrcvsz;
+};
+
struct sdp_buf {
struct sk_buff *skb;
u64 mapping[SDP_MAX_SEND_SKB_FRAGS + 1];
@@ -329,6 +424,9 @@ static inline void sdp_set_error(struct sock *sk, int err)
extern struct workqueue_struct *sdp_workqueue;
+#ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA
+void dump_packet(struct sock *sk, char *str, struct sk_buff *skb, const struct sdp_bsdh *h);
+#endif
int sdp_cma_handler(struct rdma_cm_id *, struct rdma_cm_event *);
void sdp_reset(struct sock *sk);
void sdp_reset_sk(struct sock *sk, int rc);
@@ -354,6 +452,8 @@ void sdp_post_keepalive(struct sdp_sock *ssk);
void sdp_start_keepalive_timer(struct sock *sk);
void sdp_bzcopy_write_space(struct sdp_sock *ssk);
int sdp_init_sock(struct sock *sk);
+int __init sdp_proc_init(void);
+void sdp_proc_unregister(void);
static inline struct sk_buff *sdp_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp)
{
diff --git a/drivers/infiniband/ulp/sdp/sdp_bcopy.c b/drivers/infiniband/ulp/sdp/sdp_bcopy.c
index 475d7c3..7c7271c 100644
--- a/drivers/infiniband/ulp/sdp/sdp_bcopy.c
+++ b/drivers/infiniband/ulp/sdp/sdp_bcopy.c
@@ -186,6 +186,64 @@ void sdp_post_keepalive(struct sdp_sock *ssk)
sdp_cnt(sdp_keepalive_probes_sent);
}
+#ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA
+void dump_packet(struct sock *sk, char *str, struct sk_buff *skb, const struct sdp_bsdh *h)
+{
+ int len = 0;
+ char buf[256];
+#define ENUM2STR(e) [e] = #e
+ static char *mid2str[] = {
+ ENUM2STR(SDP_MID_HELLO),
+ ENUM2STR(SDP_MID_HELLO_ACK),
+ ENUM2STR(SDP_MID_DISCONN),
+ ENUM2STR(SDP_MID_CHRCVBUF),
+ ENUM2STR(SDP_MID_CHRCVBUF_ACK),
+ ENUM2STR(SDP_MID_DATA),
+ };
+ len += snprintf(buf, 255-len, "skb: %p mid: %2x:%-20s flags: 0x%x bufs: %d "
+ "len: %d mseq: %d mseq_ack: %d",
+ skb, h->mid, mid2str[h->mid], h->flags,
+ ntohs(h->bufs), ntohl(h->len),ntohl(h->mseq),
+ ntohl(h->mseq_ack));
+
+ switch (h->mid) {
+ case SDP_MID_HELLO:
+ {
+ const struct sdp_hh *hh = (struct sdp_hh *)h;
+ len += snprintf(buf + len, 255-len,
+ " | max_adverts: %d majv_minv: %d localrcvsz: %d "
+ "desremrcvsz: %d |",
+ hh->max_adverts,
+ hh->majv_minv,
+ ntohl(hh->localrcvsz),
+ ntohl(hh->desremrcvsz));
+ }
+ break;
+ case SDP_MID_HELLO_ACK:
+ {
+ const struct sdp_hah *hah = (struct sdp_hah *)h;
+ len += snprintf(buf + len, 255-len, " | actrcvz: %d |",
+ ntohl(hah->actrcvsz));
+ }
+ break;
+ case SDP_MID_CHRCVBUF:
+ case SDP_MID_CHRCVBUF_ACK:
+ {
+ struct sdp_chrecvbuf *req_size = (struct sdp_chrecvbuf *)(h+1);
+ len += snprintf(buf + len, 255-len,
+ " | req_size: %d |", ntohl(req_size->size));
+ }
+ break;
+ case SDP_MID_DATA:
+ len += snprintf(buf + len, 255-len, " | data_len: %ld |", ntohl(h->len) - sizeof(struct sdp_bsdh));
+ default:
+ break;
+ }
+ buf[len] = 0;
+ sdp_warn(sk, "%s: %s\n", str, buf);
+}
+#endif
+
void sdp_post_send(struct sdp_sock *ssk, struct sk_buff *skb, u8 mid)
{
struct sdp_buf *tx_req;
@@ -197,6 +255,9 @@ void sdp_post_send(struct sdp_sock *ssk, struct sk_buff *skb, u8 mid)
struct ib_sge *sge;
struct ib_send_wr *bad_wr;
+ SDPSTATS_COUNTER_MID_INC(post_send, mid);
+ SDPSTATS_HIST(send_size, skb->len);
+
h->mid = mid;
if (unlikely(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG))
h->flags = SDP_OOB_PRES | SDP_OOB_PEND;
@@ -208,6 +269,7 @@ void sdp_post_send(struct sdp_sock *ssk, struct sk_buff *skb, u8 mid)
h->mseq = htonl(mseq);
h->mseq_ack = htonl(ssk->mseq_ack);
+ SDP_DUMP_PACKET(&ssk->isk.sk, "TX", skb, h);
tx_req = &ssk->tx_ring[mseq & (SDP_TX_SIZE - 1)];
tx_req->skb = skb;
dev = ssk->ib_device;
@@ -244,6 +306,16 @@ void sdp_post_send(struct sdp_sock *ssk, struct sk_buff *skb, u8 mid)
ssk->tx_wr.send_flags = IB_SEND_SIGNALED;
if (unlikely(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG))
ssk->tx_wr.send_flags |= IB_SEND_SOLICITED;
+
+ {
+ static unsigned long last_send = 0;
+ int delta = jiffies - last_send;
+
+ if (likely(last_send))
+ SDPSTATS_HIST(send_interval, delta);
+
+ last_send = jiffies;
+ }
rc = ib_post_send(ssk->qp, &ssk->tx_wr, &bad_wr);
++ssk->tx_head;
--ssk->bufs;
@@ -292,7 +364,6 @@ struct sk_buff *sdp_send_completion(struct sdp_sock *ssk, int mseq)
return skb;
}
-
static void sdp_post_recv(struct sdp_sock *ssk)
{
struct sdp_buf *rx_req;
@@ -375,6 +446,7 @@ static void sdp_post_recv(struct sdp_sock *ssk)
ssk->rx_wr.sg_list = ssk->ibsge;
ssk->rx_wr.num_sge = frags + 1;
rc = ib_post_recv(ssk->qp, &ssk->rx_wr, &bad_wr);
+ SDPSTATS_COUNTER_INC(post_recv);
++ssk->rx_head;
if (unlikely(rc)) {
sdp_dbg(&ssk->isk.sk, "ib_post_recv failed with status %d\n", rc);
@@ -583,6 +655,7 @@ void sdp_post_sends(struct sdp_sock *ssk, int nonagle)
GFP_KERNEL);
/* FIXME */
BUG_ON(!skb);
+ SDPSTATS_COUNTER_INC(post_send_credits);
sdp_post_send(ssk, skb, SDP_MID_DATA);
}
@@ -701,11 +774,14 @@ static int sdp_handle_recv_comp(struct sdp_sock *ssk, struct ib_wc *wc)
skb->tail = skb->head + skb_headlen(skb);
#endif
h = (struct sdp_bsdh *)skb->data;
+ SDP_DUMP_PACKET(&ssk->isk.sk, "RX", skb, h);
skb_reset_transport_header(skb);
ssk->mseq_ack = ntohl(h->mseq);
if (ssk->mseq_ack != (int)wc->wr_id)
printk(KERN_WARNING "SDP BUG! mseq %d != wrid %d\n",
ssk->mseq_ack, (int)wc->wr_id);
+
+ SDPSTATS_HIST_LINEAR(credits_before_update, ssk->bufs);
ssk->bufs = ntohl(h->mseq_ack) - ssk->tx_head + 1 +
ntohs(h->bufs);
@@ -782,7 +858,7 @@ static int sdp_handle_send_comp(struct sdp_sock *ssk, struct ib_wc *wc)
if (unlikely(wc->status)) {
if (wc->status != IB_WC_WR_FLUSH_ERR) {
struct sock *sk = &ssk->isk.sk;
- sdp_dbg(sk, "Send completion with error. "
+ sdp_warn(sk, "Send completion with error. "
"Status %d\n", wc->status);
sdp_set_error(sk, -ECONNRESET);
wake_up(&ssk->wq);
diff --git a/drivers/infiniband/ulp/sdp/sdp_cma.c b/drivers/infiniband/ulp/sdp/sdp_cma.c
index 96d65bd..b6bc4e5 100644
--- a/drivers/infiniband/ulp/sdp/sdp_cma.c
+++ b/drivers/infiniband/ulp/sdp/sdp_cma.c
@@ -46,40 +46,8 @@
#include "sdp_socket.h"
#include "sdp.h"
-union cma_ip_addr {
- struct in6_addr ip6;
- struct {
- __u32 pad[3];
- __u32 addr;
- } ip4;
-};
-
#define SDP_MAJV_MINV 0x22
-/* TODO: too much? Can I avoid having the src/dst and port here? */
-struct sdp_hh {
- struct sdp_bsdh bsdh;
- u8 majv_minv;
- u8 ipv_cap;
- u8 rsvd1;
- u8 max_adverts;
- __u32 desremrcvsz;
- __u32 localrcvsz;
- __u16 port;
- __u16 rsvd2;
- union cma_ip_addr src_addr;
- union cma_ip_addr dst_addr;
-};
-
-struct sdp_hah {
- struct sdp_bsdh bsdh;
- u8 majv_minv;
- u8 ipv_cap;
- u8 rsvd1;
- u8 ext_max_adverts;
- __u32 actrcvsz;
-};
-
enum {
SDP_HH_SIZE = 76,
SDP_HAH_SIZE = 180,
@@ -206,6 +174,7 @@ static int sdp_connect_handler(struct sock *sk, struct rdma_cm_id *id,
sdp_dbg(sk, "%s %p -> %p\n", __func__, sdp_sk(sk)->id, id);
h = event->param.conn.private_data;
+ SDP_DUMP_PACKET(sk, "RX", NULL, &h->bsdh);
if (!h->max_adverts)
return -EINVAL;
@@ -277,6 +246,7 @@ static int sdp_response_handler(struct sock *sk, struct rdma_cm_id *id,
return 0;
h = event->param.conn.private_data;
+ SDP_DUMP_PACKET(sk, "RX", NULL, &h->bsdh);
sdp_sk(sk)->max_bufs = sdp_sk(sk)->bufs = ntohs(h->bsdh.bufs);
sdp_sk(sk)->min_bufs = sdp_sk(sk)->bufs / 4;
sdp_sk(sk)->xmit_size_goal = ntohl(h->actrcvsz) -
@@ -428,6 +398,7 @@ int sdp_cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
conn_param.responder_resources = 4 /* TODO */;
conn_param.initiator_depth = 4 /* TODO */;
conn_param.retry_count = SDP_RETRY_COUNT;
+ SDP_DUMP_PACKET(NULL, "TX", NULL, &hh.bsdh);
rc = rdma_connect(id, &conn_param);
break;
case RDMA_CM_EVENT_ROUTE_ERROR:
@@ -458,6 +429,7 @@ int sdp_cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
conn_param.responder_resources = 4 /* TODO */;
conn_param.initiator_depth = 4 /* TODO */;
conn_param.retry_count = SDP_RETRY_COUNT;
+ SDP_DUMP_PACKET(sk, "TX", NULL, &hah.bsdh);
rc = rdma_accept(id, &conn_param);
if (rc) {
sdp_sk(child)->id = NULL;
diff --git a/drivers/infiniband/ulp/sdp/sdp_main.c b/drivers/infiniband/ulp/sdp/sdp_main.c
index 7a38c47..c9b5ba2 100644
--- a/drivers/infiniband/ulp/sdp/sdp_main.c
+++ b/drivers/infiniband/ulp/sdp/sdp_main.c
@@ -67,7 +67,6 @@ unsigned int csum_partial_copy_from_user_new (const char *src, char *dst,
#include <linux/socket.h>
#include <net/protocol.h>
#include <net/inet_common.h>
-#include <linux/proc_fs.h>
#include <rdma/rdma_cm.h>
#include <rdma/ib_verbs.h>
/* TODO: remove when sdp_socket.h becomes part of include/linux/socket.h */
@@ -138,8 +137,8 @@ MODULE_PARM_DESC(sdp_zcopy_thresh, "Zero copy send threshold; 0=0ff.");
struct workqueue_struct *sdp_workqueue;
-static struct list_head sock_list;
-static spinlock_t sock_list_lock;
+struct list_head sock_list;
+spinlock_t sock_list_lock;
static DEFINE_RWLOCK(device_removal_lock);
@@ -1288,6 +1287,8 @@ static inline struct bzcopy_state *sdp_bz_cleanup(struct bzcopy_state *bz)
if (!bz->busy)
break;
+
+ SDPSTATS_COUNTER_INC(bzcopy_poll_miss);
}
if (bz->busy)
@@ -1319,11 +1320,14 @@ static struct bzcopy_state *sdp_bz_setup(struct sdp_sock *ssk,
int thresh;
mm_segment_t cur_fs;
- cur_fs = get_fs();
-
thresh = ssk->zcopy_thresh ? : sdp_zcopy_thresh;
- if (thresh == 0 || len < thresh || !capable(CAP_IPC_LOCK))
+ if (thresh == 0 || len < thresh || !capable(CAP_IPC_LOCK)) {
+ SDPSTATS_COUNTER_INC(sendmsg_bcopy_segment);
return NULL;
+ }
+ SDPSTATS_COUNTER_INC(sendmsg_bzcopy_segment);
+
+ cur_fs = get_fs();
/*
* Since we use the TCP segmentation fields of the skb to map user
@@ -1445,6 +1449,8 @@ static inline int sdp_bcopy_get(struct sock *sk, struct sk_buff *skb,
/* Time to copy data. We are close to
* the end! */
+ SDPSTATS_COUNTER_ADD(memcpy_count, copy);
+ sdp_dbg_data(sk, "Copying from: %p offset: %d size: %d\n", from, off, copy);
err = skb_copy_to_page(sk, from, skb, page,
off, copy);
if (err) {
@@ -1463,6 +1469,8 @@ static inline int sdp_bcopy_get(struct sock *sk, struct sk_buff *skb,
skb_shinfo(skb)->frags[i - 1].size +=
copy;
} else {
+ sdp_dbg_data(sk, "Adding to frage %d: page: %p off: %d size: %d\n",
+ i, page, off, copy);
skb_fill_page_desc(skb, i, page, off, copy);
if (TCP_PAGE(sk)) {
get_page(page);
@@ -1651,7 +1659,7 @@ static int sdp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
int err, copied;
long timeo;
struct bzcopy_state *bz = NULL;
-
+ SDPSTATS_COUNTER_INC(sendmsg);
lock_sock(sk);
sdp_dbg_data(sk, "%s\n", __func__);
@@ -1688,6 +1696,8 @@ static int sdp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (size_goal > SDP_MAX_PAYLOAD)
size_goal = SDP_MAX_PAYLOAD;
+ SDPSTATS_HIST(sendmsg_seglen, seglen);
+
if (bz)
sdp_bz_cleanup(bz);
bz = sdp_bz_setup(ssk, from, seglen, size_goal);
@@ -1737,8 +1747,14 @@ new_segment:
NETIF_F_HW_CSUM))
skb->ip_summed = CHECKSUM_PARTIAL;
+ sdp_dbg_data(sk, "entail new skb: %p len = %d\n", skb, skb->len);
skb_entail(sk, ssk, skb);
copy = size_goal;
+ } else {
+ sdp_dbg_data(sk, "adding to existing skb: %p"
+ " len = %d, sk_send_head: %p copy: %d\n",
+ skb, skb->len, sk->sk_send_head, copy);
+
}
/* Try to append data to the end of skb. */
@@ -1791,6 +1807,7 @@ new_segment:
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
+ SDPSTATS_COUNTER_INC(send_wait_for_mem);
if (copied)
sdp_push(sk, ssk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
@@ -2266,192 +2283,6 @@ static int sdp_create_socket(struct net *net, struct socket *sock, int protocol)
return 0;
}
-#ifdef CONFIG_PROC_FS
-
-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 sock *)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 sock *)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 sock *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 = sdp_sk(sk)->rcv_nxt - sdp_sk(sk)->copied_seq;
- tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->snd_una;
-
- 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;
-
- s = kzalloc(sizeof(*s), GFP_KERNEL);
- 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,
-};
-
-
-static int __init sdp_proc_init(void)
-{
- int rc = 0;
- struct proc_dir_entry *p;
-
- 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
- rc = -ENOMEM;
-
- return rc;
-}
-
-static 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));
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int __init sdp_proc_init(void)
-{
- return 0;
-}
-
-static void sdp_proc_unregister(void)
-{
-
-}
-#endif /* CONFIG_PROC_FS */
-
static void sdp_add_device(struct ib_device *device)
{
}
diff --git a/drivers/infiniband/ulp/sdp/sdp_proc.c b/drivers/infiniband/ulp/sdp/sdp_proc.c
new file mode 100644
index 0000000..8971517
--- /dev/null
+++ b/drivers/infiniband/ulp/sdp/sdp_proc.c
@@ -0,0 +1,358 @@
+/*
+ * 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 "sdp_socket.h"
+#include "sdp.h"
+
+#ifdef CONFIG_PROC_FS
+
+#define PROC_SDP_STATS "sdpstats"
+
+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 sock *)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 sock *)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 sock *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 = sdp_sk(sk)->rcv_nxt - sdp_sk(sk)->copied_seq;
+ tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->snd_una;
+
+ 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;
+
+ s = kzalloc(sizeof(*s), GFP_KERNEL);
+ 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
+struct sdpstats sdpstats = { { 0 } };
+
+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]);
+ }
+}
+
+static int sdpstats_seq_show(struct seq_file *seq, void *v)
+{
+#define ENUM2STR(e) [e] = #e
+ static char *mid2str[] = {
+ ENUM2STR(SDP_MID_HELLO),
+ ENUM2STR(SDP_MID_HELLO_ACK),
+ ENUM2STR(SDP_MID_DISCONN),
+ ENUM2STR(SDP_MID_CHRCVBUF),
+ ENUM2STR(SDP_MID_CHRCVBUF_ACK),
+ ENUM2STR(SDP_MID_DATA),
+ };
+ int i;
+
+ seq_printf(seq, "SDP statistics:\n");
+
+ sdpstats_seq_hist(seq, "sendmsg_seglen", sdpstats.sendmsg_seglen,
+ ARRAY_SIZE(sdpstats.sendmsg_seglen), 1);
+
+ sdpstats_seq_hist(seq, "send_size", sdpstats.send_size,
+ ARRAY_SIZE(sdpstats.send_size), 1);
+
+ sdpstats_seq_hist(seq, "credits_before_update", sdpstats.credits_before_update,
+ ARRAY_SIZE(sdpstats.credits_before_update), 0);
+
+// sdpstats_seq_hist(seq, "send_interval", sdpstats.send_interval,
+// ARRAY_SIZE(sdpstats.send_interval));
+
+ seq_printf(seq, "sdp_sendmsg() calls\t\t: %d\n", sdpstats.sendmsg);
+ seq_printf(seq, "bcopy segments \t\t: %d\n", sdpstats.sendmsg_bcopy_segment);
+ seq_printf(seq, "bzcopy segments \t\t: %d\n", sdpstats.sendmsg_bzcopy_segment);
+ seq_printf(seq, "post_send_credits \t\t: %d\n", sdpstats.post_send_credits);
+ seq_printf(seq, "memcpy_count \t\t: %u\n", sdpstats.memcpy_count);
+
+ for (i = 0; i < ARRAY_SIZE(sdpstats.post_send); i++) {
+ if (mid2str[i]) {
+ seq_printf(seq, "post_send %-20s\t: %d\n",
+ mid2str[i], sdpstats.post_send[i]);
+ }
+ }
+
+ seq_printf(seq, "\n");
+ seq_printf(seq, "post_recv \t\t: %d\n", sdpstats.post_recv);
+ seq_printf(seq, "BZCopy poll miss \t\t: %d\n", sdpstats.bzcopy_poll_miss);
+ seq_printf(seq, "send_wait_for_mem \t\t: %d\n", sdpstats.send_wait_for_mem);
+ seq_printf(seq, "send_miss_no_credits\t\t: %d\n", sdpstats.send_miss_no_credits);
+
+ seq_printf(seq, "rx_poll_miss \t\t: %d\n", sdpstats.rx_poll_miss);
+ seq_printf(seq, "tx_poll_miss \t\t: %d\n", sdpstats.tx_poll_miss);
+
+ seq_printf(seq, "CQ stats:\n");
+ seq_printf(seq, "- RX interrupts\t\t: %d\n", sdpstats.rx_int_count);
+ seq_printf(seq, "- TX interrupts\t\t: %d\n", sdpstats.tx_int_count);
+ return 0;
+}
+
+static ssize_t sdpstats_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offs)
+{
+ memset(&sdpstats, 0, sizeof(sdpstats));
+ printk("Cleared sdp statistics\n");
+
+ return count;
+}
+
+static const struct seq_operations sdpstats_seq_ops = {
+ .show = sdpstats_seq_show,
+};
+
+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
+
+int __init sdp_proc_init(void)
+{
+ struct proc_dir_entry *p = NULL;
+ struct proc_dir_entry *sdpstats = NULL;
+
+ 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(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
+
+ sdpstats = proc_net_fops_create(PROC_SDP_STATS,
+ S_IRUGO | S_IWUGO, &sdpstats_fops);
+ if (!sdpstats)
+ goto no_mem;;
+
+ return 0;
+#endif
+
+no_mem:
+ if (sdpstats)
+ proc_net_remove(PROC_SDP_STATS);
+
+ if (p)
+ proc_net_remove(sdp_seq_afinfo.name);
+
+ return -ENOMEM;
+}
+
+void sdp_proc_unregister(void)
+{
+ proc_net_remove(sdp_seq_afinfo.name);
+ memset(sdp_seq_afinfo.seq_fops, 0, sizeof(*sdp_seq_afinfo.seq_fops));
+
+#ifdef SDPSTATS_ON
+ proc_net_remove(PROC_SDP_STATS);
+#endif
+}
+
+#else /* CONFIG_PROC_FS */
+
+int __init sdp_proc_init(void)
+{
+ return 0;
+}
+
+void sdp_proc_unregister(void)
+{
+
+}
+#endif /* CONFIG_PROC_FS */
--
1.5.3.7
More information about the general
mailing list