xstat: cope with different size timeval structures
authorMichael Meffie <mmeffie@sinenomine.net>
Fri, 24 Sep 2010 01:18:36 +0000 (21:18 -0400)
committerDerrick Brashear <shadow@dementia.org>
Sun, 5 Jun 2011 15:14:45 +0000 (08:14 -0700)
In xstat_fs_test and afsmonitor, try to display the xstat data
from the fileserver even if the fileserver has differently sized
timeval structures, or different word ordering, as the xstat
client program.

Change-Id: I16f32b25f0017cdcf5e41e583eeb129469c3aeb0
Reviewed-on: http://gerrit.openafs.org/2986
Tested-by: Derrick Brashear <shadow@dementia.org>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

src/afsmonitor/afsmon-output.c
src/afsmonitor/afsmon-parselog.c
src/afsmonitor/afsmonitor.c
src/xstat/xstat_fs.c
src/xstat/xstat_fs.h
src/xstat/xstat_fs_test.c

index e2322d2..67ed97a 100644 (file)
@@ -389,35 +389,32 @@ Print_fs_FullPerfInfo(struct xstat_fs_ProbeResults *a_fs_Results)
     static afs_int32 fullPerfLongs = (sizeof(struct fs_stats_FullPerfStats) >> 2);     /*Correct # longs to rcv */
     afs_int32 numLongs;                /*# longwords received */
     struct fs_stats_FullPerfStats *fullPerfP;  /*Ptr to full perf stats */
+    struct fs_stats_FullPerfStats buffer;
     char *printableTime;       /*Ptr to printable time string */
     time_t probeTime;
+    int code;
 
 
     probeTime = a_fs_Results->probeTime;
     printableTime = ctime(&probeTime);
     printableTime[strlen(printableTime) - 1] = '\0';
-    fullPerfP = (struct fs_stats_FullPerfStats *)
-       (a_fs_Results->data.AFS_CollData_val);
 
     fprintf(fs_outFD,
            "AFS_XSTATSCOLL_FULL_PERF_INFO (coll %d) for FS %s\n[Probe %d, %s]\n\n",
            a_fs_Results->collectionNumber, a_fs_Results->connP->hostName,
            a_fs_Results->probeNum, printableTime);
 
