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 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 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 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