libumem.c revision 9c720e3bfb657054035cb780c4d222291b7d4917
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#include "umem.h"
#include <libproc.h>
#include <mdb/mdb_modapi.h>
#include "kgrep.h"
#include "leaky.h"
#include "misc.h"
#include "proc_kludges.h"
#include <umem_impl.h>
#include <sys/vmem_impl_user.h>
#include <thr_uberdata.h>
#include "umem_pagesize.h"
typedef struct datafmt {
char *hdr1;
char *hdr2;
char *dashes;
char *fmt;
} datafmt_t;
{ " ", "tid", "---", "%3u " },
{ " memory", " cached", "-------", "%7lH " },
{ " %", "cap", "---", "%3u " },
};
{ "cache ", "name ",
"-------------------------", "%-25s " },
{ " buf", " size", "------", "%6u " },
{ " buf", " in use", "-------", "%7u " },
{ " buf", " in ptc", "-------", "%7s " },
{ " buf", " total", "-------", "%7u " },
{ " memory", " in use", "-------", "%7H " },
{ " alloc", " succeed", "---------", "%9u " },
{ "alloc", " fail", "-----", "%5llu" },
};
{ "vmem ", "name ",
"-------------------------", "%-*s " },
{ " memory", " in use", "---------", "%9H " },
{ " memory", " total", "----------", "%10H " },
{ " memory", " import", "---------", "%9H " },
{ " alloc", " succeed", "---------", "%9llu " },
{ "alloc", " fail", "-----", "%5llu " },
};
/*ARGSUSED*/
static int
{
if (ccp->cc_prounds > 0)
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
}
typedef struct umastat_vmem {
struct umastat_vmem *kv_next;
int kv_meminuse;
int kv_alloc;
int kv_fail;
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
(*nptc)++;
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
(*nbufs)++;
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
char walk[60];
int nbufs = 0;
return (WALK_NEXT);
cp->cache_bufsize);
return (WALK_ERR);
}
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
mdb_warn("unable to read 'umem_ptc_size'");
return (WALK_ERR);
}
if (mdb_walk("umem_cache",
mdb_warn("can't walk 'umem_cache'");
return (WALK_ERR);
}
mdb_printf("\n");
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
(*nptc)++;
return (WALK_NEXT);
}
static int
{
char buf[10];
int magsize;
char walk[60];
return (WALK_ERR);
}
}
goto out;
}
out:
mdb_printf("\n");
return (WALK_NEXT);
}
static int
{
return (WALK_NEXT);
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
int ident = 0;
ident = 0;
break;
}
}
mdb_printf("\n");
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
int nptc = 0, i;
if (argc != 0)
return (DCMD_USAGE);
/*
* We need to determine if we have any caches that have per-thread
* caching enabled.
*/
if (mdb_walk("umem_cache",
mdb_warn("can't walk 'umem_cache'");
return (DCMD_ERR);
}
if (nptc) {
for (i = 0; i < nptc; i++)
mdb_printf("\n");
if (mdb_walk("umem_cache",
mdb_warn("can't walk 'umem_cache'");
return (DCMD_ERR);
}
mdb_printf("\n");
for (i = 0; i < nptc; i++)
mdb_printf("\n");
mdb_warn("can't walk 'ulwp'");
return (DCMD_ERR);
}
mdb_printf("\n");
}
mdb_printf("\n");
mdb_printf("\n");
mdb_printf("\n");
mdb_warn("can't walk 'umem_cache'");
return (DCMD_ERR);
}
mdb_printf("\n");
mdb_warn("can't walk 'vmem'");
return (DCMD_ERR);
}
mdb_printf("\n");
mdb_printf("\n");
mdb_printf("\n");
mdb_printf("\n");
mdb_printf("\n");
mdb_warn("can't walk 'vmem'");
return (DCMD_ERR);
}
mdb_printf("\n");
return (DCMD_OK);
}
/*
* kmdb doesn't use libproc, and thus doesn't have any prmap_t's to walk.
* We have other ways to grep kmdb's address range.
*/
#ifndef _KMDB
typedef struct ugrep_walk_data {
void *ug_cbdata;
/*ARGSUSED*/
int
{
}
int
{
return (DCMD_ERR);
}
return (DCMD_OK);
}
kgrep_subr_pagesize(void)
{
return (PAGESIZE);
}
#endif /* !_KMDB */
static const mdb_dcmd_t dcmds[] = {
/* from libumem.c */
/* from misc.c */
/* from umem.c */
umem_status },
{ "allocdby", ":", "given a thread, print its allocated buffers",
allocdby },
{ "bufctl", ":[-vh] [-a addr] [-c caller] [-e earliest] [-l latest] "
{ "umalog", "[ fail | slab ]",
"display umem transaction log and stack traces", umalog },
{ "umausers", "[-ef] [cache ...]", "display current medium and large "
"users of the umem allocator", umausers },
{ "umem_malloc_dist", "[-dg] [-b maxbins] [-B minbinsize]",
"report distribution of outstanding malloc()s",
{ "umem_malloc_info", "?[-dg] [-b maxbins] [-B minbinsize]",
"report information about malloc()s by cache",
{ "umem_verify", "?", "check integrity of umem-managed memory",
umem_verify },
{ "vmem_seg", ":[-sv] [-c caller] [-e earliest] [-l latest] "
"[-m minsize] [-M maxsize] [-t thread] [-T type]",
#ifndef _KMDB
kgrep, kgrep_help },
/* from ../genunix/leaky.c + leaky_subr.c */
#endif
{ NULL }
};
static const mdb_walker_t walkers[] = {
/* from umem.c */
{ "allocdby", "given a thread, walk its allocated bufctls",
{ "bufctl", "walk a umem cache's bufctls",
{ "bufctl_history", "walk the available history of a bufctl",
{ "freectl", "walk a umem cache's free bufctls",
{ "freedby", "given a thread, walk its freed bufctls",
{ "freemem", "walk a umem cache's free memory",
{ "umem", "walk a umem cache",
{ "umem_cpu", "walk the umem CPU structures",
{ "umem_cpu_cache", "given a umem cache, walk its per-CPU caches",
{ "umem_hash", "given a umem cache, walk its allocated hash table",
{ "umem_log", "walk the umem transaction log",
{ "umem_slab", "given a umem cache, walk its slabs",
{ "umem_slab_partial",
"given a umem cache, walk its partially allocated slabs (min 1)",
{ "vmem", "walk vmem structures in pre-fix, depth-first order",
{ "vmem_alloc", "given a vmem_t, walk its allocated vmem_segs",
{ "vmem_free", "given a vmem_t, walk its free vmem_segs",
{ "vmem_postfix", "walk vmem structures in post-fix, depth-first order",
{ "vmem_seg", "given a vmem_t, walk all of its vmem_segs",
{ "vmem_span", "given a vmem_t, walk its spanning vmem_segs",
#ifndef _KMDB
/* from ../genunix/leaky.c + leaky_subr.c */
{ "leak", "given a leak ctl, walk other leaks w/ that stacktrace",
{ "leakbuf", "given a leak ctl, walk addr of leaks w/ that stacktrace",
#endif
{ NULL }
};
const mdb_modinfo_t *
_mdb_init(void)
{
if (umem_init() != 0)
return (NULL);
return (&modinfo);
}
void
_mdb_fini(void)
{
#ifndef _KMDB
leaky_cleanup(1);
#endif
}