/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1992-2010 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * David Korn * * * ***********************************************************************/ #pragma prototyped #define FORMAT "region=%(region)p 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)" static const char usage[] = "[-?\n@(#)$Id: vmstate (AT&T Research) 2010-03-05 $\n]" USAGE_LICENSE "[+NAME?vmstate - list the calling process vmalloc region state]" "[+DESCRIPTION?When invoked as a shell builtin, \bvmstate\b lists the " "calling process \bvmalloc\b(3) state for all regions.]" "[f:format?List the ids specified by \aformat\a. \aformat\a follows " "\bprintf\b(3) conventions, except that \bsfio\b(3) inline ids are used " "instead of arguments: " "%[-+]][\awidth\a[.\aprecis\a[.\abase\a]]]]]](\aid\a)\achar\a. The " "supported \aid\as are:]:[format:=" FORMAT "]" "{" "[+size?The total region size.]" "[+segments?The number of segments in the region.]" "[+busy_size?The total busy block size.]" "[+busy_blocks?The number of busy blocks.]" "[+busy_max?The maximum busy block size.]" "[+free_size?The total free block size.]" "[+free_blocks?The number of free blocks.]" "[+free_max?The maximum free block size.]" "}" "[+SEE ALSO?\bvmalloc\b(3)]" ; #include #include typedef struct State_s { char* format; Vmalloc_t* vm; Vmstat_t vs; unsigned int regions; Vmalloc_t* region[256]; } State_t; /* * sfkeyprintf() lookup * handle==0 for heading */ static int key(void* handle, Sffmt_t* fp, const char* arg, char** ps, Sflong_t* pn) { register State_t* state = (State_t*)handle; register char* s; if (!(s = fp->t_str) || streq(s, "size")) *pn = state->vs.extent; else if (streq(s, "region")) *pn = integralof(state->vm); else if (streq(s, "segments")) *pn = state->vs.n_seg; else if (streq(s, "busy_size")) *pn = state->vs.s_busy; else if (streq(s, "busy_blocks")) *pn = state->vs.n_busy; else if (streq(s, "busy_max")) *pn = state->vs.m_busy; else if (streq(s, "free_size")) *pn = state->vs.s_free; else if (streq(s, "free_blocks")) *pn = state->vs.n_free; else if (streq(s, "free_max")) *pn = state->vs.m_free; else if (streq(s, "format")) *ps = (char*)state->format; else { error(2, "%s: unknown format identifier", s); return 0; } return 1; } static int visit(Vmalloc_t* vm, void* addr, size_t size, Vmdisc_t* disc, void* handle) { State_t* state = (State_t*)handle; Vmstat_t vs; if (vm != state->vm) { state->vm = vm; if (state->regions < elementsof(state->region)) state->region[state->regions++] = vm; } return 0; } int b_vmstate(int argc, char** argv, void* context) { register int i; State_t state; memset(&state, 0, sizeof(state)); cmdinit(argc, argv, context, ERROR_CATALOG, 0); for (;;) { switch (optget(argv, usage)) { case 'f': state.format = opt_info.arg; continue; case '?': error(ERROR_USAGE|4, "%s", opt_info.arg); continue; case ':': error(2, "%s", opt_info.arg); continue; } break; } argv += opt_info.index; if (error_info.errors || *argv) error(ERROR_USAGE|4, "%s", optusage(NiL)); if (!state.format) state.format = FORMAT; /* * the walk must do no allocations because it locks the regions */ vmwalk(NiL, visit, &state); /* * now we can compute and list the state of each region */ for (i = 0; i < state.regions; i++) { state.vm = state.region[i]; vmstat(state.vm, &state.vs); sfkeyprintf(sfstdout, &state, state.format, key, NiL); sfprintf(sfstdout, "\n"); } return 0; }