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