-    numLongs = a_fs_Results->data.AFS_CollData_len;
-    if (numLongs != fullPerfLongs) {
+    code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
+                                       a_fs_Results->data.AFS_CollData_val,
+                                       a_fs_Results->data.AFS_CollData_len,
+                                       &buffer);
+    if (code) {
+       numLongs = a_fs_Results->data.AFS_CollData_len;
        fprintf(fs_outFD,
                " ** Data size mismatch in full performance collection!\n");
        fprintf(fs_outFD, " ** Expecting %d, got %d\n", fullPerfLongs,
                numLongs);
 
-       /* Unfortunately, the full perf stats contain timeval structures which
-        * do not have the same size everywhere. At least try to print
-        * the overall stats.
-        */
-       if (numLongs >= (sizeof(struct afs_stats_CMPerf) / sizeof(afs_int32))) {
-           Print_fs_OverallPerfInfo(&(fullPerfP->overall));
-       }
     } else {
        Print_fs_OverallPerfInfo(&(fullPerfP->overall));
        Print_fs_DetailedPerfInfo(&(fullPerfP->det));
index d608140..e9b99d5 100644 (file)
@@ -317,11 +317,17 @@ Print_fs_FullPerfInfo(a_fs_Results)
     static long fullPerfLongs = (sizeof(struct fs_stats_FullPerfStats) >> 2);  /*Correct # longs to rcv */
     long numLongs;             /*# longwords received */
     struct fs_stats_FullPerfStats *fullPerfP;  /*Ptr to full perf stats */
+    struct fs_stats_FullPerfStats buffer;
     char *printableTime;       /*Ptr to printable time string */
     time_t probeTime;
-
-    numLongs = a_fs_Results->data.AFS_CollData_len;
-    if (numLongs != fullPerfLongs) {
+    int code;
+
+    code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
+                                       a_fs_Results->data.AFS_CollData_val,
+                                       a_fs_Results->data.AFS_CollData_len,
+                                       &buffer);
+    if (code) {
+       numLongs = a_fs_Results->data.AFS_CollData_len;
        printf(" ** Data size mismatch in full performance collection!\n");
        printf(" ** Expecting %d, got %d\n", fullPerfLongs, numLongs);
        return;
@@ -330,8 +336,6 @@ Print_fs_FullPerfInfo(a_fs_Results)
     probeTime = a_fs_Results->probeTime;
     printableTime = ctime(&probeTime);
     printableTime[strlen(printableTime) - 1] = '\0';
-    fullPerfP = (struct fs_stats_FullPerfStats *)
-       (a_fs_Results->data.AFS_CollData_val);
 
     printf
        ("AFS_XSTATSCOLL_FULL_PERF_INFO (coll %d) for FS %s\n[Probe %d, %s]\n\n",
index 952a95d..b5f1c46 100644 (file)
@@ -1878,34 +1878,25 @@ fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
 {
     afs_int32 *srcbuf;
     struct fs_stats_FullPerfStats *fullPerfP;
+    struct fs_stats_FullPerfStats buffer;
     int idx;
     int i, j;
     afs_int32 *tmpbuf;
-    afs_int32 numInt32s;
-
-    fullPerfP = (struct fs_stats_FullPerfStats *)
-       (a_fsResults->data.AFS_CollData_val);
+    int code;
 
     /* there are two parts to the xstat FS statistics
      * - fullPerfP->overall which give the overall performance statistics, and
      * - fullPerfP->det which gives detailed info about file server operation
      * execution times */
 
-    /*
-     * Unfortunately, the full perf stats contain timeval structures which
-     * do not have the same size everywhere. Avoid displaying gargbage,
-     * but at least try to show the overall stats.
-     */
-    numInt32s = a_fsResults->data.AFS_CollData_len;
-    if (numInt32s !=
-       (sizeof(struct fs_stats_FullPerfStats) / sizeof(afs_int32))) {
-       srcbuf = a_fsResults->data.AFS_CollData_val;
+    code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
+                                       a_fsResults->data.AFS_CollData_val,
+                                       a_fsResults->data.AFS_CollData_len,
+                                       &buffer);
+    if (code) {
+       /* Not able to decode the full perf stats. Avoid displaying garbage. */
        for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
-           if (i < numInt32s && i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS) {
-               sprintf(a_fsData->data[i], "%d", srcbuf[i]);
-           } else {
-               sprintf(a_fsData->data[i], "%s", "--");
-           }
+           sprintf(a_fsData->data[i], "%s", "--");
        }
        return 0;
     }
index 16ac29a..e157bb9 100644 (file)
@@ -726,3 +726,137 @@ xstat_fs_ForceProbeNow(void)
      */
     return (0);
 }
+
+/**
+ * Fill the xstat full perf data structure from the data collection array.
+ *
+ * This function is a client-side decoding of the non-portable xstat_fs full
+ * performance data.  The full perf structure includes timeval structures,
+ * which have platform dependent size.
+ *
+ * To make things even more interesting, the word ordering of the time
+ * values on hosts with 64-bit time depend on endianess. The ordering
+ * within a given afs_int32 is handled by xdr.
+ *
+ * @param[out] aout an address to a stats structure pointer
+ * @param[in] ain array of int32s received
+ * @param[in] alen length of ain
+ * @param[inout] abuf a buffer provided by the caller
+ *
+ * @return 0 on success
+ */
+int
+xstat_fs_DecodeFullPerfStats(struct fs_stats_FullPerfStats **aout,
+                            afs_int32 * ain,
+                            afs_int32 alen,
+                            struct fs_stats_FullPerfStats *abuf)
+{
+    int i;
+    afs_int32 *p;
+    int snbo = -2;     /* detected remote site has network-byte ordering */
+
+    static const int XSTAT_FPS_LEN = sizeof(struct fs_stats_FullPerfStats) / sizeof(afs_int32);        /* local size of fps */
+    static const int XSTAT_FPS_SMALL = 424;    /**< fps size when sizeof(timeval) is 2*sizeof(afs_int32) */
+    static const int XSTAT_FPS_LARGE = 666;    /**< fps size when sizeof(timeval) is 2*sizeof(afs_int64) */
+
+#define DECODE_TV(t) \
+    do { \
+       if (alen == XSTAT_FPS_SMALL) { \
+           (t).tv_sec = *p++; \
+           (t).tv_usec = *p++; \
+       } else { \
+           if (snbo) { \
+               p++; \
+               (t).tv_sec = *p++; \
+               p++; \
+               (t).tv_usec = *p++; \
+           } else { \
+               (t).tv_sec = *p++; \
+               p++; \
+               (t).tv_usec = *p++; \
+               p++; \
+           } \
+       } \
+    } while (0)
+
+    if (alen != XSTAT_FPS_SMALL && alen != XSTAT_FPS_LARGE) {
+       return -1;              /* unrecognized size */
+    }
+
+    if (alen == XSTAT_FPS_LEN && alen == XSTAT_FPS_SMALL) {
+       /* Same size, and xdr dealt with byte ordering; no decoding needed. */
+       *aout = (struct fs_stats_FullPerfStats *)ain;
+       return 0;
+    }
+
+    if (alen == XSTAT_FPS_LARGE) {
+       /* Attempt to detect the word ordering of the time values. */
+       struct fs_stats_FullPerfStats *fps =
+           (struct fs_stats_FullPerfStats *)ain;
+       afs_int32 *epoch = (afs_int32 *) & (fps->det.epoch);
+       if (epoch[0] == 0 && epoch[1] != 0) {
+           snbo = 1;
+       } else if (epoch[0] != 0 && epoch[1] == 0) {
+           snbo = 0;
+       } else {
+           return -2;          /* failed to detect server word ordering */
+       }
+    }
+
+    if (alen == XSTAT_FPS_LEN && alen == XSTAT_FPS_LARGE
+#if defined(WORDS_BIGENDIAN)
+       && snbo
+#else /* WORDS_BIGENDIAN */
+       && !snbo
+#endif /* WORDS_BIGENDIAN */
+       ) {
+       /* Same size and order; no decoding needed. */
+       *aout = (struct fs_stats_FullPerfStats *)ain;
+       return 0;
+    }
+
+    /* Either different sizes, or different ordering, or both. Schlep over
+     * each field, decoding time values. The fields up to the first time value
+     * can be copied in bulk. */
+    if (xstat_fs_debug) {
+       printf("debug: Decoding xstat full perf stats; length=%d", alen);
+       if (alen == XSTAT_FPS_LARGE) {
+           printf(", order='%s'", (snbo ? "big-endian" : "little-endian"));
+       }
+       printf("\n");
+    }
+
+    p = ain;
+    memset(abuf, 0, sizeof(struct fs_stats_FullPerfStats));
+    memcpy(abuf, p, sizeof(struct afs_PerfStats));
+    p += sizeof(struct afs_PerfStats) / sizeof(afs_int32);
+
+    DECODE_TV(abuf->det.epoch);
+    for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
+       struct fs_stats_opTimingData *td = abuf->det.rpcOpTimes + i;
+       td->numOps = *p++;
+       td->numSuccesses = *p++;
+       DECODE_TV(td->sumTime);
+       DECODE_TV(td->sqrTime);
+       DECODE_TV(td->minTime);
+       DECODE_TV(td->maxTime);
+    }
+    for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
+       struct fs_stats_xferData *xd = abuf->det.xferOpTimes + i;
+       xd->numXfers = *p++;
+       xd->numSuccesses = *p++;
+       DECODE_TV(xd->sumTime);
+       DECODE_TV(xd->sqrTime);
+       DECODE_TV(xd->minTime);
+       DECODE_TV(xd->maxTime);
+       xd->sumBytes = *p++;
+       xd->minBytes = *p++;
+       xd->maxBytes = *p++;
+       memcpy((void *)xd->count, (void *)p,
+              sizeof(afs_int32) * FS_STATS_NUM_XFER_BUCKETS);
+       p += FS_STATS_NUM_XFER_BUCKETS;
+    }
+    *aout = abuf;
+    return 0;
+#undef DECODE_TV
+}
index fd45b3b..6e2b77b 100644 (file)
@@ -145,4 +145,12 @@ extern int xstat_fs_Cleanup(int);
      *          with the xstat_fs connection array.
      */
 
