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