a6e844771387cf76aa84501bc0ab2b3ea9af7dfa
[openafs.git] / src / afsmonitor / afsmon-output.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Module:      afsmon-output.c
12  *              Outputs the xstat probe results to a file
13  *              Most of this code is taken from xstat_fs_test.c and
14  *              xstat_cm_test.c
15  *
16  *-------------------------------------------------------------------------*/
17
18 #include <stdio.h>
19 #include <time.h>
20 #include <afsconfig.h>
21 #include <afs/param.h>
22 #include <string.h>
23
24
25 #include <afs/xstat_fs.h>
26 #include <afs/xstat_cm.h>
27
28 #include "afsmonitor.h"
29
30
31 /* Extern Variables */
32 extern int afsmon_debug;        /* debugging on ? */
33 extern FILE *debugFD;           /* debug file FD */
34 extern char errMsg[256];        /* error message buffer */
35
36 static FILE *fs_outFD;          /* fs output file descriptor */
37 static FILE *cm_outFD;          /* cm output file descriptor */
38
39 /* structures used by FS & CM stats print routines */
40
41 static char *fsOpNames[] = {
42     "FetchData",
43     "FetchACL",
44     "FetchStatus",
45     "StoreData",
46     "StoreACL",
47     "StoreStatus",
48     "RemoveFile",
49     "CreateFile",
50     "Rename",
51     "Symlink",
52     "Link",
53     "MakeDir",
54     "RemoveDir",
55     "SetLock",
56     "ExtendLock",
57     "ReleaseLock",
58     "GetStatistics",
59     "GiveUpCallbacks",
60     "GetVolumeInfo",
61     "GetVolumeStatus",
62     "SetVolumeStatus",
63     "GetRootVolume",
64     "CheckToken",
65     "GetTime",
66     "NGetVolumeInfo",
67     "BulkStatus",
68     "XStatsVersion",
69     "GetXStats"
70 };
71
72 static char *cmOpNames[] = {
73     "CallBack",
74     "InitCallBackState",
75     "Probe",
76     "GetLock",
77     "GetCE",
78     "XStatsVersion",
79     "GetXStats"
80 };
81
82 static char *xferOpNames[] = {
83     "FetchData",
84     "StoreData"
85 };
86
87 static char *CbCounterStrings[] = {
88     "DeleteFiles",
89     "DeleteCallBacks",
90     "BreakCallBacks",
91     "AddCallBack",
92     "GotSomeSpaces",
93     "DeleteAllCallBacks",
94     "nFEs",
95     "nCBs",
96     "nblks",
97     "CBsTimedOut",
98     "nbreakers",
99     "GSS1",
100     "GSS2",
101     "GSS3",
102     "GSS4",
103     "GSS5"
104 };
105
106 /*________________________________________________________________________
107                                 FS STATS ROUTINES 
108  *_______________________________________________________________________*/
109
110 /*------------------------------------------------------------------------
111  * Print_fs_OverallPerfInfo
112  *
113  * Description:
114  *      Print out overall performance numbers.
115  *
116  * Arguments:
117  *      a_ovP : Ptr to the overall performance numbers.
118  *
119  * Returns:
120  *      Nothing.
121  *
122  * Environment:
123  *      Nothing interesting.
124  *
125  * Side Effects:
126  *      As advertised.
127  *------------------------------------------------------------------------*/
128
129 void
130 Print_fs_OverallPerfInfo(struct afs_PerfStats *a_ovP)
131 {                               /*Print_fs_OverallPerfInfo */
132
133     fprintf(fs_outFD, "\t%10d numPerfCalls\n\n", a_ovP->numPerfCalls);
134
135
136     /*
137      * Vnode cache section.
138      */
139     fprintf(fs_outFD, "\t%10d vcache_L_Entries\n", a_ovP->vcache_L_Entries);
140     fprintf(fs_outFD, "\t%10d vcache_L_Allocs\n", a_ovP->vcache_L_Allocs);
141     fprintf(fs_outFD, "\t%10d vcache_L_Gets\n", a_ovP->vcache_L_Gets);
142     fprintf(fs_outFD, "\t%10d vcache_L_Reads\n", a_ovP->vcache_L_Reads);
143     fprintf(fs_outFD, "\t%10d vcache_L_Writes\n\n", a_ovP->vcache_L_Writes);
144
145     fprintf(fs_outFD, "\t%10d vcache_S_Entries\n", a_ovP->vcache_S_Entries);
146     fprintf(fs_outFD, "\t%10d vcache_S_Allocs\n", a_ovP->vcache_S_Allocs);
147     fprintf(fs_outFD, "\t%10d vcache_S_Gets\n", a_ovP->vcache_S_Gets);
148     fprintf(fs_outFD, "\t%10d vcache_S_Reads\n", a_ovP->vcache_S_Reads);
149     fprintf(fs_outFD, "\t%10d vcache_S_Writes\n\n", a_ovP->vcache_S_Writes);
150
151     fprintf(fs_outFD, "\t%10d vcache_H_Entries\n", a_ovP->vcache_H_Entries);
152     fprintf(fs_outFD, "\t%10d vcache_H_Gets\n", a_ovP->vcache_H_Gets);
153     fprintf(fs_outFD, "\t%10d vcache_H_Replacements\n\n",
154             a_ovP->vcache_H_Replacements);
155
156     /*
157      * Directory package section.
158      */
159     fprintf(fs_outFD, "\t%10d dir_Buffers\n", a_ovP->dir_Buffers);
160     fprintf(fs_outFD, "\t%10d dir_Calls\n", a_ovP->dir_Calls);
161     fprintf(fs_outFD, "\t%10d dir_IOs\n\n", a_ovP->dir_IOs);
162
163     /*
164      * Rx section.
165      */
166     fprintf(fs_outFD, "\t%10d rx_packetRequests\n", a_ovP->rx_packetRequests);
167     fprintf(fs_outFD, "\t%10d rx_noPackets_RcvClass\n",
168             a_ovP->rx_noPackets_RcvClass);
169     fprintf(fs_outFD, "\t%10d rx_noPackets_SendClass\n",
170             a_ovP->rx_noPackets_SendClass);
171     fprintf(fs_outFD, "\t%10d rx_noPackets_SpecialClass\n",
172             a_ovP->rx_noPackets_SpecialClass);
173     fprintf(fs_outFD, "\t%10d rx_socketGreedy\n", a_ovP->rx_socketGreedy);
174     fprintf(fs_outFD, "\t%10d rx_bogusPacketOnRead\n",
175             a_ovP->rx_bogusPacketOnRead);
176     fprintf(fs_outFD, "\t%10d rx_bogusHost\n", a_ovP->rx_bogusHost);
177     fprintf(fs_outFD, "\t%10d rx_noPacketOnRead\n", a_ovP->rx_noPacketOnRead);
178     fprintf(fs_outFD, "\t%10d rx_noPacketBuffersOnRead\n",
179             a_ovP->rx_noPacketBuffersOnRead);
180     fprintf(fs_outFD, "\t%10d rx_selects\n", a_ovP->rx_selects);
181     fprintf(fs_outFD, "\t%10d rx_sendSelects\n", a_ovP->rx_sendSelects);
182     fprintf(fs_outFD, "\t%10d rx_packetsRead_RcvClass\n",
183             a_ovP->rx_packetsRead_RcvClass);
184     fprintf(fs_outFD, "\t%10d rx_packetsRead_SendClass\n",
185             a_ovP->rx_packetsRead_SendClass);
186     fprintf(fs_outFD, "\t%10d rx_packetsRead_SpecialClass\n",
187             a_ovP->rx_packetsRead_SpecialClass);
188     fprintf(fs_outFD, "\t%10d rx_dataPacketsRead\n",
189             a_ovP->rx_dataPacketsRead);
190     fprintf(fs_outFD, "\t%10d rx_ackPacketsRead\n", a_ovP->rx_ackPacketsRead);
191     fprintf(fs_outFD, "\t%10d rx_dupPacketsRead\n", a_ovP->rx_dupPacketsRead);
192     fprintf(fs_outFD, "\t%10d rx_spuriousPacketsRead\n",
193             a_ovP->rx_spuriousPacketsRead);
194     fprintf(fs_outFD, "\t%10d rx_packetsSent_RcvClass\n",
195             a_ovP->rx_packetsSent_RcvClass);
196     fprintf(fs_outFD, "\t%10d rx_packetsSent_SendClass\n",
197             a_ovP->rx_packetsSent_SendClass);
198     fprintf(fs_outFD, "\t%10d rx_packetsSent_SpecialClass\n",
199             a_ovP->rx_packetsSent_SpecialClass);
200     fprintf(fs_outFD, "\t%10d rx_ackPacketsSent\n", a_ovP->rx_ackPacketsSent);
201     fprintf(fs_outFD, "\t%10d rx_pingPacketsSent\n",
202             a_ovP->rx_pingPacketsSent);
203     fprintf(fs_outFD, "\t%10d rx_abortPacketsSent\n",
204             a_ovP->rx_abortPacketsSent);
205     fprintf(fs_outFD, "\t%10d rx_busyPacketsSent\n",
206             a_ovP->rx_busyPacketsSent);
207     fprintf(fs_outFD, "\t%10d rx_dataPacketsSent\n",
208             a_ovP->rx_dataPacketsSent);
209     fprintf(fs_outFD, "\t%10d rx_dataPacketsReSent\n",
210             a_ovP->rx_dataPacketsReSent);
211     fprintf(fs_outFD, "\t%10d rx_dataPacketsPushed\n",
212             a_ovP->rx_dataPacketsPushed);
213     fprintf(fs_outFD, "\t%10d rx_ignoreAckedPacket\n",
214             a_ovP->rx_ignoreAckedPacket);
215     fprintf(fs_outFD, "\t%10d rx_totalRtt_Sec\n", a_ovP->rx_totalRtt_Sec);
216     fprintf(fs_outFD, "\t%10d rx_totalRtt_Usec\n", a_ovP->rx_totalRtt_Usec);
217     fprintf(fs_outFD, "\t%10d rx_minRtt_Sec\n", a_ovP->rx_minRtt_Sec);
218     fprintf(fs_outFD, "\t%10d rx_minRtt_Usec\n", a_ovP->rx_minRtt_Usec);
219     fprintf(fs_outFD, "\t%10d rx_maxRtt_Sec\n", a_ovP->rx_maxRtt_Sec);
220     fprintf(fs_outFD, "\t%10d rx_maxRtt_Usec\n", a_ovP->rx_maxRtt_Usec);
221     fprintf(fs_outFD, "\t%10d rx_nRttSamples\n", a_ovP->rx_nRttSamples);
222     fprintf(fs_outFD, "\t%10d rx_nServerConns\n", a_ovP->rx_nServerConns);
223     fprintf(fs_outFD, "\t%10d rx_nClientConns\n", a_ovP->rx_nClientConns);
224     fprintf(fs_outFD, "\t%10d rx_nPeerStructs\n", a_ovP->rx_nPeerStructs);
225     fprintf(fs_outFD, "\t%10d rx_nCallStructs\n", a_ovP->rx_nCallStructs);
226     fprintf(fs_outFD, "\t%10d rx_nFreeCallStructs\n\n",
227             a_ovP->rx_nFreeCallStructs);
228
229     /*
230      * Host module fields.
231      */
232     fprintf(fs_outFD, "\t%10d host_NumHostEntries\n",
233             a_ovP->host_NumHostEntries);
234     fprintf(fs_outFD, "\t%10d host_HostBlocks\n", a_ovP->host_HostBlocks);
235     fprintf(fs_outFD, "\t%10d host_NonDeletedHosts\n",
236             a_ovP->host_NonDeletedHosts);
237     fprintf(fs_outFD, "\t%10d host_HostsInSameNetOrSubnet\n",
238             a_ovP->host_HostsInSameNetOrSubnet);
239     fprintf(fs_outFD, "\t%10d host_HostsInDiffSubnet\n",
240             a_ovP->host_HostsInDiffSubnet);
241     fprintf(fs_outFD, "\t%10d host_HostsInDiffNetwork\n",
242             a_ovP->host_HostsInDiffNetwork);
243     fprintf(fs_outFD, "\t%10d host_NumClients\n", a_ovP->host_NumClients);
244     fprintf(fs_outFD, "\t%10d host_ClientBlocks\n\n",
245             a_ovP->host_ClientBlocks);
246
247 }                               /*Print_fs_OverallPerfInfo */
248
249
250 /*------------------------------------------------------------------------
251  * Print_fs_OpTiming
252  *
253  * Description:
254  *      Print out the contents of an RPC op timing structure.
255  *
256  * Arguments:
257  *      a_opIdx   : Index of the AFS operation we're printing number on.
258  *      a_opTimeP : Ptr to the op timing structure to print.
259  *
260  * Returns:
261  *      Nothing.
262  *
263  * Environment:
264  *      Nothing interesting.
265  *
266  * Side Effects:
267  *      As advertised.
268  *------------------------------------------------------------------------*/
269
270 void
271 Print_fs_OpTiming(int a_opIdx, struct fs_stats_opTimingData *a_opTimeP)
272 {                               /*Print_fs_OpTiming */
273
274     fprintf(fs_outFD,
275             "%15s: %d ops (%d OK); sum=%ld.%06ld, min=%ld.%06ld, max=%ld.%06ld\n",
276             fsOpNames[a_opIdx], a_opTimeP->numOps, a_opTimeP->numSuccesses,
277             (long)a_opTimeP->sumTime.tv_sec, (long)a_opTimeP->sumTime.tv_usec,
278             (long)a_opTimeP->minTime.tv_sec, (long)a_opTimeP->minTime.tv_usec,
279             (long)a_opTimeP->maxTime.tv_sec, (long)a_opTimeP->maxTime.tv_usec);
280
281 }                               /*Print_fs_OpTiming */
282
283
284 /*------------------------------------------------------------------------
285  * Print_fs_XferTiming
286  *
287  * Description:
288  *      Print out the contents of a data transfer structure.
289  *
290  * Arguments:
291  *      a_opIdx : Index of the AFS operation we're printing number on.
292  *      a_xferP : Ptr to the data transfer structure to print.
293  *
294  * Returns:
295  *      Nothing.
296  *
297  * Environment:
298  *      Nothing interesting.
299  *
300  * Side Effects:
301  *      As advertised.
302  *------------------------------------------------------------------------*/
303
304 void
305 Print_fs_XferTiming(int a_opIdx, struct fs_stats_xferData *a_xferP)
306 {                               /*Print_fs_XferTiming */
307
308     fprintf(fs_outFD,
309             "%s: %d xfers (%d OK), time sum=%ld.%06ld, min=%ld.%06ld, max=%ld.%06ld\n",
310             xferOpNames[a_opIdx], a_xferP->numXfers, a_xferP->numSuccesses,
311             (long)a_xferP->sumTime.tv_sec, (long)a_xferP->sumTime.tv_usec,
312             (long)a_xferP->minTime.tv_sec, (long)a_xferP->minTime.tv_usec,
313             (long)a_xferP->maxTime.tv_sec, (long)a_xferP->maxTime.tv_usec);
314     fprintf(fs_outFD, "\t[bytes: sum=%d, min=%d, max=%d]\n",
315             a_xferP->sumBytes, a_xferP->minBytes, a_xferP->maxBytes);
316     fprintf(fs_outFD,
317             "\t[buckets: 0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d 6: %d, 7: %d, 8: %d]\n",
318             a_xferP->count[0], a_xferP->count[1], a_xferP->count[2],
319             a_xferP->count[3], a_xferP->count[4], a_xferP->count[5],
320             a_xferP->count[6], a_xferP->count[7], a_xferP->count[8]);
321
322 }                               /*Print_fs_XferTiming */
323
324
325 /*------------------------------------------------------------------------
326  * Print_fs_DetailedPerfInfo
327  *
328  * Description:
329  *      Print out a set of detailed performance numbers.
330  *
331  * Arguments:
332  *      a_detP : Ptr to detailed perf numbers to print.
333  *
334  * Returns:
335  *      Nothing.
336  *
337  * Environment:
338  *      Nothing interesting.
339  *
340  * Side Effects:
341  *      As advertised.
342  *------------------------------------------------------------------------*/
343
344 void
345 Print_fs_DetailedPerfInfo(struct fs_stats_DetailedStats *a_detP)
346 {                               /*Print_fs_DetailedPerfInfo */
347
348     int currIdx;                /*Loop variable */
349
350     fprintf(fs_outFD, "\t%10ld epoch\n", (long)a_detP->epoch.tv_sec);
351
352     for (currIdx = 0; currIdx < FS_STATS_NUM_RPC_OPS; currIdx++)
353         Print_fs_OpTiming(currIdx, &(a_detP->rpcOpTimes[currIdx]));
354
355     for (currIdx = 0; currIdx < FS_STATS_NUM_XFER_OPS; currIdx++)
356         Print_fs_XferTiming(currIdx, &(a_detP->xferOpTimes[currIdx]));
357
358 }                               /*Print_fs_DetailedPerfInfo */
359
360
361 /*------------------------------------------------------------------------
362  * Print_fs_FullPerfInfo
363  *
364  * Description:
365  *      Print out the AFS_XSTATSCOLL_FULL_PERF_INFO collection we just
366  *      received.
367  *
368  * Arguments:
369  *      None.
370  *
371  * Returns:
372  *      Nothing.
373  *
374  * Environment:
375  *      All the info we need is nestled into xstat_fs_Results.
376  *
377  * Side Effects:
378  *      As advertised.
379  *------------------------------------------------------------------------*/
380
381 void
382 Print_fs_FullPerfInfo(struct xstat_fs_ProbeResults *a_fs_Results)
383 {                               /*Print_fs_FullPerfInfo */
384     static afs_int32 fullPerfLongs = (sizeof(struct fs_stats_FullPerfStats) >> 2);      /*Correct # longs to rcv */
385     afs_int32 numLongs;         /*# longwords received */
386     struct fs_stats_FullPerfStats *fullPerfP;   /*Ptr to full perf stats */
387     char *printableTime;        /*Ptr to printable time string */
388     time_t probeTime;
389
390
391     probeTime = a_fs_Results->probeTime;
392     printableTime = ctime(&probeTime);
393     printableTime[strlen(printableTime) - 1] = '\0';
394     fullPerfP = (struct fs_stats_FullPerfStats *)
395         (a_fs_Results->data.AFS_CollData_val);
396
397     fprintf(fs_outFD,
398             "AFS_XSTATSCOLL_FULL_PERF_INFO (coll %d) for FS %s\n[Probe %d, %s]\n\n",
399             a_fs_Results->collectionNumber, a_fs_Results->connP->hostName,
400             a_fs_Results->probeNum, printableTime);
401
402     numLongs = a_fs_Results->data.AFS_CollData_len;
403     if (numLongs != fullPerfLongs) {
404         fprintf(fs_outFD,
405                 " ** Data size mismatch in full performance collection!\n");
406         fprintf(fs_outFD, " ** Expecting %d, got %d\n", fullPerfLongs,
407                 numLongs);
408
409         /* Unfortunately, the full perf stats contain timeval structures which
410          * do not have the same size everywhere. At least try to print
411          * the overall stats.
412          */
413         if (numLongs >= (sizeof(struct afs_stats_CMPerf) / sizeof(afs_int32))) {
414             Print_fs_OverallPerfInfo(&(fullPerfP->overall));
415         }
416     } else {
417         Print_fs_OverallPerfInfo(&(fullPerfP->overall));
418         Print_fs_DetailedPerfInfo(&(fullPerfP->det));
419     }
420
421 }                               /*Print_fs_FullPerfInfo */
422
423 /*------------------------------------------------------------------------
424  * Print_fs_CallbackStats
425  *
426  * Description:
427  *      Print out the AFS_XSTATSCOLL_CBSTATS collection we just
428  *      received.
429  *
430  * Arguments:
431  *      None.
432  *
433  * Returns:
434  *      Nothing.
435  *
436  * Environment:
437  *      All the info we need is nestled into xstat_fs_Results.
438  *
439  * Side Effects:
440  *      As advertised.
441  *------------------------------------------------------------------------*/
442 void
443 Print_fs_CallBackStats(struct xstat_fs_ProbeResults *a_fs_Results)
444 {
445     char *printableTime;
446     time_t probeTime;
447     int numInt32s = xstat_fs_Results.data.AFS_CollData_len;
448     afs_int32 *val = xstat_fs_Results.data.AFS_CollData_val;
449     int i;
450
451     probeTime = a_fs_Results->probeTime;
452     printableTime = ctime(&probeTime);
453     printableTime[strlen(printableTime) - 1] = '\0';
454     fprintf(fs_outFD,
455             "AFS_XSTATSCOLL_CBSTATS (coll %d) for FS %s\n[Probe %d, %s]\n\n",
456             a_fs_Results->collectionNumber, a_fs_Results->connP->hostName,
457             a_fs_Results->probeNum, printableTime);
458
459     numInt32s = min(numInt32s, sizeof(CbCounterStrings)/sizeof(*CbCounterStrings));
460     for (i=0; i<numInt32s; i++) {
461         fprintf(fs_outFD, "\t%10u %s\n", val[i], CbCounterStrings[i]);
462     }
463 }                               /*Print_fs_CallbackStats */
464
465 /*------------------------------------------------------------------------
466  * afsmon_fsOutput()
467  *
468  * Description:
469  *      Prints the contents of xstat_fs_Results to an output file. The 
470  *      output is either in a compact (longs only) format or a detailed
471  *      format giving the names of each of the datums. Output is appended.
472  *
473  * Arguments:
474  *      Name of output file.
475  *      Flag to indicate if detailed output is required.
476  *
477  * Returns:
478  *      Nothing.
479  *
480  * Environment:
481  *      All the info we need is nestled into xstat_fs_Results.
482  *
483  * Side Effects:
484  *      As advertised.
485  *------------------------------------------------------------------------*/
486 int
487 afsmon_fsOutput(char *a_outfile,        /* ptr to output file name */
488                 int a_detOutput)        /* detailed output ? */
489 {
490
491     static char rn[] = "afsmon_fsOutput";       /* routine name */
492     char *printTime;            /* ptr to time string */
493     char *hostname;             /* fileserner name */
494     afs_int32 numLongs;         /* longwords in result */
495     afs_int32 *currLong;        /* ptr to longwords in result */
496     int i;
497     time_t probeTime;
498
499     if (afsmon_debug) {
500         fprintf(debugFD, "[ %s ] Called, a_outfile= %s, a_detOutput= %d\n",
501                 rn, a_outfile, a_detOutput);
502         fflush(debugFD);
503     }
504
505     fs_outFD = fopen(a_outfile, "a");
506     if (fs_outFD == (FILE *) 0) {
507         sprintf(errMsg, "[ %s ] failed to open output file %s", rn,
508                 a_outfile);
509         afsmon_Exit(1);
510     }
511
512     /* get the probe time and strip the \n at the end */
513     probeTime = xstat_fs_Results.probeTime;
514     printTime = ctime(&probeTime);
515     printTime[strlen(printTime) - 1] = '\0';
516     hostname = xstat_fs_Results.connP->hostName;
517
518     /* print "time hostname FS" */
519     fprintf(fs_outFD, "\n%s %s FS ", printTime, hostname);
520
521     /* if probe failed print -1 and return */
522     if (xstat_fs_Results.probeOK) {
523         fprintf(fs_outFD, "-1\n");
524         fclose(fs_outFD);
525         return (0);
526     }
527
528     /* print out the probe information as  long words */
529     numLongs = xstat_fs_Results.data.AFS_CollData_len;
530     currLong = (afs_int32 *) (xstat_fs_Results.data.AFS_CollData_val);
531
532     for (i = 0; i < numLongs; i++) {
533         fprintf(fs_outFD, "%d ", *currLong++);
534     }
535     fprintf(fs_outFD, "\n\n");
536
537     /* print detailed information */
538     if (a_detOutput) {
539         if (xstat_fs_Results.collectionNumber ==
540             AFS_XSTATSCOLL_FULL_PERF_INFO) {
541             Print_fs_FullPerfInfo(&xstat_fs_Results);
542             fflush(fs_outFD);
543         } else if (xstat_fs_Results.collectionNumber ==
544                    AFS_XSTATSCOLL_CBSTATS) {
545             Print_fs_CallBackStats(&xstat_fs_Results);
546             fflush(fs_outFD);
547         }
548     }
549
550     if (fclose(fs_outFD))
551         if (afsmon_debug) {
552             fprintf(debugFD, "[ %s ] failed to close %s\n", rn, a_outfile);
553             fflush(debugFD);
554         }
555
556     return (0);
557 }
558
559 /*___________________________________________________________________________
560                         CM STATS
561  *__________________________________________________________________________*/
562
563
564
565 /*------------------------------------------------------------------------
566  * Print_cm_UpDownStats
567  *
568  * Description:
569  *      Print the up/downtime stats for the given class of server records
570  *      provided.
571  *
572  * Arguments:
573  *      a_upDownP : Ptr to the server up/down info.
574  *
575  * Returns:
576  *      Nothing.
577  *
578  * Environment:
579  *      Nothing interesting.
580  *
581  * Side Effects:
582  *      As advertised.
583  *------------------------------------------------------------------------*/
584
585 void
586 Print_cm_UpDownStats(struct afs_stats_SrvUpDownInfo *a_upDownP) /*Ptr to server up/down info */
587 {                               /*Print_cm_UpDownStats */
588
589     /*
590      * First, print the simple values.
591      */
592     fprintf(cm_outFD, "\t\t%10d numTtlRecords\n", a_upDownP->numTtlRecords);
593     fprintf(cm_outFD, "\t\t%10d numUpRecords\n", a_upDownP->numUpRecords);
594     fprintf(cm_outFD, "\t\t%10d numDownRecords\n", a_upDownP->numDownRecords);
595     fprintf(cm_outFD, "\t\t%10d sumOfRecordAges\n",
596             a_upDownP->sumOfRecordAges);
597     fprintf(cm_outFD, "\t\t%10d ageOfYoungestRecord\n",
598             a_upDownP->ageOfYoungestRecord);
599     fprintf(cm_outFD, "\t\t%10d ageOfOldestRecord\n",
600             a_upDownP->ageOfOldestRecord);
601     fprintf(cm_outFD, "\t\t%10d numDowntimeIncidents\n",
602             a_upDownP->numDowntimeIncidents);
603     fprintf(cm_outFD, "\t\t%10d numRecordsNeverDown\n",
604             a_upDownP->numRecordsNeverDown);
605     fprintf(cm_outFD, "\t\t%10d maxDowntimesInARecord\n",
606             a_upDownP->maxDowntimesInARecord);
607     fprintf(cm_outFD, "\t\t%10d sumOfDowntimes\n", a_upDownP->sumOfDowntimes);
608     fprintf(cm_outFD, "\t\t%10d shortestDowntime\n",
609             a_upDownP->shortestDowntime);
610     fprintf(cm_outFD, "\t\t%10d longestDowntime\n",
611             a_upDownP->longestDowntime);
612
613     /*
614      * Now, print the array values.
615      */
616     fprintf(cm_outFD, "\t\tDowntime duration distribution:\n");
617     fprintf(cm_outFD, "\t\t\t%8d: 0 min .. 10 min\n",
618             a_upDownP->downDurations[0]);
619     fprintf(cm_outFD, "\t\t\t%8d: 10 min .. 30 min\n",
620             a_upDownP->downDurations[1]);
621     fprintf(cm_outFD, "\t\t\t%8d: 30 min .. 1 hr\n",
622             a_upDownP->downDurations[2]);
623     fprintf(cm_outFD, "\t\t\t%8d: 1 hr .. 2 hr\n",
624             a_upDownP->downDurations[3]);
625     fprintf(cm_outFD, "\t\t\t%8d: 2 hr .. 4 hr\n",
626             a_upDownP->downDurations[4]);
627     fprintf(cm_outFD, "\t\t\t%8d: 4 hr .. 8 hr\n",
628             a_upDownP->downDurations[5]);
629     fprintf(cm_outFD, "\t\t\t%8d: > 8 hr\n", a_upDownP->downDurations[6]);
630
631     fprintf(cm_outFD, "\t\tDowntime incident distribution:\n");
632     fprintf(cm_outFD, "\t\t\t%8d: 0 times\n", a_upDownP->downIncidents[0]);
633     fprintf(cm_outFD, "\t\t\t%8d: 1 time\n", a_upDownP->downIncidents[1]);
634     fprintf(cm_outFD, "\t\t\t%8d: 2 .. 5 times\n",
635             a_upDownP->downIncidents[2]);
636     fprintf(cm_outFD, "\t\t\t%8d: 6 .. 10 times\n",
637             a_upDownP->downIncidents[3]);
638     fprintf(cm_outFD, "\t\t\t%8d: 10 .. 50 times\n",
639             a_upDownP->downIncidents[4]);
640     fprintf(cm_outFD, "\t\t\t%8d: > 50 times\n", a_upDownP->downIncidents[5]);
641
642 }                               /*Print_cm_UpDownStats */
643
644
645 /*------------------------------------------------------------------------
646  * Print_cm_OverallPerfInfo
647  *
648  * Description:
649  *      Print out overall performance numbers.
650  *
651  * Arguments:
652  *      a_ovP : Ptr to the overall performance numbers.
653  *
654  * Returns:
655  *      Nothing.
656  *
657  * Environment:
658  *      All the info we need is nestled into xstat_cm_Results.
659  *
660  * Side Effects:
661  *      As advertised.
662  *------------------------------------------------------------------------*/
663
664 void
665 Print_cm_OverallPerfInfo(struct afs_stats_CMPerf *a_ovP)
666 {                               /*Print_cm_OverallPerfInfo */
667
668     fprintf(cm_outFD, "\t%10d numPerfCalls\n", a_ovP->numPerfCalls);
669
670     fprintf(cm_outFD, "\t%10d epoch\n", a_ovP->epoch);
671     fprintf(cm_outFD, "\t%10d numCellsVisible\n", a_ovP->numCellsVisible);
672     fprintf(cm_outFD, "\t%10d numCellsContacted\n", a_ovP->numCellsContacted);
673     fprintf(cm_outFD, "\t%10d dlocalAccesses\n", a_ovP->dlocalAccesses);
674     fprintf(cm_outFD, "\t%10d vlocalAccesses\n", a_ovP->vlocalAccesses);
675     fprintf(cm_outFD, "\t%10d dremoteAccesses\n", a_ovP->dremoteAccesses);
676     fprintf(cm_outFD, "\t%10d vremoteAccesses\n", a_ovP->vremoteAccesses);
677     fprintf(cm_outFD, "\t%10d cacheNumEntries\n", a_ovP->cacheNumEntries);
678     fprintf(cm_outFD, "\t%10d cacheBlocksTotal\n", a_ovP->cacheBlocksTotal);
679     fprintf(cm_outFD, "\t%10d cacheBlocksInUse\n", a_ovP->cacheBlocksInUse);
680     fprintf(cm_outFD, "\t%10d cacheBlocksOrig\n", a_ovP->cacheBlocksOrig);
681     fprintf(cm_outFD, "\t%10d cacheMaxDirtyChunks\n",
682             a_ovP->cacheMaxDirtyChunks);
683     fprintf(cm_outFD, "\t%10d cacheCurrDirtyChunks\n",
684             a_ovP->cacheCurrDirtyChunks);
685     fprintf(cm_outFD, "\t%10d dcacheHits\n", a_ovP->dcacheHits);
686     fprintf(cm_outFD, "\t%10d vcacheHits\n", a_ovP->vcacheHits);
687     fprintf(cm_outFD, "\t%10d dcacheMisses\n", a_ovP->dcacheMisses);
688     fprintf(cm_outFD, "\t%10d vcacheMisses\n", a_ovP->vcacheMisses);
689     fprintf(cm_outFD, "\t%10d cacheFilesReused\n", a_ovP->cacheFilesReused);
690     fprintf(cm_outFD, "\t%10d vcacheXAllocs\n", a_ovP->vcacheXAllocs);
691
692     fprintf(cm_outFD, "\t%10d bufAlloced\n", a_ovP->bufAlloced);
693     fprintf(cm_outFD, "\t%10d bufHits\n", a_ovP->bufHits);
694     fprintf(cm_outFD, "\t%10d bufMisses\n", a_ovP->bufMisses);
695     fprintf(cm_outFD, "\t%10d bufFlushDirty\n", a_ovP->bufFlushDirty);
696
697     fprintf(cm_outFD, "\t%10d LargeBlocksActive\n", a_ovP->LargeBlocksActive);
698     fprintf(cm_outFD, "\t%10d LargeBlocksAlloced\n",
699             a_ovP->LargeBlocksAlloced);
700     fprintf(cm_outFD, "\t%10d SmallBlocksActive\n", a_ovP->SmallBlocksActive);
701     fprintf(cm_outFD, "\t%10d SmallBlocksAlloced\n",
702             a_ovP->SmallBlocksAlloced);
703     fprintf(cm_outFD, "\t%10d OutStandingMemUsage\n",
704             a_ovP->OutStandingMemUsage);
705     fprintf(cm_outFD, "\t%10d OutStandingAllocs\n", a_ovP->OutStandingAllocs);
706     fprintf(cm_outFD, "\t%10d CallBackAlloced\n", a_ovP->CallBackAlloced);
707     fprintf(cm_outFD, "\t%10d CallBackFlushes\n", a_ovP->CallBackFlushes);
708
709     fprintf(cm_outFD, "\t%10d srvRecords\n", a_ovP->srvRecords);
710     fprintf(cm_outFD, "\t%10d srvNumBuckets\n", a_ovP->srvNumBuckets);
711     fprintf(cm_outFD, "\t%10d srvMaxChainLength\n", a_ovP->srvMaxChainLength);
712     fprintf(cm_outFD, "\t%10d srvMaxChainLengthHWM\n",
713             a_ovP->srvMaxChainLengthHWM);
714     fprintf(cm_outFD, "\t%10d srvRecordsHWM\n", a_ovP->srvRecordsHWM);
715
716     fprintf(cm_outFD, "\t%10d sysName_ID\n", a_ovP->sysName_ID);
717
718     fprintf(cm_outFD, "\tFile Server up/downtimes, same cell:\n");
719     Print_cm_UpDownStats(&(a_ovP->fs_UpDown[0]));
720
721     fprintf(cm_outFD, "\tFile Server up/downtimes, diff cell:\n");
722     Print_cm_UpDownStats(&(a_ovP->fs_UpDown[1]));
723
724     fprintf(cm_outFD, "\tVL Server up/downtimes, same cell:\n");
725     Print_cm_UpDownStats(&(a_ovP->vl_UpDown[0]));
726
727     fprintf(cm_outFD, "\tVL Server up/downtimes, diff cell:\n");
728     Print_cm_UpDownStats(&(a_ovP->vl_UpDown[1]));
729
730 }                               /*Print_cm_OverallPerfInfo */
731
732
733 /*------------------------------------------------------------------------
734  * Print_cm_PerfInfo
735  *
736  * Description:
737  *      Print out the AFSCB_XSTATSCOLL_PERF_INFO collection we just
738  *      received.
739  *
740  * Arguments:
741  *      None.
742  *
743  * Returns:
744  *      Nothing.
745  *
746  * Environment:
747  *      All the info we need is nestled into xstat_cm_Results.
748  *
749  * Side Effects:
750  *      As advertised.
751  *------------------------------------------------------------------------*/
752
753 void
754 Print_cm_PerfInfo(void)
755 {                               /*Print_cm_PerfInfo */
756     static afs_int32 perfLongs = (sizeof(struct afs_stats_CMPerf) >> 2);        /*Correct # longs to rcv */
757     afs_int32 numLongs;         /*# longwords received */
758     struct afs_stats_CMPerf *perfP;     /*Ptr to performance stats */
759     char *printableTime;        /*Ptr to printable time string */
760     time_t probeTime;
761
762     numLongs = xstat_cm_Results.data.AFSCB_CollData_len;
763     if (numLongs != perfLongs) {
764         fprintf(cm_outFD,
765                 " ** Data size mismatch in performance collection!\n");
766         fprintf(cm_outFD, "** Expecting %d, got %d\n", perfLongs, numLongs);
767         return;
768     }
769
770     probeTime = xstat_cm_Results.probeTime;
771     printableTime = ctime(&probeTime);
772     printableTime[strlen(printableTime) - 1] = '\0';
773     perfP = (struct afs_stats_CMPerf *)
774         (xstat_cm_Results.data.AFSCB_CollData_val);
775
776     fprintf(cm_outFD,
777             "AFSCB_XSTATSCOLL_PERF_INFO (coll %d) for CM %s\n[Probe %d, %s]\n\n",
778             xstat_cm_Results.collectionNumber,
779             xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
780             printableTime);
781
782     Print_cm_OverallPerfInfo(perfP);
783
784 }                               /*Print_cm_PerfInfo */
785
786
787 /*------------------------------------------------------------------------
788  * Print_cm_OpTiming
789  *
790  * Description:
791  *      Print out the contents of an FS RPC op timing structure.
792  *
793  * Arguments:
794  *      a_opIdx   : Index of the AFS operation we're printing number on.
795  *      a_opNames : Ptr to table of operaton names.
796  *      a_opTimeP : Ptr to the op timing structure to print.
797  *
798  * Returns:
799  *      Nothing.
800  *
801  * Environment:
802  *      Nothing interesting.
803  *
804  * Side Effects:
805  *      As advertised.
806  *------------------------------------------------------------------------*/
807
808 void
809 Print_cm_OpTiming(int a_opIdx, char *a_opNames[],
810                   struct afs_stats_opTimingData *a_opTimeP)
811 {                               /*Print_cm_OpTiming */
812
813     fprintf(cm_outFD,
814             "%15s: %d ops (%d OK); sum=%ld.%06ld, min=%ld.%06ld, max=%ld.%06ld\n",
815             a_opNames[a_opIdx], a_opTimeP->numOps, a_opTimeP->numSuccesses,
816             (long)a_opTimeP->sumTime.tv_sec, (long)a_opTimeP->sumTime.tv_usec,
817             (long)a_opTimeP->minTime.tv_sec, (long)a_opTimeP->minTime.tv_usec,
818             (long)a_opTimeP->maxTime.tv_sec, (long)a_opTimeP->maxTime.tv_usec);
819
820 }                               /*Print_cm_OpTiming */
821
822
823 /*------------------------------------------------------------------------
824  * Print_cm_XferTiming
825  *
826  * Description:
827  *      Print out the contents of a data transfer structure.
828  *
829  * Arguments:
830  *      a_opIdx : Index of the AFS operation we're printing number on.
831  *      a_xferP : Ptr to the data transfer structure to print.
832  *
833  * Returns:
834  *      Nothing.
835  *
836  * Environment:
837  *      Nothing interesting.
838  *
839  * Side Effects:
840  *      As advertised.
841  *------------------------------------------------------------------------*/
842
843 void
844 Print_cm_XferTiming(int a_opIdx, char *a_opNames[], 
845                     struct afs_stats_xferData *a_xferP)
846 {                               /*Print_cm_XferTiming */
847
848     fprintf(cm_outFD,
849             "%s: %d xfers (%d OK), time sum=%ld.%06ld, min=%ld.%06ld, max=%ld.%06ld\n",
850             a_opNames[a_opIdx], a_xferP->numXfers, a_xferP->numSuccesses,
851             (long)a_xferP->sumTime.tv_sec, (long)a_xferP->sumTime.tv_usec,
852             (long)a_xferP->minTime.tv_sec, (long)a_xferP->minTime.tv_usec,
853             (long)a_xferP->maxTime.tv_sec, (long)a_xferP->maxTime.tv_usec);
854     fprintf(cm_outFD, "\t[bytes: sum=%d, min=%d, max=%d]\n",
855             a_xferP->sumBytes, a_xferP->minBytes, a_xferP->maxBytes);
856     fprintf(cm_outFD,
857             "\t[buckets: 0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d 6: %d, 7: %d, 8: %d]\n",
858             a_xferP->count[0], a_xferP->count[1], a_xferP->count[2],
859             a_xferP->count[3], a_xferP->count[4], a_xferP->count[5],
860             a_xferP->count[6], a_xferP->count[7], a_xferP->count[8]);
861
862 }                               /*Print_cm_XferTiming */
863
864
865 /*------------------------------------------------------------------------
866  * Print_cm_ErrInfo
867  *
868  * Description:
869  *      Print out the contents of an FS RPC error info structure.
870  *
871  * Arguments:
872  *      a_opIdx   : Index of the AFS operation we're printing.
873  *      a_opNames : Ptr to table of operation names.
874  *      a_opErrP  : Ptr to the op timing structure to print.
875  *
876  * Returns:
877  *      Nothing.
878  *
879  * Environment:
880  *      Nothing interesting.
881  *
882  * Side Effects:
883  *      As advertised.
884  *------------------------------------------------------------------------*/
885
886 void
887 Print_cm_ErrInfo(int a_opIdx, char *a_opNames[],
888                  struct afs_stats_RPCErrors *a_opErrP)
889 {                               /*Print_cm_ErrInfo */
890
891     fprintf(cm_outFD,
892             "%15s: %d server, %d network, %d prot, %d vol, %d busies, %d other\n",
893             a_opNames[a_opIdx], a_opErrP->err_Server, a_opErrP->err_Network,
894             a_opErrP->err_Protection, a_opErrP->err_Volume,
895             a_opErrP->err_VolumeBusies, a_opErrP->err_Other);
896
897 }                               /*Print_cm_ErrInfo */
898
899
900 /*------------------------------------------------------------------------
901  * Print_cm_RPCPerfInfo
902  *
903  * Description:
904  *      Print out a set of RPC performance numbers.
905  *
906  * Arguments:
907  *      a_rpcP : Ptr to RPC perf numbers to print.
908  *
909  * Returns:
910  *      Nothing.
911  *
912  * Environment:
913  *      Nothing interesting.
914  *
915  * Side Effects:
916  *      As advertised.
917  *------------------------------------------------------------------------*/
918
919 void
920 Print_cm_RPCPerfInfo(struct afs_stats_RPCOpInfo *a_rpcP)
921 {                               /*Print_cm_RPCPerfInfo */
922
923     int currIdx;                /*Loop variable */
924
925     /*
926      * Print the contents of each of the opcode-related arrays.
927      */
928     fprintf(cm_outFD, "FS Operation Timings:\n---------------------\n");
929     for (currIdx = 0; currIdx < AFS_STATS_NUM_FS_RPC_OPS; currIdx++)
930         Print_cm_OpTiming(currIdx, fsOpNames, &(a_rpcP->fsRPCTimes[currIdx]));
931
932     fprintf(cm_outFD, "\nError Info:\n-----------\n");
933     for (currIdx = 0; currIdx < AFS_STATS_NUM_FS_RPC_OPS; currIdx++)
934         Print_cm_ErrInfo(currIdx, fsOpNames, &(a_rpcP->fsRPCErrors[currIdx]));
935
936     fprintf(cm_outFD, "\nTransfer timings:\n-----------------\n");
937     for (currIdx = 0; currIdx < AFS_STATS_NUM_FS_XFER_OPS; currIdx++)
938         Print_cm_XferTiming(currIdx, xferOpNames,
939                             &(a_rpcP->fsXferTimes[currIdx]));
940
941     fprintf(cm_outFD, "\nCM Operation Timings:\n---------------------\n");
942     for (currIdx = 0; currIdx < AFS_STATS_NUM_CM_RPC_OPS; currIdx++)
943         Print_cm_OpTiming(currIdx, cmOpNames, &(a_rpcP->cmRPCTimes[currIdx]));
944
945 }                               /*Print_cm_RPCPerfInfo */
946
947
948 /*------------------------------------------------------------------------
949  * Print_cm_FullPerfInfo
950  *
951  * Description:
952  *      Print out a set of full performance numbers.
953  *
954  * Arguments:
955  *      None.
956  *
957  * Returns:
958  *      Nothing.
959  *
960  * Environment:
961  *      Nothing interesting.
962  *
963  * Side Effects:
964  *      As advertised.
965  *------------------------------------------------------------------------*/
966
967 void
968 Print_cm_FullPerfInfo(void)
969 {                               /*Print_cm_FullPerfInfo */
970
971     struct afs_stats_AuthentInfo *authentP;     /*Ptr to authentication stats */
972     struct afs_stats_AccessInfo *accessinfP;    /*Ptr to access stats */
973     static afs_int32 fullPerfLongs = (sizeof(struct afs_stats_CMFullPerf) >> 2);        /*Correct #longs */
974     afs_int32 numLongs;         /*# longs actually received */
975     struct afs_stats_CMFullPerf *fullP; /*Ptr to full perf info */
976     time_t probeTime;
977     char *printableTime;        /*Ptr to printable time string */
978
979     numLongs = xstat_cm_Results.data.AFSCB_CollData_len;
980     if (numLongs != fullPerfLongs) {
981         fprintf(cm_outFD,
982                 " ** Data size mismatch in performance collection!\n");
983         fprintf(cm_outFD, " ** Expecting %d, got %d\n", fullPerfLongs,
984                 numLongs);
985         return;
986     }
987
988     probeTime = xstat_cm_Results.probeTime;
989     printableTime = ctime(&probeTime);
990     printableTime[strlen(printableTime) - 1] = '\0';
991     fullP = (struct afs_stats_CMFullPerf *)
992         (xstat_cm_Results.data.AFSCB_CollData_val);
993
994     fprintf(cm_outFD,
995             "AFSCB_XSTATSCOLL_FULL_PERF_INFO (coll %d) for CM %s\n[Probe %d, %s]\n\n",
996             xstat_cm_Results.collectionNumber,
997             xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
998             printableTime);
999
1000     /*
1001      * Print the overall numbers first, followed by all of the RPC numbers,
1002      * then each of the other groupings.
1003      */
1004     fprintf(cm_outFD,
1005             "Overall Performance Info:\n-------------------------\n");
1006     Print_cm_OverallPerfInfo(&(fullP->perf));
1007     fprintf(cm_outFD, "\n");
1008     Print_cm_RPCPerfInfo(&(fullP->rpc));
1009
1010     authentP = &(fullP->authent);
1011     fprintf(cm_outFD, "\nAuthentication info:\n--------------------\n");
1012     fprintf(cm_outFD,
1013             "\t%d PAGS, %d records (%d auth, %d unauth), %d max in PAG, chain max: %d\n",
1014             authentP->curr_PAGs, authentP->curr_Records,
1015             authentP->curr_AuthRecords, authentP->curr_UnauthRecords,
1016             authentP->curr_MaxRecordsInPAG, authentP->curr_LongestChain);
1017     fprintf(cm_outFD, "\t%d PAG creations, %d tkt updates\n",
1018             authentP->PAGCreations, authentP->TicketUpdates);
1019     fprintf(cm_outFD,
1020             "\t[HWMs: %d PAGS, %d records, %d max in PAG, chain max: %d]\n",
1021             authentP->HWM_PAGs, authentP->HWM_Records,
1022             authentP->HWM_MaxRecordsInPAG, authentP->HWM_LongestChain);
1023
1024     accessinfP = &(fullP->accessinf);
1025     fprintf(cm_outFD,
1026             "\n[Un]replicated accesses:\n------------------------\n");
1027     fprintf(cm_outFD,
1028             "\t%d unrep, %d rep, %d reps accessed, %d max reps/ref, %d first OK\n\n",
1029             accessinfP->unreplicatedRefs, accessinfP->replicatedRefs,
1030             accessinfP->numReplicasAccessed, accessinfP->maxReplicasPerRef,
1031             accessinfP->refFirstReplicaOK);
1032
1033     /* There really isn't any authorship info
1034      * authorP = &(fullP->author); */
1035
1036 }                               /*Print_cm_FullPerfInfo */
1037
1038 /*------------------------------------------------------------------------
1039  * afsmon_cmOutput()
1040  *
1041  * Description:
1042  *      Prints the contents of xstat_cm_Results to an output file. The 
1043  *      output is either in a compact (longs only) format or a detailed
1044  *      format giving the names of each of the datums. Output is appended.
1045  *
1046  * Arguments:
1047  *      Name of output file.
1048  *      Flag to indicate if detailed output is required.
1049  *
1050  * Returns:
1051  *      Nothing.
1052  *
1053  * Environment:
1054  *      All the info we need is nestled into xstat_cm_Results.
1055  *
1056  * Side Effects:
1057  *      As advertised.
1058  *------------------------------------------------------------------------*/
1059 int
1060 afsmon_cmOutput(char *a_outfile,                /* ptr to output file name */
1061                 int a_detOutput)                /* detailed output ? */
1062 {
1063
1064     static char rn[] = "afsmon_cmOutput";       /* routine name */
1065     char *printTime;            /* ptr to time string */
1066     char *hostname;             /* fileserner name */
1067     afs_int32 numLongs;         /* longwords in result */
1068     afs_int32 *currLong;        /* ptr to longwords in result */
1069     int i;
1070     time_t probeTime;
1071
1072     if (afsmon_debug) {
1073         fprintf(debugFD, "[ %s ] Called, a_outfile= %s, a_detOutput= %d\n",
1074                 rn, a_outfile, a_detOutput);
1075         fflush(debugFD);
1076     }
1077
1078     /* need to lock this file before writing */
1079     cm_outFD = fopen(a_outfile, "a");
1080     if (cm_outFD == (FILE *) 0) {
1081         sprintf(errMsg, "[ %s ] failed to open output file %s", rn,
1082                 a_outfile);
1083         afsmon_Exit(1);
1084     }
1085
1086     /* get the probe time and strip the \n at the end */
1087     probeTime = xstat_cm_Results.probeTime;
1088     printTime = ctime(&probeTime);
1089     printTime[strlen(printTime) - 1] = '\0';
1090     hostname = xstat_cm_Results.connP->hostName;
1091
1092     /* print "time hostname CM" prefix  */
1093     fprintf(cm_outFD, "\n%s %s CM ", printTime, hostname);
1094
1095     /* if probe failed print -1 and vanish */
1096     if (xstat_cm_Results.probeOK) {
1097         fprintf(cm_outFD, "-1\n");
1098         fclose(cm_outFD);
1099         return (0);
1100     }
1101
1102     /* print out the probe information as  long words */
1103     numLongs = xstat_cm_Results.data.AFSCB_CollData_len;
1104     currLong = (afs_int32 *) (xstat_cm_Results.data.AFSCB_CollData_val);
1105
1106     for (i = 0; i < numLongs; i++) {
1107         fprintf(cm_outFD, "%d ", *currLong++);
1108     }
1109     fprintf(cm_outFD, "\n\n");
1110
1111     /* print out detailed statistics */
1112     if (a_detOutput) {
1113         Print_cm_FullPerfInfo();
1114         fflush(cm_outFD);
1115     }
1116
1117     if (fclose(cm_outFD))
1118         if (afsmon_debug) {
1119             fprintf(debugFD, "[ %s ] failed to close %s\n", rn, a_outfile);
1120             fflush(debugFD);
1121         }
1122
1123     return (0);
1124 }