d2787b
From f2b9d3a089cc9ff9910da0075defe306851aca5c Mon Sep 17 00:00:00 2001
d2787b
From: Ravishankar N <ravishankar@redhat.com>
d2787b
Date: Fri, 4 Jun 2021 12:27:57 +0530
d2787b
Subject: [PATCH 576/584] rpcsvc: Add latency tracking for rpc programs
d2787b
d2787b
Added latency tracking of rpc-handling code. With this change we
d2787b
should be able to monitor the amount of time rpc-handling code is
d2787b
consuming for each of the rpc call.
d2787b
d2787b
Upstream patch details:
d2787b
> https://review.gluster.org/#/c/glusterfs/+/24955/
d2787b
> fixes: #1466
d2787b
> Change-Id: I04fc7f3b12bfa5053c0fc36885f271cb78f581cd
d2787b
> Signed-off-by: Pranith Kumar K <pkarampu@redhat.com>
d2787b
d2787b
BUG: 1928676
d2787b
Change-Id: Ibcedddb5db3ff4906607050cf9f7ea3ebb266cc5
d2787b
Signed-off-by: Ravishankar N <ravishankar@redhat.com>
d2787b
Reviewed-on: https://code.engineering.redhat.com/gerrit/c/rhs-glusterfs/+/245295
d2787b
Tested-by: RHGS Build Bot <nigelb@redhat.com>
d2787b
Reviewed-by: Xavi Hernandez Juan <xhernandez@redhat.com>
d2787b
Reviewed-by: Ashish Pandey <aspandey@redhat.com>
d2787b
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
d2787b
---
d2787b
 libglusterfs/src/glusterfs/latency.h   | 22 +++++---
d2787b
 libglusterfs/src/glusterfs/mem-types.h |  1 +
d2787b
 libglusterfs/src/glusterfs/stack.h     |  7 +--
d2787b
 libglusterfs/src/glusterfs/statedump.h |  2 +
d2787b
 libglusterfs/src/glusterfs/xlator.h    |  2 +-
d2787b
 libglusterfs/src/latency.c             | 93 +++++++++++++++-------------------
d2787b
 libglusterfs/src/libglusterfs.sym      |  5 ++
d2787b
 libglusterfs/src/monitoring.c          |  8 +--
d2787b
 libglusterfs/src/statedump.c           | 38 +++++++++++++-
d2787b
 libglusterfs/src/xlator.c              |  5 ++
d2787b
 rpc/rpc-lib/src/libgfrpc.sym           |  1 +
d2787b
 rpc/rpc-lib/src/rpcsvc.c               | 72 +++++++++++++++++++++++++-
d2787b
 rpc/rpc-lib/src/rpcsvc.h               |  5 ++
d2787b
 xlators/protocol/server/src/server.c   |  2 +
d2787b
 14 files changed, 193 insertions(+), 70 deletions(-)
d2787b
d2787b
diff --git a/libglusterfs/src/glusterfs/latency.h b/libglusterfs/src/glusterfs/latency.h
d2787b
index ed47b1f..4d601bb 100644
d2787b
--- a/libglusterfs/src/glusterfs/latency.h
d2787b
+++ b/libglusterfs/src/glusterfs/latency.h
d2787b
@@ -11,13 +11,23 @@
d2787b
 #ifndef __LATENCY_H__
d2787b
 #define __LATENCY_H__
d2787b
 
d2787b
-#include "glusterfs/glusterfs.h"
d2787b
+#include <inttypes.h>
d2787b
+#include <time.h>
d2787b
 
d2787b
-typedef struct fop_latency {
d2787b
-    double min;   /* min time for the call (microseconds) */
d2787b
-    double max;   /* max time for the call (microseconds) */
d2787b
-    double total; /* total time (microseconds) */
d2787b
+typedef struct _gf_latency {
d2787b
+    uint64_t min;   /* min time for the call (nanoseconds) */
d2787b
+    uint64_t max;   /* max time for the call (nanoseconds) */
d2787b
+    uint64_t total; /* total time (nanoseconds) */
d2787b
     uint64_t count;
d2787b
-} fop_latency_t;
d2787b
+} gf_latency_t;
d2787b
 
d2787b
+gf_latency_t *
d2787b
+gf_latency_new(size_t n);
d2787b
+
d2787b
+void
d2787b
+gf_latency_reset(gf_latency_t *lat);
d2787b
+
d2787b
+void
d2787b
+gf_latency_update(gf_latency_t *lat, struct timespec *begin,
d2787b
+                  struct timespec *end);
d2787b
 #endif /* __LATENCY_H__ */