+/*
+ * Decode the full performance statistics collection data.
+ */
+extern int xstat_fs_DecodeFullPerfStats(struct fs_stats_FullPerfStats **stats,
+                                       afs_int32 * ain, afs_int32 alen,
+                                       struct fs_stats_FullPerfStats
+                                       *buffer);
+
 #endif /* _xstat_fs_h_ */
index 76f6842..c90fd03 100644 (file)
@@ -385,33 +385,34 @@ PrintDetailedPerfInfo(struct fs_stats_DetailedStats *a_detP)
 void
 PrintFullPerfInfo(void)
 {
-
-    static afs_int32 fullPerfInt32s = (sizeof(struct fs_stats_FullPerfStats) >> 2);    /*Correct # int32s to rcv */
-    afs_int32 numInt32s;       /*# int32words received */
+    int code;
     struct fs_stats_FullPerfStats *fullPerfP;  /*Ptr to full perf stats */
+    struct fs_stats_FullPerfStats buffer;  /* to decode the stats */
     char *printableTime;       /*Ptr to printable time
                                 * string */
     time_t probeTime = xstat_fs_Results.probeTime;
-
-    numInt32s = xstat_fs_Results.data.AFS_CollData_len;
-    if (numInt32s != fullPerfInt32s) {
-       printf("** Data size mismatch in full performance collection!");
-       printf("** Expecting %u, got %u\n", fullPerfInt32s, numInt32s);
-       return;
-    }
+    static afs_int32 fullPerfInt32s = (sizeof(struct fs_stats_FullPerfStats) >> 2);    /*Correct # int32s to rcv */
 
     printableTime = ctime(&probeTime);
     printableTime[strlen(printableTime) - 1] = '\0';
-    fullPerfP = (struct fs_stats_FullPerfStats *)
-       (xstat_fs_Results.data.AFS_CollData_val);
-
     printf
        ("AFS_XSTATSCOLL_FULL_PERF_INFO (coll %d) for FS %s\n[Probe %u, %s]\n\n",
         xstat_fs_Results.collectionNumber, xstat_fs_Results.connP->hostName,
         xstat_fs_Results.probeNum, printableTime);
 
-    PrintOverallPerfInfo(&(fullPerfP->overall));
-    PrintDetailedPerfInfo(&(fullPerfP->det));
+    code =
+       xstat_fs_DecodeFullPerfStats(&fullPerfP,
+                                    xstat_fs_Results.data.AFS_CollData_val,
+                                    xstat_fs_Results.data.AFS_CollData_len,
+                                    &buffer);
+    if (code) {
+       afs_int32 numInt32s = xstat_fs_Results.data.AFS_CollData_len;   /*# int32words received */
+       printf("** Data size mismatch in full performance collection!\n");
+       printf("** Expecting %u, got %u\n", fullPerfInt32s, numInt32s);
+    } else {
+       PrintOverallPerfInfo(&(fullPerfP->overall));
+       PrintDetailedPerfInfo(&(fullPerfP->det));
+    }
 }