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