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));
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;
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",
{
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;
}
*/
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
+}
* 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_ */
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));
+ }
}