1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1992-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * *
20 ***********************************************************************/
21 #pragma prototyped
22
23 #define FORMAT "region=%(region)p method=%(method)s flags=%(flags)s size=%(size)d segments=%(segments)d busy=(%(busy_size)d,%(busy_blocks)d,%(busy_max)d) free=(%(free_size)d,%(free_blocks)d,%(free_max)d)"
24
25 static const char usage[] =
26 "[-?\n@(#)$Id: vmstate (AT&T Research) 2010-04-08 $\n]"
27 USAGE_LICENSE
28 "[+NAME?vmstate - list the calling process vmalloc region state]"
29 "[+DESCRIPTION?When invoked as a shell builtin, \bvmstate\b lists the "
30 "calling process \bvmalloc\b(3) state for all regions.]"
31 "[f:format?List the ids specified by \aformat\a. \aformat\a follows "
32 "\bprintf\b(3) conventions, except that \bsfio\b(3) inline ids are used "
33 "instead of arguments: "
34 "%[-+]][\awidth\a[.\aprecis\a[.\abase\a]]]]]](\aid\a)\achar\a. The "
35 "supported \aid\as are:]:[format:=" FORMAT "]"
36 "{"
37 "[+method?The vmalloc method name.]"
38 "[+flags?The vmalloc method flags.]"
39 "[+size?The total region size.]"
40 "[+segments?The number of segments in the region.]"
41 "[+busy_size?The total busy block size.]"
42 "[+busy_blocks?The number of busy blocks.]"
43 "[+busy_max?The maximum busy block size.]"
44 "[+free_size?The total free block size.]"
45 "[+free_blocks?The number of free blocks.]"
46 "[+free_max?The maximum free block size.]"
47 "}"
48 "[+SEE ALSO?\bvmalloc\b(3)]"
49 ;
50
51 #include <cmd.h>
52 #include <vmalloc.h>
53 #include <sfdisc.h>
54
55 typedef struct State_s
56 {
57 char* format;
58 Vmalloc_t* vm;
59 Vmstat_t vs;
60 unsigned int regions;
61 Vmalloc_t* region[256];
62 } State_t;
63
64 /*
65 * sfkeyprintf() lookup
66 * handle==0 for heading
67 */
68
69 static int
key(void * handle,Sffmt_t * fp,const char * arg,char ** ps,Sflong_t * pn)70 key(void* handle, Sffmt_t* fp, const char* arg, char** ps, Sflong_t* pn)
71 {
72 register State_t* state = (State_t*)handle;
73 register char* s;
74
75 if (!(s = fp->t_str) || streq(s, "size"))
76 *pn = state->vs.extent;
77 else if (streq(s, "region"))
78 *pn = integralof(state->vm);
79 else if (streq(s, "segments"))
80 *pn = state->vs.n_seg;
81 else if (streq(s, "busy_size"))
82 *pn = state->vs.s_busy;
83 else if (streq(s, "busy_blocks"))
84 *pn = state->vs.n_busy;
85 else if (streq(s, "busy_max"))
86 *pn = state->vs.m_busy;
87 else if (streq(s, "flags"))
88 {
89 *ps = s = fmtbuf(32);
90 #ifdef VM_TRUST
91 if (state->vs.mode & VM_TRUST)
92 s = strcopy(s, "TRUST|");
93 #endif
94 if (state->vs.mode & VM_TRACE)
95 s = strcopy(s, "TRACE|");
96 if (state->vs.mode & VM_DBCHECK)
97 s = strcopy(s, "DBCHECK|");
98 if (state->vs.mode & VM_DBABORT)
99 s = strcopy(s, "DBABORT|");
100 if (s > *ps)
101 *(s - 1) = 0;
102 else
103 strcpy(s, "0");
104 }
105 else if (streq(s, "free_size"))
106 *pn = state->vs.s_free;
107 else if (streq(s, "free_blocks"))
108 *pn = state->vs.n_free;
109 else if (streq(s, "free_max"))
110 *pn = state->vs.m_free;
111 else if (streq(s, "format"))
112 *ps = (char*)state->format;
113 else if (streq(s, "method"))
114 {
115 if (state->vs.mode & VM_MTBEST)
116 *ps = "best";
117 else if (state->vs.mode & VM_MTPOOL)
118 *ps = "pool";
119 else if (state->vs.mode & VM_MTLAST)
120 *ps = "last";
121 else if (state->vs.mode & VM_MTDEBUG)
122 *ps = "debug";
123 else if (state->vs.mode & VM_MTPROFILE)
124 *ps = "profile";
125 else
126 *ps = "UNKNOWN";
127 }
128 else
129 {
130 error(2, "%s: unknown format identifier", s);
131 return 0;
132 }
133 return 1;
134 }
135
136 static int
visit(Vmalloc_t * vm,void * addr,size_t size,Vmdisc_t * disc,void * handle)137 visit(Vmalloc_t* vm, void* addr, size_t size, Vmdisc_t* disc, void* handle)
138 {
139 State_t* state = (State_t*)handle;
140
141 if (vm != state->vm)
142 {
143 state->vm = vm;
144 if (state->regions < elementsof(state->region))
145 state->region[state->regions++] = vm;
146 }
147 return 0;
148 }
149
150 int
b_vmstate(int argc,char ** argv,Shbltin_t * context)151 b_vmstate(int argc, char** argv, Shbltin_t* context)
152 {
153 register int i;
154 State_t state;
155
156 memset(&state, 0, sizeof(state));
157 cmdinit(argc, argv, context, ERROR_CATALOG, 0);
158 for (;;)
159 {
160 switch (optget(argv, usage))
161 {
162 case 'f':
163 state.format = opt_info.arg;
164 continue;
165 case '?':
166 error(ERROR_USAGE|4, "%s", opt_info.arg);
167 break;
168 case ':':
169 error(2, "%s", opt_info.arg);
170 break;
171 }
172 break;
173 }
174 argv += opt_info.index;
175 if (error_info.errors || *argv)
176 error(ERROR_USAGE|4, "%s", optusage(NiL));
177 if (!state.format)
178 state.format = FORMAT;
179
180 /*
181 * the walk must do no allocations because it locks the regions
182 */
183
184 vmwalk(NiL, visit, &state);
185
186 /*
187 * now we can compute and list the state of each region
188 */
189
190 for (i = 0; i < state.regions; i++)
191 {
192 state.vm = state.region[i];
193 vmstat(state.vm, &state.vs);
194 sfkeyprintf(sfstdout, &state, state.format, key, NiL);
195 sfprintf(sfstdout, "\n");
196 }
197 return 0;
198 }
199