Windows: Implement cm_TGTLifeTime()
[openafs.git] / src / WINNT / afsd / cm_performance.c
1 /*
2  *  Copyright (c) 2008 - Secure Endpoints Inc.
3  */
4
5
6 #include <afsconfig.h>
7 #include <afs/param.h>
8 #include <roken.h>
9
10 #include <afs/stds.h>
11
12 #include <windows.h>
13 #include <winsock2.h>
14 #include <iphlpapi.h>
15 #include <stdlib.h>
16 #include <malloc.h>
17 #include <string.h>
18
19 #include "afsd.h"
20
21 static cm_fid_stats_t ** fidStatsHashTablep = NULL;
22 static afs_uint32        fidStatsHashTableSize = 0;
23
24 /*
25  * algorithm and implementation adapted from code written by
26  * Frank Pilhofer <fp@fpx.de>
27  */
28 afs_uint32 nearest_prime(afs_uint32 s)
29 {
30 #define TEST(f,x)       (*(f+(x)/16)&(1<<(((x)%16L)/2)))
31 #define SET(f,x)        *(f+(x)/16)|=1<<(((x)%16L)/2)
32     unsigned char *feld=NULL, *zzz;
33     afs_uint32 teste=1, mom, hits=1, count, max, alloc, largest_prime = 0;
34
35     max = s + 10000L;
36
37     while (feld==NULL)
38         zzz = feld = malloc (alloc=((max>>4)+1L));
39
40     for (count=0; count<alloc; count++)
41         *zzz++ = 0x00;
42
43     while ((teste+=2) < max) {
44         if (!TEST(feld, teste)) {
45             for (mom=3L*teste; mom<max; mom+=teste<<1)
46                 SET (feld, mom);
47         }
48     }
49
50     count=s-2;
51     if (s%2==0)
52         count++;
53     while ((count+=2)<max) {
54         if (!TEST(feld,count)) {
55             largest_prime = count;
56             break;
57         }
58     }
59     free (feld);
60     return largest_prime;
61 }
62
63 /* We never free these objects so we don't need to
64  * worry about reuse or tracking the allocations
65  *
66  * The management of the free allocation is not
67  * thread safe because we never expect this code
68  * to be called from more than one thread.
69  */
70 cm_fid_stats_t * cm_PerformanceGetNew(void)
71 {
72     static cm_fid_stats_t * allocp = NULL;
73     static afs_int32        allocSize = 0;
74     static afs_int32        nextFree = 0;
75
76     if (nextFree < allocSize)
77         return &allocp[nextFree++];
78
79     allocp = (cm_fid_stats_t *)malloc(32768);
80     if (allocp == NULL)
81         return NULL;
82
83     allocSize = 32768/sizeof(cm_fid_stats_t);
84     memset(allocp, 0, 32768);
85     nextFree = 1;
86     return allocp;
87 }
88
89 void cm_PerformanceInsertToHashTable(cm_fid_stats_t *statp)
90 {
91     afs_uint32 hash = statp->fid.hash % fidStatsHashTableSize;
92
93     statp->nextp = fidStatsHashTablep[hash];
94     fidStatsHashTablep[hash] = statp;
95 }
96
97 void cm_PerformanceAddSCache(cm_scache_t *scp)
98 {
99     cm_fid_stats_t * statp = cm_PerformanceGetNew();
100
101     if (!statp)
102         return;
103
104     lock_ObtainRead(&scp->rw);
105     if (!(scp->flags & CM_SCACHEFLAG_DELETED)) {
106         statp->fid = scp->fid;
107         statp->fileLength = scp->length;
108         statp->fileType   = scp->fileType;
109         statp->flags = CM_FIDSTATS_FLAG_HAVE_SCACHE;
110         lock_ConvertRToW(&scp->rw);
111         if (cm_HaveCallback(scp))
112             statp->flags |= CM_FIDSTATS_FLAG_CALLBACK;
113         lock_ConvertWToR(&scp->rw);
114         if (scp->flags & CM_SCACHEFLAG_RO)
115             statp->flags |= CM_FIDSTATS_FLAG_RO;
116         if (scp->flags & CM_SCACHEFLAG_PURERO)
117             statp->flags |= CM_FIDSTATS_FLAG_PURERO;
118     }
119     lock_ReleaseRead(&scp->rw);
120
121 #if 0
122     if (statp->fid.vnode == 1) {
123         cm_volume_t *volp = NULL;
124         cm_cell_t *cellp = NULL;
125         cm_req_t req;
126
127         cm_InitReq(&req);
128
129         cellp = cm_FindCellByID(statp->fid.cell, 0);
130         if (cellp) {
131             if (!cm_FindVolumeByID(cellp, statp->fid.volume, cm_rootUserp, &req, 0, &volp)) {
132                 statp->flags |= CM_FIDSTATS_HAVE_VOLUME;
133                 cm_PutVolume(volp);
134             }
135         }
136     }
137 #endif
138
139     cm_PerformanceInsertToHashTable(statp);
140 }
141
142
143 void cm_PerformanceTuningInit(void)
144 {
145     afs_uint32 i;
146     cm_scache_t *scp;
147     cm_volume_t *volp;
148     cm_buf_t *bp;
149     cm_fid_t fid;
150     afs_uint32 hash;
151     cm_fid_stats_t * statp;
152
153     fidStatsHashTableSize = nearest_prime(cm_data.stats/3);
154     if (fidStatsHashTableSize == 0)
155         fidStatsHashTableSize = cm_data.stats/3;
156     fidStatsHashTablep = (cm_fid_stats_t **)malloc(fidStatsHashTableSize * sizeof(cm_fid_stats_t *));
157     if (fidStatsHashTablep == NULL) {
158         fidStatsHashTableSize = 0;
159         return;
160     }
161
162     memset(fidStatsHashTablep, 0, fidStatsHashTableSize * sizeof(cm_fid_stats_t *));
163
164     lock_ObtainRead(&cm_scacheLock);
165     for (i=0; i<cm_data.scacheHashTableSize; i++) {
166         for (scp=cm_data.scacheHashTablep[i]; scp; scp=scp->nextp) {
167             if (scp->fid.cell == 0)
168                 continue;
169             lock_ReleaseRead(&cm_scacheLock);
170             cm_PerformanceAddSCache(scp);
171             lock_ObtainRead(&cm_scacheLock);
172         }
173     }
174     lock_ReleaseRead(&cm_scacheLock);
175
176     lock_ObtainRead(&cm_volumeLock);
177     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
178         if (volp->vol[RWVOL].ID) {
179             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[RWVOL].ID, 1, 1);
180             hash = fid.hash % fidStatsHashTableSize;
181
182             for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
183                 if (!cm_FidCmp(&fid, &statp->fid)) {
184                     statp->flags |= CM_FIDSTATS_FLAG_HAVE_VOLUME;
185                     break;
186                 }
187             }
188             if (!statp) {
189                 statp = cm_PerformanceGetNew();
190                 statp->fid = fid;
191                 statp->fileType = CM_SCACHETYPE_DIRECTORY;
192                 statp->flags = CM_FIDSTATS_FLAG_HAVE_VOLUME;
193                 cm_PerformanceInsertToHashTable(statp);
194             }
195         }
196         if (volp->vol[ROVOL].ID) {
197             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[ROVOL].ID, 1, 1);
198             hash = fid.hash % fidStatsHashTableSize;
199
200             for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
201                 if (!cm_FidCmp(&fid, &statp->fid)) {
202                     statp->flags |= CM_FIDSTATS_FLAG_HAVE_VOLUME;
203                     break;
204                 }
205             }
206             if (!statp) {
207                 statp = cm_PerformanceGetNew();
208                 statp->fid = fid;
209                 statp->fileType = CM_SCACHETYPE_DIRECTORY;
210                 statp->flags = CM_FIDSTATS_FLAG_HAVE_VOLUME | CM_FIDSTATS_FLAG_RO | CM_FIDSTATS_FLAG_PURERO;
211                 cm_PerformanceInsertToHashTable(statp);
212             }
213         }
214         if (volp->vol[BACKVOL].ID) {
215             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[BACKVOL].ID, 1, 1);
216             hash = fid.hash % fidStatsHashTableSize;
217
218             for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
219                 if (!cm_FidCmp(&fid, &statp->fid)) {
220                     statp->flags |= CM_FIDSTATS_FLAG_HAVE_VOLUME;
221                     break;
222                 }
223             }
224             if (!statp) {
225                 statp = cm_PerformanceGetNew();
226                 statp->fid = fid;
227                 statp->fileType = CM_SCACHETYPE_DIRECTORY;
228                 statp->flags = CM_FIDSTATS_FLAG_HAVE_VOLUME | CM_FIDSTATS_FLAG_RO;
229                 cm_PerformanceInsertToHashTable(statp);
230             }
231         }
232     }
233     lock_ReleaseRead(&cm_volumeLock);
234
235     lock_ObtainRead(&buf_globalLock);
236     for (bp = cm_data.buf_allp; bp; bp=bp->allp) {
237         int valid = 0;
238
239         if (bp->fid.cell == 0)
240             continue;
241
242         lock_ReleaseRead(&buf_globalLock);
243         scp = cm_FindSCache(&bp->fid);
244         if (scp) {
245             lock_ObtainMutex(&bp->mx);
246             lock_ObtainRead(&scp->rw);
247             valid = cm_HaveBuffer(scp, bp, TRUE);
248             lock_ReleaseRead(&scp->rw);
249             lock_ReleaseMutex(&bp->mx);
250             cm_ReleaseSCache(scp);
251
252             if (valid) {
253                 hash = bp->fid.hash % fidStatsHashTableSize;
254                 for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
255                     if (!cm_FidCmp(&bp->fid, &statp->fid)) {
256                         statp->buffers++;
257                         break;
258                     }
259                 }
260             }
261         }
262         lock_ObtainRead(&buf_globalLock);
263     }
264     lock_ReleaseRead(&buf_globalLock);
265
266     cm_PerformancePrintReport();
267 }
268
269 void cm_PerformanceTuningCheck(void)
270 {
271     afs_uint32 i;
272     cm_scache_t *scp;
273     cm_volume_t *volp;
274     cm_buf_t *bp;
275     cm_fid_t fid;
276     afs_uint32 hash;
277     cm_fid_stats_t * statp;
278
279     if (fidStatsHashTablep == NULL)
280         return;
281
282     /* Clean all cm_fid_stat_t objects first */
283     for (i = 0; i < fidStatsHashTableSize; i++) {
284         for (statp = fidStatsHashTablep[i]; statp; statp = statp->nextp) {
285             statp->flags &= (CM_FIDSTATS_FLAG_RO | CM_FIDSTATS_FLAG_PURERO);
286             statp->buffers = 0;
287             statp->fileLength.QuadPart = 0;
288         }
289     }
290
291     lock_ObtainRead(&cm_scacheLock);
292     for (i=0; i<cm_data.scacheHashTableSize; i++) {
293         for (scp=cm_data.scacheHashTablep[i]; scp; scp=scp->nextp) {
294             if (scp->fid.cell == 0)
295                 continue;
296             hash = scp->fid.hash % fidStatsHashTableSize;
297
298             for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
299                 if (!cm_FidCmp(&fid, &statp->fid)) {
300                     statp->fileType = scp->fileType;
301                     if (cm_HaveCallback(scp))
302                         statp->flags |= CM_FIDSTATS_FLAG_CALLBACK;
303                     statp->flags |= CM_FIDSTATS_FLAG_HAVE_SCACHE;
304                     break;
305                 }
306             }
307             if (!statp) {
308                 lock_ReleaseRead(&cm_scacheLock);
309                 cm_PerformanceAddSCache(scp);
310                 lock_ObtainRead(&cm_scacheLock);
311             }
312         }
313     }
314     lock_ReleaseRead(&cm_scacheLock);
315
316     lock_ObtainRead(&cm_volumeLock);
317     for(volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
318         if (volp->vol[RWVOL].ID) {
319             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[RWVOL].ID, 1, 1);
320             hash = fid.hash % fidStatsHashTableSize;
321
322             for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
323                 if (!cm_FidCmp(&fid, &statp->fid)) {
324                     statp->flags |= CM_FIDSTATS_FLAG_HAVE_VOLUME;
325                     break;
326                 }
327             }
328             if (!statp) {
329                 statp = cm_PerformanceGetNew();
330                 statp->fid = fid;
331                 statp->fileType = CM_SCACHETYPE_DIRECTORY;
332                 statp->flags = CM_FIDSTATS_FLAG_HAVE_VOLUME;
333                 cm_PerformanceInsertToHashTable(statp);
334             }
335         }
336         if (volp->vol[ROVOL].ID) {
337             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[ROVOL].ID, 1, 1);
338             hash = fid.hash % fidStatsHashTableSize;
339
340             for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
341                 if (!cm_FidCmp(&fid, &statp->fid)) {
342                     statp->flags |= CM_FIDSTATS_FLAG_HAVE_VOLUME;
343                     break;
344                 }
345             }
346             if (!statp) {
347                 statp = cm_PerformanceGetNew();
348                 statp->fid = fid;
349                 statp->fileType = CM_SCACHETYPE_DIRECTORY;
350                 statp->flags = CM_FIDSTATS_FLAG_HAVE_VOLUME | CM_FIDSTATS_FLAG_RO | CM_FIDSTATS_FLAG_PURERO;
351                 cm_PerformanceInsertToHashTable(statp);
352             }
353         }
354         if (volp->vol[BACKVOL].ID) {
355             cm_SetFid(&fid, volp->cellp->cellID, volp->vol[BACKVOL].ID, 1, 1);
356             hash = fid.hash % fidStatsHashTableSize;
357
358             for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
359                 if (!cm_FidCmp(&fid, &statp->fid)) {
360                     statp->flags |= CM_FIDSTATS_FLAG_HAVE_VOLUME;
361                     break;
362                 }
363             }
364             if (!statp) {
365                 statp = cm_PerformanceGetNew();
366                 statp->fid = fid;
367                 statp->fileType = CM_SCACHETYPE_DIRECTORY;
368                 statp->flags = CM_FIDSTATS_FLAG_HAVE_VOLUME | CM_FIDSTATS_FLAG_RO;
369                 cm_PerformanceInsertToHashTable(statp);
370             }
371         }
372     }
373     lock_ReleaseRead(&cm_volumeLock);
374
375     lock_ObtainRead(&buf_globalLock);
376     for (bp = cm_data.buf_allp; bp; bp=bp->allp) {
377         int valid = 0;
378
379         if (bp->fid.cell == 0)
380             continue;
381
382         lock_ReleaseRead(&buf_globalLock);
383         scp = cm_FindSCache(&bp->fid);
384         if (scp) {
385             lock_ObtainMutex(&bp->mx);
386             lock_ObtainRead(&scp->rw);
387             valid = cm_HaveBuffer(scp, bp, TRUE);
388             lock_ReleaseRead(&scp->rw);
389             lock_ReleaseMutex(&bp->mx);
390             cm_ReleaseSCache(scp);
391
392             if (valid) {
393                 hash = bp->fid.hash % fidStatsHashTableSize;
394                 for (statp = fidStatsHashTablep[hash]; statp; statp = statp->nextp) {
395                     if (!cm_FidCmp(&bp->fid, &statp->fid)) {
396                         statp->buffers++;
397                         break;
398                     }
399                 }
400             }
401         }
402         lock_ObtainRead(&buf_globalLock);
403     }
404     lock_ReleaseRead(&buf_globalLock);
405
406     cm_PerformancePrintReport();
407 }
408
409 void cm_PerformancePrintReport(void)
410 {
411     afs_uint32 i;
412     cm_fid_stats_t *statp;
413
414     afs_uint32 rw_vols = 0, ro_vols = 0, bk_vols = 0;
415     afs_uint32 fid_cnt = 0, fid_w_vol = 0, fid_w_scache = 0, fid_w_buffers = 0, fid_w_callbacks = 0;
416     afs_uint32 fid_w_scache_no_vol = 0, fid_w_scache_no_buf = 0, fid_w_vol_no_scache = 0, fid_w_buf_no_scache = 0;
417     afs_uint32 fid_file = 0, fid_dir = 0, fid_mp = 0, fid_sym = 0, fid_other = 0;
418     afs_uint32 fid_0k = 0, fid_1k = 0, fid_4k = 0, fid_64k = 0, fid_1m = 0, fid_20m = 0, fid_100m = 0, fid_1g = 0, fid_2g = 0, fid_large = 0;
419
420     HANDLE hLogFile;
421     char logfileName[MAX_PATH+1];
422     DWORD dwSize;
423
424     if (fidStatsHashTablep == NULL)
425         return;
426
427     /* Clean all cm_fid_stat_t objects first */
428     for (i = 0; i < fidStatsHashTableSize; i++) {
429         for (statp = fidStatsHashTablep[i]; statp; statp = statp->nextp) {
430             /* summarize the data */
431             fid_cnt++;
432
433             if ((statp->flags & (CM_FIDSTATS_FLAG_RO | CM_FIDSTATS_FLAG_PURERO)) == (CM_FIDSTATS_FLAG_RO | CM_FIDSTATS_FLAG_PURERO))
434                 ro_vols++;
435             else if (statp->flags & CM_FIDSTATS_FLAG_RO)
436                 bk_vols++;
437             else
438                 rw_vols++;
439
440             if (statp->flags & CM_FIDSTATS_FLAG_HAVE_VOLUME)
441                 fid_w_vol++;
442
443             if (statp->flags & CM_FIDSTATS_FLAG_HAVE_SCACHE)
444                 fid_w_scache++;
445
446             if (statp->flags & CM_FIDSTATS_FLAG_CALLBACK)
447                 fid_w_callbacks++;
448
449             if (statp->buffers > 0)
450                 fid_w_buffers++;
451
452             if ((statp->flags & CM_FIDSTATS_FLAG_HAVE_SCACHE) &&
453                 !(statp->flags & CM_FIDSTATS_FLAG_HAVE_VOLUME))
454                 fid_w_scache_no_vol++;
455
456             if ((statp->flags & CM_FIDSTATS_FLAG_HAVE_SCACHE) &&
457                 statp->buffers == 0)
458                 fid_w_scache_no_buf++;
459
460             if ((statp->flags & CM_FIDSTATS_FLAG_HAVE_VOLUME) &&
461                 !(statp->flags & CM_FIDSTATS_FLAG_HAVE_SCACHE))
462                 fid_w_vol_no_scache++;
463
464             if (!(statp->flags & CM_FIDSTATS_FLAG_HAVE_SCACHE) &&
465                 statp->buffers > 0)
466                 fid_w_buf_no_scache++;
467
468             switch (statp->fileType) {
469             case CM_SCACHETYPE_FILE       :
470                 fid_file++;
471                 break;
472             case CM_SCACHETYPE_DIRECTORY  :
473                 fid_dir++;
474                 break;
475             case CM_SCACHETYPE_SYMLINK    :
476                 fid_sym++;
477                 break;
478             case CM_SCACHETYPE_MOUNTPOINT :
479                 fid_mp++;
480                 break;
481             case CM_SCACHETYPE_DFSLINK    :
482             case CM_SCACHETYPE_INVALID    :
483             default:
484                 fid_other++;
485             }
486
487             if (statp->fileType == CM_SCACHETYPE_FILE) {
488                 if (statp->fileLength.HighPart == 0) {
489                     if (statp->fileLength.LowPart == 0)
490                         fid_0k++;
491                     else if (statp->fileLength.LowPart <= 1024)
492                         fid_1k++;
493                     else if (statp->fileLength.LowPart <= 4096)
494                         fid_4k++;
495                     else if (statp->fileLength.LowPart <= 65536)
496                         fid_64k++;
497                     else if (statp->fileLength.LowPart <= 1024*1024)
498                         fid_1m++;
499                     else if (statp->fileLength.LowPart <= 20*1024*1024)
500                         fid_20m++;
501                     else if (statp->fileLength.LowPart <= 100*1024*1024)
502                         fid_100m++;
503                     else if (statp->fileLength.LowPart <= 1024*1024*1024)
504                         fid_1g++;
505                     else
506                         fid_2g++;
507                 } else {
508                     fid_large++;
509                 }
510             }
511         }
512     }
513
514     dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
515     if ( dwSize == 0 || dwSize > sizeof(logfileName) )
516     {
517         GetWindowsDirectory(logfileName, sizeof(logfileName));
518     }
519     strncat(logfileName, "\\afsd_performance.log", sizeof(logfileName));
520
521     hLogFile = CreateFile(logfileName, FILE_APPEND_DATA, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
522                           FILE_ATTRIBUTE_NORMAL, NULL);
523
524     if (hLogFile) {
525         char output[1024];
526         char t[100];
527         int zilch;
528
529         GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, t, sizeof(t));
530
531         StringCbPrintfA(output, sizeof(output),
532                         "TIME - %s\r\n"
533                         "INUSE- stats=(%u of %u) vols=(%u of %u) bufs=(%I64u of %I64u)\r\n"
534                         "FIDs - total=%u haveVol=%u haveStat=%u haveCB=%u haveBuf=%u haveStatNoVol=%u haveVolNoStat=%u haveStatNoBuf=%u haveBufNoStat=%u\r\n"
535                         "VOLs - rw=%u ro=%u bk=%u\r\n"
536                         "TYPEs- file=%u dir=%u mp=%u sym=%u unk=%u\r\n"
537                         "SIZEs- 0kb=%u 1kb=%u 4kb=%u 64kb=%u 1mb=%u 20m=%u 100mb=%u 1gb=%u 2gb=%u larger=%u\r\n\r\n",
538                          t,
539                          cm_data.currentSCaches, cm_data.maxSCaches, cm_data.currentVolumes, cm_data.maxVolumes,
540                          cm_data.buf_nbuffers - cm_data.buf_freeCount, cm_data.buf_nbuffers,
541                          fid_cnt, fid_w_vol, fid_w_scache, fid_w_callbacks, fid_w_buffers,
542                          fid_w_scache_no_vol, fid_w_vol_no_scache, fid_w_scache_no_buf, fid_w_buf_no_scache,
543                          rw_vols, ro_vols, bk_vols,
544                          fid_file, fid_dir, fid_mp, fid_sym, fid_other,
545                          fid_0k, fid_1k, fid_4k, fid_64k, fid_1m, fid_20m, fid_100m, fid_1g, fid_2g, fid_large
546                          );
547         WriteFile(hLogFile, output, (DWORD)strlen(output), &zilch, NULL);
548
549         CloseHandle(hLogFile);
550     }
551
552
553 }