[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