Update from db-2.3.12.
[kopensolaris-gnu/glibc.git] / db2 / mp / mp_pr.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997
5  *      Sleepycat Software.  All rights reserved.
6  */
7 #include "config.h"
8
9 #ifndef lint
10 static const char sccsid[] = "@(#)mp_pr.c       10.18 (Sleepycat) 11/1/97";
11 #endif /* not lint */
12
13 #ifndef NO_SYSTEM_INCLUDES
14 #include <sys/types.h>
15
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #endif
22
23 #include "db_int.h"
24 #include "shqueue.h"
25 #include "db_shash.h"
26 #include "mp.h"
27
28 void __memp_debug __P((DB_MPOOL *, FILE *, int));
29
30 static void __memp_pbh __P((FILE *, DB_MPOOL *, BH *, int));
31 static void __memp_pdbmf __P((FILE *, DB_MPOOLFILE *, int));
32 static void __memp_pmf __P((FILE *, MPOOLFILE *, int));
33 static void __memp_pmp __P((FILE *, DB_MPOOL *, MPOOL *, int));
34
35 /*
36  * memp_stat --
37  *      Display MPOOL statistics.
38  */
39 int
40 memp_stat(dbmp, gspp, fspp, db_malloc)
41         DB_MPOOL *dbmp;
42         DB_MPOOL_STAT **gspp;
43         DB_MPOOL_FSTAT ***fspp;
44         void *(*db_malloc) __P((size_t));
45 {
46         DB_MPOOL_FSTAT **tfsp;
47         MPOOLFILE *mfp;
48         size_t len, nlen;
49         char *name;
50
51         /* Allocate space for the global statistics. */
52         if (gspp != NULL) {
53                 *gspp = NULL;
54
55                 if ((*gspp = db_malloc == NULL ?
56                     (DB_MPOOL_STAT *)__db_malloc(sizeof(**gspp)) :
57                     (DB_MPOOL_STAT *)db_malloc(sizeof(**gspp))) == NULL)
58                         return (ENOMEM);
59
60                 LOCKREGION(dbmp);
61
62                 /* Copy out the global statistics. */
63                 **gspp = dbmp->mp->stat;
64                 (*gspp)->st_hash_buckets = dbmp->mp->htab_buckets;
65                 (*gspp)->st_region_wait =
66                     dbmp->mp->rlayout.lock.mutex_set_wait;
67                 (*gspp)->st_region_nowait =
68                     dbmp->mp->rlayout.lock.mutex_set_nowait;
69
70                 UNLOCKREGION(dbmp);
71         }
72
73         if (fspp != NULL) {
74                 *fspp = NULL;
75
76                 LOCKREGION(dbmp);
77
78                 /* Count the MPOOLFILE structures. */
79                 for (len = 0,
80                     mfp = SH_TAILQ_FIRST(&dbmp->mp->mpfq, __mpoolfile);
81                     mfp != NULL;
82                     ++len, mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile));
83
84                 UNLOCKREGION(dbmp);
85
86                 if (len == 0)
87                         return (0);
88
89                 /* Allocate space for the pointers. */
90                 len = (len + 1) * sizeof(DB_MPOOL_FSTAT *);
91                 if ((*fspp = db_malloc == NULL ?
92                     (DB_MPOOL_FSTAT **)__db_malloc(len) :
93                     (DB_MPOOL_FSTAT **)db_malloc(len)) == NULL)
94                         return (ENOMEM);
95
96                 LOCKREGION(dbmp);
97
98                 /* Build each individual entry. */
99                 for (tfsp = *fspp,
100                     mfp = SH_TAILQ_FIRST(&dbmp->mp->mpfq, __mpoolfile);
101                     mfp != NULL;
102                     ++tfsp, mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
103                         name = R_ADDR(dbmp, mfp->path_off);
104                         nlen = strlen(name);
105                         len = sizeof(DB_MPOOL_FSTAT) + nlen + 1;
106                         if ((*tfsp = db_malloc == NULL ?
107                             (DB_MPOOL_FSTAT *)__db_malloc(len) :
108                             (DB_MPOOL_FSTAT *)db_malloc(len)) == NULL)
109                                 return (ENOMEM);
110                         **tfsp = mfp->stat;
111                         (*tfsp)->file_name = (char *)
112                             (u_int8_t *)*tfsp + sizeof(DB_MPOOL_FSTAT);
113                         memcpy((*tfsp)->file_name, name, nlen + 1);
114                 }
115                 *tfsp = NULL;
116
117                 UNLOCKREGION(dbmp);
118         }
119         return (0);
120 }
121
122 /*
123  * __memp_debug --
124  *      Display MPOOL structures.
125  *
126  * PUBLIC: void __memp_debug __P((DB_MPOOL *, FILE *, int));
127  */
128 void
129 __memp_debug(dbmp, fp, data)
130         DB_MPOOL *dbmp;
131         FILE *fp;
132         int data;
133 {
134         DB_MPOOLFILE *dbmfp;
135         u_long cnt;
136
137         /* Make it easy to call from the debugger. */
138         if (fp == NULL)
139                 fp = stderr;
140
141         /* Welcome message. */
142         (void)fprintf(fp, "%s\nMpool per-process (%lu) statistics\n",
143             DB_LINE, (u_long)getpid());
144
145         if (data)
146                 (void)fprintf(fp, "    fd: %d; addr %lx; maddr %lx\n",
147                     dbmp->fd, (u_long)dbmp->addr, (u_long)dbmp->maddr);
148
149         /* Display the DB_MPOOLFILE structures. */
150         for (cnt = 0, dbmfp = TAILQ_FIRST(&dbmp->dbmfq);
151             dbmfp != NULL; ++cnt, dbmfp = TAILQ_NEXT(dbmfp, q));
152         (void)fprintf(fp, "%lu process-local files\n", cnt);
153         for (dbmfp = TAILQ_FIRST(&dbmp->dbmfq);
154             dbmfp != NULL; dbmfp = TAILQ_NEXT(dbmfp, q)) {
155                 (void)fprintf(fp, "%s\n", dbmfp->path);
156                 __memp_pdbmf(fp, dbmfp, data);
157         }
158
159         /* Switch to global statistics. */
160         (void)fprintf(fp, "\n%s\nMpool statistics\n", DB_LINE);
161
162         /* Display the MPOOL structure. */
163         __memp_pmp(fp, dbmp, dbmp->mp, data);
164
165         /* Flush in case we're debugging. */
166         (void)fflush(fp);
167 }
168
169 /*
170  * __memp_pdbmf --
171  *      Display a DB_MPOOLFILE structure.
172  */
173 static void
174 __memp_pdbmf(fp, dbmfp, data)
175         FILE *fp;
176         DB_MPOOLFILE *dbmfp;
177         int data;
178 {
179         if (!data)
180                 return;
181
182         (void)fprintf(fp, "    fd: %d; %s\n",
183             dbmfp->fd, F_ISSET(dbmfp, MP_READONLY) ? "readonly" : "read/write");
184 }
185
186 /*
187  * __memp_pmp --
188  *      Display the MPOOL structure.
189  */
190 static void
191 __memp_pmp(fp, dbmp, mp, data)
192         FILE *fp;
193         DB_MPOOL *dbmp;
194         MPOOL *mp;
195         int data;
196 {
197         BH *bhp;
198         MPOOLFILE *mfp;
199         DB_HASHTAB *htabp;
200         size_t bucket;
201         int cnt;
202         const char *sep;
203
204         (void)fprintf(fp, "references: %lu; cachesize: %lu\n",
205             (u_long)mp->rlayout.refcnt, (u_long)mp->stat.st_cachesize);
206         (void)fprintf(fp,
207             "    %lu pages created\n", (u_long)mp->stat.st_page_create);
208         (void)fprintf(fp,
209             "    %lu mmap pages returned\n", (u_long)mp->stat.st_map);
210         (void)fprintf(fp, "    %lu I/O's (%lu read, %lu written)\n",
211             (u_long)mp->stat.st_page_in + mp->stat.st_page_out,
212             (u_long)mp->stat.st_page_in, (u_long)mp->stat.st_page_out);
213         if (mp->stat.st_cache_hit + mp->stat.st_cache_miss != 0)
214                 (void)fprintf(fp,
215                     "    %.0f%% cache hit rate (%lu hit, %lu miss)\n",
216                     ((double)mp->stat.st_cache_hit /
217             (mp->stat.st_cache_hit + mp->stat.st_cache_miss)) * 100,
218                     (u_long)mp->stat.st_cache_hit,
219                     (u_long)mp->stat.st_cache_miss);
220
221         /* Display the MPOOLFILE structures. */
222         for (cnt = 0, mfp = SH_TAILQ_FIRST(&dbmp->mp->mpfq, __mpoolfile);
223             mfp != NULL; ++cnt, mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile));
224         (void)fprintf(fp, "%d total files\n", cnt);
225         for (cnt = 1, mfp = SH_TAILQ_FIRST(&dbmp->mp->mpfq, __mpoolfile);
226             mfp != NULL; ++cnt, mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
227                 (void)fprintf(fp, "file %d\n", cnt);
228                 __memp_pmf(fp, mfp, data);
229         }
230
231         if (!data)
232                 return;
233
234         /* Display the hash table list of BH's. */
235         (void)fprintf(fp, "%s\nHASH table of BH's (%lu buckets):\n",
236             DB_LINE, (u_long)mp->htab_buckets);
237         (void)fprintf(fp,
238             "longest chain searched %lu\n", (u_long)mp->stat.st_hash_longest);
239         (void)fprintf(fp, "average chain searched %lu (total/calls: %lu/%lu)\n",
240             (u_long)mp->stat.st_hash_examined /
241             (mp->stat.st_hash_searches ? mp->stat.st_hash_searches : 1),
242             (u_long)mp->stat.st_hash_examined,
243             (u_long)mp->stat.st_hash_searches);
244         for (htabp = dbmp->htab,
245             bucket = 0; bucket < mp->htab_buckets; ++htabp, ++bucket) {
246                 if (SH_TAILQ_FIRST(&dbmp->htab[bucket], __bh) != NULL)
247                         (void)fprintf(fp, "%lu:\n", (u_long)bucket);
248                 for (bhp = SH_TAILQ_FIRST(&dbmp->htab[bucket], __bh);
249                     bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, hq, __bh))
250                         __memp_pbh(fp, dbmp, bhp, data);
251         }
252
253         /* Display the LRU list of BH's. */
254         (void)fprintf(fp, "LRU list of BH's (pgno/offset):");
255         for (sep = "\n    ", bhp = SH_TAILQ_FIRST(&dbmp->mp->bhq, __bh);
256             bhp != NULL; sep = ", ", bhp = SH_TAILQ_NEXT(bhp, q, __bh))
257                 (void)fprintf(fp, "%s%lu/%lu", sep,
258                     (u_long)bhp->pgno, (u_long)R_OFFSET(dbmp, bhp));
259         (void)fprintf(fp, "\n");
260 }
261
262 /*
263  * __memp_pmf --
264  *      Display an MPOOLFILE structure.
265  */
266 static void
267 __memp_pmf(fp, mfp, data)
268         FILE *fp;
269         MPOOLFILE *mfp;
270         int data;
271 {
272         (void)fprintf(fp, "    %lu pages created\n",
273             (u_long)mfp->stat.st_page_create);
274         (void)fprintf(fp, "    %lu I/O's (%lu read, %lu written)\n",
275             (u_long)mfp->stat.st_page_in + mfp->stat.st_page_out,
276             (u_long)mfp->stat.st_page_in, (u_long)mfp->stat.st_page_out);
277         if (mfp->stat.st_cache_hit + mfp->stat.st_cache_miss != 0)
278                 (void)fprintf(fp,
279                     "    %.0f%% cache hit rate (%lu hit, %lu miss)\n",
280                     ((double)mfp->stat.st_cache_hit /
281                     (mfp->stat.st_cache_hit + mfp->stat.st_cache_miss)) * 100,
282                     (u_long)mfp->stat.st_cache_hit,
283                     (u_long)mfp->stat.st_cache_miss);
284         if (!data)
285                 return;
286
287         (void)fprintf(fp, "    %d references; %s; pagesize: %lu\n", mfp->ref,
288             mfp->can_mmap ? "mmap" : "read/write",
289             (u_long)mfp->stat.st_pagesize);
290 }
291
292 /*
293  * __memp_pbh --
294  *      Display a BH structure.
295  */
296 static void
297 __memp_pbh(fp, dbmp, bhp, data)
298         FILE *fp;
299         DB_MPOOL *dbmp;
300         BH *bhp;
301         int data;
302 {
303         const char *sep;
304
305         if (!data)
306                 return;
307
308         (void)fprintf(fp, "    BH @ %lu (mf: %lu): page %lu; ref %lu",
309             (u_long)R_OFFSET(dbmp, bhp),
310             (u_long)bhp->mf_offset, (u_long)bhp->pgno, (u_long)bhp->ref);
311         sep = "; ";
312         if (F_ISSET(bhp, BH_DIRTY)) {
313                 (void)fprintf(fp, "%sdirty", sep);
314                 sep = ", ";
315         }
316         if (F_ISSET(bhp, BH_WRITE)) {
317                 (void)fprintf(fp, "%schk_write", sep);
318                 sep = ", ";
319         }
320         (void)fprintf(fp, "\n");
321 }