d2787b
diff --git a/libglusterfs/src/glusterfs/mem-types.h b/libglusterfs/src/glusterfs/mem-types.h
d2787b
index 92730a9..970b9ff 100644
d2787b
--- a/libglusterfs/src/glusterfs/mem-types.h
d2787b
+++ b/libglusterfs/src/glusterfs/mem-types.h
d2787b
@@ -139,6 +139,7 @@ enum gf_common_mem_types_ {
d2787b
     gf_common_mt_mgmt_v3_lock_timer_t, /* used only in one location */
d2787b
     gf_common_mt_server_cmdline_t,     /* used only in one location */
d2787b
     gf_mt_gfdb_query_record_t,
d2787b
+    gf_common_mt_latency_t,
d2787b
     gf_common_mt_end
d2787b
 };
d2787b
 #endif
d2787b
diff --git a/libglusterfs/src/glusterfs/stack.h b/libglusterfs/src/glusterfs/stack.h
d2787b
index bd466d8..536a330 100644
d2787b
--- a/libglusterfs/src/glusterfs/stack.h
d2787b
+++ b/libglusterfs/src/glusterfs/stack.h
d2787b
@@ -45,6 +45,9 @@ typedef int32_t (*ret_fn_t)(call_frame_t *frame, call_frame_t *prev_frame,
d2787b
                             xlator_t *this, int32_t op_ret, int32_t op_errno,
d2787b
                             ...);
d2787b
 
