]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
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>
Mon, 6 Jun 2011 03:32:04 +0000 (20:32 -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.

Reviewed-on: http://gerrit.openafs.org/2986
Tested-by: Derrick Brashear <shadow@dementia.org>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
(cherry picked from commit c0a55111d726b26d07661957a65e4d59f155d5e6)

Change-Id: I3bef968538c90d6e261142c60a817b4b9e2ad228
Reviewed-on: http://gerrit.openafs.org/4791
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-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 e2322d227a3eef5b325af2779bf15d85d12ccb66..67ed97aea6be37c2535d41e844988ea61a4fd933 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 d608140b5ceb56b9a7901b515f6df9d636101c5c..e9b99d51c9ff3b53f5e0c65cf248168f49892438 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 952a95dc08964160b4936aa2302325c22af2ba32..b5f1c466ea848fb475f019afbfbd95a6b1aff64a 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 7fa7b34151016e0a02779b1cf8c7a8ef50e824ef..f79f4876a74600e607a9341f7b44decb982301e3 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 fd45b3b7facbe98958b9d5207e82cc0003fcc78e..6e2b77b858c0473be0d05f178ce6e0cb7e98535f 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 4409e2ae172b63d0d1656af50e65a277defc55eb..3be314e414b839db00f07c39ee0e6c5d655f9375 100644 (file)
@@ -402,33 +402,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));
+    }
 }