d2787b
+void
d2787b
+gf_frame_latency_update(call_frame_t *frame);
d2787b
+
d2787b
 struct call_pool {
d2787b
     union {
d2787b
         struct list_head all_frames;
d2787b
@@ -149,8 +152,6 @@ struct _call_stack {
d2787b
     } while (0);
d2787b
 
d2787b
 struct xlator_fops;
d2787b
-void
d2787b
-gf_update_latency(call_frame_t *frame);
d2787b
 
d2787b
 static inline void
d2787b
 FRAME_DESTROY(call_frame_t *frame)
d2787b
@@ -158,7 +159,7 @@ FRAME_DESTROY(call_frame_t *frame)
d2787b
     void *local = NULL;
d2787b
 
d2787b
     if (frame->root->ctx->measure_latency)
d2787b
-        gf_update_latency(frame);
d2787b
+        gf_frame_latency_update(frame);
d2787b
 
d2787b
     list_del_init(&frame->frames);
d2787b
     if (frame->local) {
d2787b
diff --git a/libglusterfs/src/glusterfs/statedump.h b/libglusterfs/src/glusterfs/statedump.h
d2787b
index 89d04f9..ce08270 100644
d2787b
--- a/libglusterfs/src/glusterfs/statedump.h
d2787b
+++ b/libglusterfs/src/glusterfs/statedump.h
d2787b
@@ -127,4 +127,6 @@ gf_proc_dump_xlator_meminfo(xlator_t *this, strfd_t *strfd);
d2787b
 void
d2787b
 gf_proc_dump_xlator_profile(xlator_t *this, strfd_t *strfd);
d2787b
 
d2787b
+void
d2787b
+gf_latency_statedump_and_reset(char *key, gf_latency_t *lat);
d2787b
 #endif /* STATEDUMP_H */
d2787b
diff --git a/libglusterfs/src/glusterfs/xlator.h b/libglusterfs/src/glusterfs/xlator.h
d2787b
index 273039a..ecb9fa4 100644
d2787b
--- a/libglusterfs/src/glusterfs/xlator.h
d2787b
+++ b/libglusterfs/src/glusterfs/xlator.h
d2787b
@@ -808,7 +808,7 @@ struct _xlator {
d2787b
 
d2787b
         struct {
d2787b
             /* for latency measurement */
d2787b
-            fop_latency_t latencies[GF_FOP_MAXVALUE];
d2787b
+            gf_latency_t latencies[GF_FOP_MAXVALUE];
d2787b
             /* for latency measurement */
d2787b
             fop_metrics_t metrics[GF_FOP_MAXVALUE];
d2787b
 
d2787b
diff --git a/libglusterfs/src/latency.c b/libglusterfs/src/latency.c
d2787b
index ce61399..ce4b0e8 100644
d2787b
--- a/libglusterfs/src/latency.c
d2787b
+++ b/libglusterfs/src/latency.c
d2787b
@@ -14,39 +14,34 @@
d2787b
  */
d2787b
 
d2787b
 #include "glusterfs/glusterfs.h"
d2787b
-#include "glusterfs/xlator.h"
d2787b
-#include "glusterfs/common-utils.h"
d2787b
 #include "glusterfs/statedump.h"
d2787b
-#include "glusterfs/libglusterfs-messages.h"
d2787b
 
d2787b
-void
d2787b
-gf_update_latency(call_frame_t *frame)
d2787b
+gf_latency_t *
d2787b
+gf_latency_new(size_t n)
d2787b
 {
d2787b
-    double elapsed;
d2787b
-    struct timespec *begin, *end;
d2787b
-
d2787b
-    fop_latency_t *lat;
d2787b
-
d2787b
-    begin = &frame->begin;
d2787b
-    end = &frame->end;
d2787b
+    int i = 0;
d2787b
+    gf_latency_t *lat = NULL;
d2787b
 
d2787b
-    if (!(begin->tv_sec && end->tv_sec))
d2787b
-        goto out;
d2787b
+    lat = GF_MALLOC(n * sizeof(*lat), gf_common_mt_latency_t);
d2787b
+    if (!lat)
d2787b
+        return NULL;
d2787b
 
d2787b
-    elapsed = gf_tsdiff(begin, end);
d2787b
+    for (i = 0; i < n; i++) {
d2787b
+        gf_latency_reset(lat + i);
d2787b
+    }
d2787b
+    return lat;
d2787b
+}
d2787b
 
d2787b
-    if (frame->op < 0 || frame->op >= GF_FOP_MAXVALUE) {
d2787b
-        gf_log("[core]", GF_LOG_WARNING, "Invalid frame op value: %d",
d2787b
-               frame->op);
d2787b
+void
d2787b
+gf_latency_update(gf_latency_t *lat, struct timespec *begin,
d2787b
+                  struct timespec *end)
d2787b
+{
d2787b
+    if (!(begin->tv_sec && end->tv_sec)) {
d2787b
+        /*Measure latency might have been enabled/disabled during the op*/
d2787b
         return;
d2787b
     }
d2787b
 
d2787b
-    /* Can happen mostly at initiator xlator, as STACK_WIND/UNWIND macros
d2787b
-       set it right anyways for those frames */
d2787b
-    if (!frame->op)
d2787b
-        frame->op = frame->root->op;
d2787b
-
d2787b
-    lat = &frame->this->stats.interval.latencies[frame->op];
d2787b
+    double elapsed = gf_tsdiff(begin, end);
d2787b
 
d2787b
     if (lat->max < elapsed)
d2787b
         lat->max = elapsed;
d2787b
@@ -56,40 +51,34 @@ gf_update_latency(call_frame_t *frame)
d2787b
 
d2787b
     lat->total += elapsed;
d2787b
     lat->count++;
d2787b
-out:
d2787b
-    return;
d2787b
 }
d2787b
 
d2787b
 void
d2787b
-gf_proc_dump_latency_info(xlator_t *xl)
d2787b
+gf_latency_reset(gf_latency_t *lat)
d2787b
 {
d2787b
-    char key_prefix[GF_DUMP_MAX_BUF_LEN];
d2787b
-    char key[GF_DUMP_MAX_BUF_LEN];
d2787b
-    int i;
d2787b
-
d2787b
-    snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.latency", xl->name);
d2787b
-    gf_proc_dump_add_section("%s", key_prefix);
d2787b
-
d2787b
-    for (i = 0; i < GF_FOP_MAXVALUE; i++) {
d2787b
-        gf_proc_dump_build_key(key, key_prefix, "%s", (char *)gf_fop_list[i]);
d2787b
-
d2787b
-        fop_latency_t *lat = &xl->stats.interval.latencies[i];
d2787b
+    if (!lat)
d2787b
+        return;
d2787b
+    memset(lat, 0, sizeof(*lat));
d2787b
+    lat->min = ULLONG_MAX;
d2787b
+    /* make sure 'min' is set to high value, so it would be
d2787b
+       properly set later */
d2787b
+}
d2787b
 
d2787b
-        /* Doesn't make sense to continue if there are no fops
d2787b
-           came in the given interval */
d2787b
-        if (!lat->count)
d2787b
-            continue;
d2787b
+void
d2787b
+gf_frame_latency_update(call_frame_t *frame)
d2787b
+{
d2787b
+    gf_latency_t *lat;
d2787b
+    /* Can happen mostly at initiator xlator, as STACK_WIND/UNWIND macros
d2787b
+       set it right anyways for those frames */
d2787b
+    if (!frame->op)
d2787b
+        frame->op = frame->root->op;
d2787b
 
d2787b
-        gf_proc_dump_write(key, "%.03f,%" PRId64 ",%.03f",
d2787b
-                           (lat->total / lat->count), lat->count, lat->total);
d2787b
+    if (frame->op < 0 || frame->op >= GF_FOP_MAXVALUE) {
d2787b
+        gf_log("[core]", GF_LOG_WARNING, "Invalid frame op value: %d",
d2787b
+               frame->op);
d2787b
+        return;
d2787b
     }
d2787b
 
d2787b
-    memset(xl->stats.interval.latencies, 0,
d2787b
-           sizeof(xl->stats.interval.latencies));
d2787b
-
d2787b
-    /* make sure 'min' is set to high value, so it would be
d2787b
-       properly set later */
d2787b
-    for (i = 0; i < GF_FOP_MAXVALUE; i++) {
d2787b
-        xl->stats.interval.latencies[i].min = 0xffffffff;
d2787b
-    }
d2787b
+    lat = &frame->this->stats.interval.latencies[frame->op];
d2787b
+    gf_latency_update(lat, &frame->begin, &frame->end);
d2787b
 }
d2787b
diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym
d2787b
index 9072afa..4f968e1 100644
d2787b
--- a/libglusterfs/src/libglusterfs.sym
d2787b
+++ b/libglusterfs/src/libglusterfs.sym
d2787b
@@ -1183,3 +1183,8 @@ gf_latency_reset
d2787b
 gf_latency_update
d2787b
 gf_frame_latency_update
d2787b
 gf_assert
d2787b
+gf_latency_statedump_and_reset
d2787b
+gf_latency_new
d2787b
+gf_latency_reset
d2787b
+gf_latency_update
d2787b
+gf_frame_latency_update
d2787b
diff --git a/libglusterfs/src/monitoring.c b/libglusterfs/src/monitoring.c
d2787b
index 6d9bfb1..20b7f52 100644
d2787b
--- a/libglusterfs/src/monitoring.c
d2787b
+++ b/libglusterfs/src/monitoring.c
d2787b
@@ -113,15 +113,15 @@ dump_latency_and_count(xlator_t *xl, int fd)
d2787b
             dprintf(fd, "%s.interval.%s.fail_count %" PRIu64 "\n", xl->name,
d2787b
                     gf_fop_list[index], cbk);
d2787b
         }
d2787b
-        if (xl->stats.interval.latencies[index].count != 0.0) {
d2787b
+        if (xl->stats.interval.latencies[index].count != 0) {
d2787b
             dprintf(fd, "%s.interval.%s.latency %lf\n", xl->name,
d2787b
                     gf_fop_list[index],
d2787b
-                    (xl->stats.interval.latencies[index].total /
d2787b
+                    (((double)xl->stats.interval.latencies[index].total) /
d2787b
                      xl->stats.interval.latencies[index].count));
d2787b
-            dprintf(fd, "%s.interval.%s.max %lf\n", xl->name,
d2787b
+            dprintf(fd, "%s.interval.%s.max %" PRIu64 "\n", xl->name,
d2787b
                     gf_fop_list[index],
d2787b
                     xl->stats.interval.latencies[index].max);
d2787b
-            dprintf(fd, "%s.interval.%s.min %lf\n", xl->name,
d2787b
+            dprintf(fd, "%s.interval.%s.min %" PRIu64 "\n", xl->name,
d2787b
                     gf_fop_list[index],
d2787b
                     xl->stats.interval.latencies[index].min);
d2787b
         }
d2787b
diff --git a/libglusterfs/src/statedump.c b/libglusterfs/src/statedump.c
d2787b
index d18b50f..4bf4cc2 100644
d2787b
--- a/libglusterfs/src/statedump.c
d2787b
+++ b/libglusterfs/src/statedump.c
d2787b
@@ -201,6 +201,40 @@ gf_proc_dump_write(char *key, char *value, ...)
d2787b
     return ret;
d2787b
 }
d2787b
 
d2787b
+void
d2787b
+gf_latency_statedump_and_reset(char *key, gf_latency_t *lat)
d2787b
+{
d2787b
+    /* Doesn't make sense to continue if there are no fops
d2787b
+       came in the given interval */
d2787b
+    if (!lat || !lat->count)
d2787b
+        return;
d2787b
+    gf_proc_dump_write(key,
d2787b
+                       "AVG:%lf CNT:%" PRIu64 " TOTAL:%" PRIu64 " MIN:%" PRIu64
d2787b
+                       " MAX:%" PRIu64,
d2787b
+                       (((double)lat->total) / lat->count), lat->count,
d2787b
+                       lat->total, lat->min, lat->max);
d2787b
+    gf_latency_reset(lat);
d2787b
+}
d2787b
+
d2787b
+void
d2787b
+gf_proc_dump_xl_latency_info(xlator_t *xl)
d2787b
+{
d2787b
+    char key_prefix[GF_DUMP_MAX_BUF_LEN];
d2787b
+    char key[GF_DUMP_MAX_BUF_LEN];
d2787b
+    int i;
d2787b
+
d2787b
+    snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.latency", xl->name);
d2787b
+    gf_proc_dump_add_section("%s", key_prefix);
d2787b
+
d2787b
+    for (i = 0; i < GF_FOP_MAXVALUE; i++) {
d2787b
+        gf_proc_dump_build_key(key, key_prefix, "%s", (char *)gf_fop_list[i]);
d2787b
+
d2787b
+        gf_latency_t *lat = &xl->stats.interval.latencies[i];
d2787b
+
d2787b
+        gf_latency_statedump_and_reset(key, lat);
d2787b
+    }
d2787b
+}
d2787b
+
d2787b
 static void
d2787b
 gf_proc_dump_xlator_mem_info(xlator_t *xl)
d2787b
 {
d2787b
@@ -487,7 +521,7 @@ gf_proc_dump_single_xlator_info(xlator_t *trav)
d2787b
         return;
d2787b
 
d2787b
     if (ctx->measure_latency)
d2787b
-        gf_proc_dump_latency_info(trav);
d2787b
+        gf_proc_dump_xl_latency_info(trav);
d2787b
 
d2787b
     gf_proc_dump_xlator_mem_info(trav);
d2787b
 
d2787b
@@ -1024,7 +1058,7 @@ gf_proc_dump_xlator_profile(xlator_t *this, strfd_t *strfd)
d2787b
     {
d2787b
         gf_dump_strfd = strfd;
d2787b
 
d2787b
-        gf_proc_dump_latency_info(this);
d2787b
+        gf_proc_dump_xl_latency_info(this);
d2787b
 
d2787b
         gf_dump_strfd = NULL;
d2787b
     }
d2787b
diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c
d2787b
index 36cc32c..b9ad411 100644
d2787b
--- a/libglusterfs/src/xlator.c
d2787b
+++ b/libglusterfs/src/xlator.c
d2787b
@@ -246,6 +246,7 @@ xlator_dynload_apis(xlator_t *xl)
d2787b
     void *handle = NULL;
d2787b
     volume_opt_list_t *vol_opt = NULL;
d2787b
     xlator_api_t *xlapi = NULL;
d2787b
+    int i = 0;
d2787b
 
d2787b
     handle = xl->dlhandle;
d2787b
 
d2787b
@@ -343,6 +344,10 @@ xlator_dynload_apis(xlator_t *xl)
d2787b
     memcpy(xl->op_version, xlapi->op_version,
d2787b
            sizeof(uint32_t) * GF_MAX_RELEASES);
d2787b
 
d2787b
+    for (i = 0; i < GF_FOP_MAXVALUE; i++) {
d2787b
+        gf_latency_reset(&xl->stats.interval.latencies[i]);
d2787b
+    }
d2787b
+
d2787b
     ret = 0;
d2787b
 out:
d2787b
     return ret;
d2787b
diff --git a/rpc/rpc-lib/src/libgfrpc.sym b/rpc/rpc-lib/src/libgfrpc.sym
d2787b
index f3544e3..a1757cc 100644
d2787b
--- a/rpc/rpc-lib/src/libgfrpc.sym
d2787b
+++ b/rpc/rpc-lib/src/libgfrpc.sym
d2787b
@@ -66,3 +66,4 @@ rpc_transport_unix_options_build
d2787b
 rpc_transport_unref
d2787b
 rpc_clnt_mgmt_pmap_signout
d2787b
 rpcsvc_autoscale_threads
d2787b
+rpcsvc_statedump
d2787b
diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c
d2787b
index b031d93..855b512 100644
d2787b
--- a/rpc/rpc-lib/src/rpcsvc.c
d2787b
+++ b/rpc/rpc-lib/src/rpcsvc.c
d2787b
@@ -25,6 +25,7 @@
d2787b
 #include <glusterfs/syncop.h>
d2787b
 #include "rpc-drc.h"
d2787b
 #include "protocol-common.h"
d2787b
+#include <glusterfs/statedump.h>
d2787b
 
d2787b
 #include <errno.h>
d2787b
 #include <pthread.h>
d2787b
@@ -377,6 +378,10 @@ rpcsvc_program_actor(rpcsvc_request_t *req)
d2787b
         goto err;
d2787b
     }
d2787b
 
d2787b
+    if (svc->xl->ctx->measure_latency) {
d2787b
+        timespec_now(&req->begin);
d2787b
+    }
d2787b
+
d2787b
     req->ownthread = program->ownthread;
d2787b
     req->synctask = program->synctask;
d2787b
 
d2787b
@@ -1526,10 +1531,18 @@ rpcsvc_submit_generic(rpcsvc_request_t *req, struct iovec *proghdr,
d2787b
     size_t hdrlen = 0;
d2787b
     char new_iobref = 0;
d2787b
     rpcsvc_drc_globals_t *drc = NULL;
d2787b
+    gf_latency_t *lat = NULL;
d2787b
 
d2787b
     if ((!req) || (!req->trans))
d2787b
         return -1;
d2787b
 
d2787b
+    if (req->prog && req->begin.tv_sec) {
d2787b
+        if ((req->procnum >= 0) && (req->procnum < req->prog->numactors)) {
d2787b
+            timespec_now(&req->end);
d2787b
+            lat = &req->prog->latencies[req->procnum];
d2787b
+            gf_latency_update(lat, &req->begin, &req->end);
d2787b
+        }
d2787b
+    }
d2787b
     trans = req->trans;
d2787b
 
d2787b
     for (i = 0; i < hdrcount; i++) {
d2787b
@@ -1860,6 +1873,15 @@ rpcsvc_submit_message(rpcsvc_request_t *req, struct iovec *proghdr,
d2787b
                                  iobref);
d2787b
 }
d2787b
 
d2787b
+void
d2787b
+rpcsvc_program_destroy(rpcsvc_program_t *program)
d2787b
+{
d2787b
+    if (program) {
d2787b
+        GF_FREE(program->latencies);
d2787b
+        GF_FREE(program);
d2787b
+    }
d2787b
+}
d2787b
+
d2787b
 int
d2787b
 rpcsvc_program_unregister(rpcsvc_t *svc, rpcsvc_program_t *program)
d2787b
 {
d2787b
@@ -1917,8 +1939,7 @@ rpcsvc_program_unregister(rpcsvc_t *svc, rpcsvc_program_t *program)
d2787b
 
d2787b
     ret = 0;
d2787b
 out:
d2787b
-    if (prog)
d2787b
-        GF_FREE(prog);
d2787b
+    rpcsvc_program_destroy(prog);
d2787b
 
d2787b
     if (ret == -1) {
d2787b
         if (program) {
d2787b
@@ -2303,6 +2324,11 @@ rpcsvc_program_register(rpcsvc_t *svc, rpcsvc_program_t *program,
d2787b
     }
d2787b
 
d2787b
     memcpy(newprog, program, sizeof(*program));
d2787b
+    newprog->latencies = gf_latency_new(program->numactors);
d2787b
+    if (!newprog->latencies) {
d2787b
+        rpcsvc_program_destroy(newprog);
d2787b
+        goto out;
d2787b
+    }
d2787b
 
d2787b
     INIT_LIST_HEAD(&newprog->program);
d2787b
     pthread_mutexattr_init(&thr_attr);
d2787b
@@ -3240,6 +3266,48 @@ out:
d2787b
     return ret;
d2787b
 }
d2787b
 
d2787b
+void
d2787b
+rpcsvc_program_dump(rpcsvc_program_t *prog)
d2787b
+{
d2787b
+    char key_prefix[GF_DUMP_MAX_BUF_LEN];
d2787b
+    char key[GF_DUMP_MAX_BUF_LEN];
d2787b
+    int i;
d2787b
+
d2787b
+    snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s", prog->progname);
d2787b
+    gf_proc_dump_add_section("%s", key_prefix);
d2787b
+
d2787b
+    gf_proc_dump_build_key(key, key_prefix, "program-number");
d2787b
+    gf_proc_dump_write(key, "%d", prog->prognum);
d2787b
+
d2787b
+    gf_proc_dump_build_key(key, key_prefix, "program-version");
d2787b
+    gf_proc_dump_write(key, "%d", prog->progver);
d2787b
+
d2787b
+    strncat(key_prefix, ".latency",
d2787b
+            sizeof(key_prefix) - strlen(key_prefix) - 1);
d2787b
+
d2787b
+    for (i = 0; i < prog->numactors; i++) {
d2787b
+        gf_proc_dump_build_key(key, key_prefix, "%s", prog->actors[i].procname);
d2787b
+        gf_latency_statedump_and_reset(key, &prog->latencies[i]);
d2787b
+    }
d2787b
+}
d2787b
+
d2787b
+void
d2787b
+rpcsvc_statedump(rpcsvc_t *svc)
d2787b
+{
d2787b
+    rpcsvc_program_t *prog = NULL;
d2787b
+    int ret = 0;
d2787b
+    ret = pthread_rwlock_tryrdlock(&svc->rpclock);
d2787b
+    if (ret)
d2787b
+        return;
d2787b
+    {
d2787b
+        list_for_each_entry(prog, &svc->programs, program)
d2787b
+        {
d2787b
+            rpcsvc_program_dump(prog);
d2787b
+        }
d2787b
+    }
d2787b
+    pthread_rwlock_unlock(&svc->rpclock);
d2787b
+}
d2787b
+
d2787b
 rpcsvc_actor_t gluster_dump_actors[GF_DUMP_MAXVALUE] = {
d2787b
     [GF_DUMP_NULL] = {"NULL", GF_DUMP_NULL, NULL, NULL, 0, DRC_NA},
d2787b
     [GF_DUMP_DUMP] = {"DUMP", GF_DUMP_DUMP, rpcsvc_dump, NULL, 0, DRC_NA},
d2787b
diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h
d2787b
index a51edc7..e336d00 100644
d2787b
--- a/rpc/rpc-lib/src/rpcsvc.h
d2787b
+++ b/rpc/rpc-lib/src/rpcsvc.h
d2787b
@@ -275,6 +275,8 @@ struct rpcsvc_request {
d2787b
     gf_boolean_t ownthread;
d2787b
 
d2787b
     gf_boolean_t synctask;
d2787b
+    struct timespec begin; /*req handling start time*/
d2787b
+    struct timespec end;   /*req handling end time*/
d2787b
 };
d2787b
 
d2787b
 #define rpcsvc_request_program(req) ((rpcsvc_program_t *)((req)->prog))
d2787b
@@ -431,6 +433,7 @@ struct rpcsvc_program {
d2787b
 
d2787b
     /* Program specific state handed to actors */
d2787b
     void *private;
d2787b
+    gf_latency_t *latencies; /*Tracks latency statistics for the rpc call*/
d2787b
 
d2787b
     /* This upcall is provided by the program during registration.
d2787b
      * It is used to notify the program about events like connection being
d2787b
@@ -696,4 +699,6 @@ rpcsvc_autoscale_threads(glusterfs_ctx_t *ctx, rpcsvc_t *rpc, int incr);
d2787b
 
d2787b
 extern int
d2787b
 rpcsvc_destroy(rpcsvc_t *svc);
d2787b
+void
d2787b
+rpcsvc_statedump(rpcsvc_t *svc);
d2787b
 #endif
d2787b
diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c
d2787b
index 54d9c0f..90eb3ff 100644
d2787b
--- a/xlators/protocol/server/src/server.c
d2787b
+++ b/xlators/protocol/server/src/server.c
d2787b
@@ -267,6 +267,8 @@ server_priv(xlator_t *this)
d2787b
     gf_proc_dump_build_key(key, "server", "total-bytes-write");
d2787b
     gf_proc_dump_write(key, "%" PRIu64, total_write);
d2787b
 
d2787b
+    rpcsvc_statedump(conf->rpc);
d2787b
+
d2787b
     ret = 0;
d2787b
 out:
d2787b
     if (ret)
d2787b
-- 
d2787b
1.8.3.1
d2787b