profile.c revision 233409
1179237Sjb/* 2179237Sjb * CDDL HEADER START 3179237Sjb * 4179237Sjb * The contents of this file are subject to the terms of the 5179237Sjb * Common Development and Distribution License (the "License"). 6179237Sjb * You may not use this file except in compliance with the License. 7179237Sjb * 8179237Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9179237Sjb * or http://www.opensolaris.org/os/licensing. 10179237Sjb * See the License for the specific language governing permissions 11179237Sjb * and limitations under the License. 12179237Sjb * 13179237Sjb * When distributing Covered Code, include this CDDL HEADER in each 14179237Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15179237Sjb * If applicable, add the following below this CDDL HEADER, with the 16179237Sjb * fields enclosed by brackets "[]" replaced with your own identifying 17179237Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 18179237Sjb * 19179237Sjb * CDDL HEADER END 20179237Sjb * 21179237Sjb * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 22179237Sjb * 23179237Sjb * $FreeBSD: head/sys/cddl/dev/profile/profile.c 233409 2012-03-24 05:14:37Z gonzo $ 24179237Sjb * 25179237Sjb */ 26179237Sjb 27179237Sjb/* 28179237Sjb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 29179237Sjb * Use is subject to license terms. 30179237Sjb */ 31179237Sjb 32179237Sjb#include <sys/cdefs.h> 33179237Sjb#include <sys/param.h> 34179237Sjb#include <sys/systm.h> 35179237Sjb#include <sys/conf.h> 36179237Sjb#include <sys/cpuvar.h> 37179237Sjb#include <sys/fcntl.h> 38179237Sjb#include <sys/filio.h> 39179237Sjb#include <sys/kdb.h> 40179237Sjb#include <sys/kernel.h> 41179237Sjb#include <sys/kmem.h> 42179237Sjb#include <sys/kthread.h> 43179237Sjb#include <sys/limits.h> 44179237Sjb#include <sys/linker.h> 45179237Sjb#include <sys/lock.h> 46179237Sjb#include <sys/malloc.h> 47179237Sjb#include <sys/module.h> 48179237Sjb#include <sys/mutex.h> 49179237Sjb#include <sys/poll.h> 50179237Sjb#include <sys/proc.h> 51179237Sjb#include <sys/selinfo.h> 52179237Sjb#include <sys/smp.h> 53179237Sjb#include <sys/uio.h> 54179237Sjb#include <sys/unistd.h> 55179237Sjb#include <machine/stdarg.h> 56179237Sjb 57179237Sjb#include <sys/cyclic.h> 58179237Sjb#include <sys/dtrace.h> 59179237Sjb#include <sys/dtrace_bsd.h> 60179237Sjb 61179237Sjb#define PROF_NAMELEN 15 62179237Sjb 63179237Sjb#define PROF_PROFILE 0 64179237Sjb#define PROF_TICK 1 65179237Sjb#define PROF_PREFIX_PROFILE "profile-" 66179237Sjb#define PROF_PREFIX_TICK "tick-" 67179237Sjb 68179237Sjb/* 69179237Sjb * Regardless of platform, there are five artificial frames in the case of the 70179237Sjb * profile provider: 71179237Sjb * 72179237Sjb * profile_fire 73179237Sjb * cyclic_expire 74179237Sjb * cyclic_fire 75179237Sjb * [ cbe ] 76179237Sjb * [ locore ] 77179237Sjb * 78179237Sjb * On amd64, there are two frames associated with locore: one in locore, and 79179237Sjb * another in common interrupt dispatch code. (i386 has not been modified to 80179237Sjb * use this common layer.) Further, on i386, the interrupted instruction 81179237Sjb * appears as its own stack frame. All of this means that we need to add one 82179237Sjb * frame for amd64, and then take one away for both amd64 and i386. 83179237Sjb * 84179237Sjb * On SPARC, the picture is further complicated because the compiler 85179237Sjb * optimizes away tail-calls -- so the following frames are optimized away: 86179237Sjb * 87179237Sjb * profile_fire 88179237Sjb * cyclic_expire 89179237Sjb * 90179237Sjb * This gives three frames. However, on DEBUG kernels, the cyclic_expire 91179237Sjb * frame cannot be tail-call eliminated, yielding four frames in this case. 92179237Sjb * 93179237Sjb * All of the above constraints lead to the mess below. Yes, the profile 94179237Sjb * provider should ideally figure this out on-the-fly by hiting one of its own 95179237Sjb * probes and then walking its own stack trace. This is complicated, however, 96179237Sjb * and the static definition doesn't seem to be overly brittle. Still, we 97179237Sjb * allow for a manual override in case we get it completely wrong. 98179237Sjb */ 99179237Sjb#ifdef __amd64 100179237Sjb#define PROF_ARTIFICIAL_FRAMES 7 101179237Sjb#else 102179237Sjb#ifdef __i386 103179237Sjb#define PROF_ARTIFICIAL_FRAMES 6 104179237Sjb#else 105179237Sjb#ifdef __sparc 106179237Sjb#ifdef DEBUG 107179237Sjb#define PROF_ARTIFICIAL_FRAMES 4 108179237Sjb#else 109179237Sjb#define PROF_ARTIFICIAL_FRAMES 3 110179237Sjb#endif 111179237Sjb#endif 112179237Sjb#endif 113179237Sjb#endif 114179237Sjb 115233409Sgonzo#ifdef __mips 116233409Sgonzo/* 117233409Sgonzo * This value is bogus just to make module compilable on mips 118233409Sgonzo */ 119233409Sgonzo#define PROF_ARTIFICIAL_FRAMES 3 120233409Sgonzo#endif 121233409Sgonzo 122179237Sjbtypedef struct profile_probe { 123179237Sjb char prof_name[PROF_NAMELEN]; 124179237Sjb dtrace_id_t prof_id; 125179237Sjb int prof_kind; 126179237Sjb hrtime_t prof_interval; 127179237Sjb cyclic_id_t prof_cyclic; 128179237Sjb} profile_probe_t; 129179237Sjb 130179237Sjbtypedef struct profile_probe_percpu { 131179237Sjb hrtime_t profc_expected; 132179237Sjb hrtime_t profc_interval; 133179237Sjb profile_probe_t *profc_probe; 134179237Sjb} profile_probe_percpu_t; 135179237Sjb 136179237Sjbstatic d_open_t profile_open; 137179237Sjbstatic int profile_unload(void); 138179237Sjbstatic void profile_create(hrtime_t, char *, int); 139179237Sjbstatic void profile_destroy(void *, dtrace_id_t, void *); 140179237Sjbstatic void profile_enable(void *, dtrace_id_t, void *); 141179237Sjbstatic void profile_disable(void *, dtrace_id_t, void *); 142179237Sjbstatic void profile_load(void *); 143179237Sjbstatic void profile_provide(void *, dtrace_probedesc_t *); 144179237Sjb 145179237Sjbstatic int profile_rates[] = { 146179237Sjb 97, 199, 499, 997, 1999, 147179237Sjb 4001, 4999, 0, 0, 0, 148179237Sjb 0, 0, 0, 0, 0, 149179237Sjb 0, 0, 0, 0, 0 150179237Sjb}; 151179237Sjb 152179237Sjbstatic int profile_ticks[] = { 153179237Sjb 1, 10, 100, 500, 1000, 154179237Sjb 5000, 0, 0, 0, 0, 155179237Sjb 0, 0, 0, 0, 0 156179237Sjb}; 157179237Sjb 158179237Sjb/* 159179237Sjb * profile_max defines the upper bound on the number of profile probes that 160179237Sjb * can exist (this is to prevent malicious or clumsy users from exhausing 161179237Sjb * system resources by creating a slew of profile probes). At mod load time, 162179237Sjb * this gets its value from PROFILE_MAX_DEFAULT or profile-max-probes if it's 163179237Sjb * present in the profile.conf file. 164179237Sjb */ 165179237Sjb#define PROFILE_MAX_DEFAULT 1000 /* default max. number of probes */ 166179237Sjbstatic uint32_t profile_max = PROFILE_MAX_DEFAULT; 167179237Sjb /* maximum number of profile probes */ 168179237Sjbstatic uint32_t profile_total; /* current number of profile probes */ 169179237Sjb 170179237Sjbstatic struct cdevsw profile_cdevsw = { 171179237Sjb .d_version = D_VERSION, 172179237Sjb .d_open = profile_open, 173179237Sjb .d_name = "profile", 174179237Sjb}; 175179237Sjb 176179237Sjbstatic dtrace_pattr_t profile_attr = { 177179237Sjb{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 178179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 179179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 180179237Sjb{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 181179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 182179237Sjb}; 183179237Sjb 184179237Sjbstatic dtrace_pops_t profile_pops = { 185179237Sjb profile_provide, 186179237Sjb NULL, 187179237Sjb profile_enable, 188179237Sjb profile_disable, 189179237Sjb NULL, 190179237Sjb NULL, 191179237Sjb NULL, 192179237Sjb NULL, 193179237Sjb NULL, 194179237Sjb profile_destroy 195179237Sjb}; 196179237Sjb 197179237Sjbstatic struct cdev *profile_cdev; 198179237Sjbstatic dtrace_provider_id_t profile_id; 199179237Sjbstatic hrtime_t profile_interval_min = NANOSEC / 5000; /* 5000 hz */ 200179237Sjbstatic int profile_aframes = 0; /* override */ 201179237Sjb 202179237Sjbstatic void 203179237Sjbprofile_fire(void *arg) 204179237Sjb{ 205179237Sjb profile_probe_percpu_t *pcpu = arg; 206179237Sjb profile_probe_t *prof = pcpu->profc_probe; 207179237Sjb hrtime_t late; 208179237Sjb solaris_cpu_t *c = &solaris_cpu[curcpu]; 209179237Sjb 210179237Sjb late = gethrtime() - pcpu->profc_expected; 211179237Sjb pcpu->profc_expected += pcpu->profc_interval; 212179237Sjb 213179237Sjb dtrace_probe(prof->prof_id, c->cpu_profile_pc, 214179237Sjb c->cpu_profile_upc, late, 0, 0); 215179237Sjb} 216179237Sjb 217179237Sjbstatic void 218179237Sjbprofile_tick(void *arg) 219179237Sjb{ 220179237Sjb profile_probe_t *prof = arg; 221179237Sjb solaris_cpu_t *c = &solaris_cpu[curcpu]; 222179237Sjb 223179237Sjb dtrace_probe(prof->prof_id, c->cpu_profile_pc, 224179237Sjb c->cpu_profile_upc, 0, 0, 0); 225179237Sjb} 226179237Sjb 227179237Sjbstatic void 228179237Sjbprofile_create(hrtime_t interval, char *name, int kind) 229179237Sjb{ 230179237Sjb profile_probe_t *prof; 231179237Sjb 232179237Sjb if (interval < profile_interval_min) 233179237Sjb return; 234179237Sjb 235179237Sjb if (dtrace_probe_lookup(profile_id, NULL, NULL, name) != 0) 236179237Sjb return; 237179237Sjb 238179237Sjb atomic_add_32(&profile_total, 1); 239179237Sjb if (profile_total > profile_max) { 240179237Sjb atomic_add_32(&profile_total, -1); 241179237Sjb return; 242179237Sjb } 243179237Sjb 244179237Sjb prof = kmem_zalloc(sizeof (profile_probe_t), KM_SLEEP); 245179237Sjb (void) strcpy(prof->prof_name, name); 246179237Sjb prof->prof_interval = interval; 247179237Sjb prof->prof_cyclic = CYCLIC_NONE; 248179237Sjb prof->prof_kind = kind; 249179237Sjb prof->prof_id = dtrace_probe_create(profile_id, 250179237Sjb NULL, NULL, name, 251179237Sjb profile_aframes ? profile_aframes : PROF_ARTIFICIAL_FRAMES, prof); 252179237Sjb} 253179237Sjb 254179237Sjb/*ARGSUSED*/ 255179237Sjbstatic void 256179237Sjbprofile_provide(void *arg, dtrace_probedesc_t *desc) 257179237Sjb{ 258179237Sjb int i, j, rate, kind; 259179237Sjb hrtime_t val = 0, mult = 1, len = 0; 260179237Sjb char *name, *suffix = NULL; 261179237Sjb 262179237Sjb const struct { 263179237Sjb char *prefix; 264179237Sjb int kind; 265179237Sjb } types[] = { 266179237Sjb { PROF_PREFIX_PROFILE, PROF_PROFILE }, 267179237Sjb { PROF_PREFIX_TICK, PROF_TICK }, 268179237Sjb { 0, 0 } 269179237Sjb }; 270179237Sjb 271179237Sjb const struct { 272179237Sjb char *name; 273179237Sjb hrtime_t mult; 274179237Sjb } suffixes[] = { 275179237Sjb { "ns", NANOSEC / NANOSEC }, 276179237Sjb { "nsec", NANOSEC / NANOSEC }, 277179237Sjb { "us", NANOSEC / MICROSEC }, 278179237Sjb { "usec", NANOSEC / MICROSEC }, 279179237Sjb { "ms", NANOSEC / MILLISEC }, 280179237Sjb { "msec", NANOSEC / MILLISEC }, 281179237Sjb { "s", NANOSEC / SEC }, 282179237Sjb { "sec", NANOSEC / SEC }, 283179237Sjb { "m", NANOSEC * (hrtime_t)60 }, 284179237Sjb { "min", NANOSEC * (hrtime_t)60 }, 285179237Sjb { "h", NANOSEC * (hrtime_t)(60 * 60) }, 286179237Sjb { "hour", NANOSEC * (hrtime_t)(60 * 60) }, 287179237Sjb { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 288179237Sjb { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 289179237Sjb { "hz", 0 }, 290179237Sjb { NULL } 291179237Sjb }; 292179237Sjb 293179237Sjb if (desc == NULL) { 294179237Sjb char n[PROF_NAMELEN]; 295179237Sjb 296179237Sjb /* 297179237Sjb * If no description was provided, provide all of our probes. 298179237Sjb */ 299179237Sjb for (i = 0; i < sizeof (profile_rates) / sizeof (int); i++) { 300179237Sjb if ((rate = profile_rates[i]) == 0) 301179237Sjb continue; 302179237Sjb 303179237Sjb (void) snprintf(n, PROF_NAMELEN, "%s%d", 304179237Sjb PROF_PREFIX_PROFILE, rate); 305179237Sjb profile_create(NANOSEC / rate, n, PROF_PROFILE); 306179237Sjb } 307179237Sjb 308179237Sjb for (i = 0; i < sizeof (profile_ticks) / sizeof (int); i++) { 309179237Sjb if ((rate = profile_ticks[i]) == 0) 310179237Sjb continue; 311179237Sjb 312179237Sjb (void) snprintf(n, PROF_NAMELEN, "%s%d", 313179237Sjb PROF_PREFIX_TICK, rate); 314179237Sjb profile_create(NANOSEC / rate, n, PROF_TICK); 315179237Sjb } 316179237Sjb 317179237Sjb return; 318179237Sjb } 319179237Sjb 320179237Sjb name = desc->dtpd_name; 321179237Sjb 322179237Sjb for (i = 0; types[i].prefix != NULL; i++) { 323179237Sjb len = strlen(types[i].prefix); 324179237Sjb 325179237Sjb if (strncmp(name, types[i].prefix, len) != 0) 326179237Sjb continue; 327179237Sjb break; 328179237Sjb } 329179237Sjb 330179237Sjb if (types[i].prefix == NULL) 331179237Sjb return; 332179237Sjb 333179237Sjb kind = types[i].kind; 334179237Sjb j = strlen(name) - len; 335179237Sjb 336179237Sjb /* 337179237Sjb * We need to start before any time suffix. 338179237Sjb */ 339179237Sjb for (j = strlen(name); j >= len; j--) { 340179237Sjb if (name[j] >= '0' && name[j] <= '9') 341179237Sjb break; 342179237Sjb suffix = &name[j]; 343179237Sjb } 344179237Sjb 345179237Sjb ASSERT(suffix != NULL); 346179237Sjb 347179237Sjb /* 348179237Sjb * Now determine the numerical value present in the probe name. 349179237Sjb */ 350179237Sjb for (; j >= len; j--) { 351179237Sjb if (name[j] < '0' || name[j] > '9') 352179237Sjb return; 353179237Sjb 354179237Sjb val += (name[j] - '0') * mult; 355179237Sjb mult *= (hrtime_t)10; 356179237Sjb } 357179237Sjb 358179237Sjb if (val == 0) 359179237Sjb return; 360179237Sjb 361179237Sjb /* 362179237Sjb * Look-up the suffix to determine the multiplier. 363179237Sjb */ 364179237Sjb for (i = 0, mult = 0; suffixes[i].name != NULL; i++) { 365179237Sjb if (strcasecmp(suffixes[i].name, suffix) == 0) { 366179237Sjb mult = suffixes[i].mult; 367179237Sjb break; 368179237Sjb } 369179237Sjb } 370179237Sjb 371179237Sjb if (suffixes[i].name == NULL && *suffix != '\0') 372179237Sjb return; 373179237Sjb 374179237Sjb if (mult == 0) { 375179237Sjb /* 376179237Sjb * The default is frequency-per-second. 377179237Sjb */ 378179237Sjb val = NANOSEC / val; 379179237Sjb } else { 380179237Sjb val *= mult; 381179237Sjb } 382179237Sjb 383179237Sjb profile_create(val, name, kind); 384179237Sjb} 385179237Sjb 386179237Sjb/* ARGSUSED */ 387179237Sjbstatic void 388179237Sjbprofile_destroy(void *arg, dtrace_id_t id, void *parg) 389179237Sjb{ 390179237Sjb profile_probe_t *prof = parg; 391179237Sjb 392179237Sjb ASSERT(prof->prof_cyclic == CYCLIC_NONE); 393179237Sjb kmem_free(prof, sizeof (profile_probe_t)); 394179237Sjb 395179237Sjb ASSERT(profile_total >= 1); 396179237Sjb atomic_add_32(&profile_total, -1); 397179237Sjb} 398179237Sjb 399179237Sjb/*ARGSUSED*/ 400179237Sjbstatic void 401179237Sjbprofile_online(void *arg, cpu_t *cpu, cyc_handler_t *hdlr, cyc_time_t *when) 402179237Sjb{ 403179237Sjb profile_probe_t *prof = arg; 404179237Sjb profile_probe_percpu_t *pcpu; 405179237Sjb 406179237Sjb pcpu = kmem_zalloc(sizeof (profile_probe_percpu_t), KM_SLEEP); 407179237Sjb pcpu->profc_probe = prof; 408179237Sjb 409179237Sjb hdlr->cyh_func = profile_fire; 410179237Sjb hdlr->cyh_arg = pcpu; 411179237Sjb 412179237Sjb when->cyt_interval = prof->prof_interval; 413179237Sjb when->cyt_when = gethrtime() + when->cyt_interval; 414179237Sjb 415179237Sjb pcpu->profc_expected = when->cyt_when; 416179237Sjb pcpu->profc_interval = when->cyt_interval; 417179237Sjb} 418179237Sjb 419179237Sjb/*ARGSUSED*/ 420179237Sjbstatic void 421179237Sjbprofile_offline(void *arg, cpu_t *cpu, void *oarg) 422179237Sjb{ 423179237Sjb profile_probe_percpu_t *pcpu = oarg; 424179237Sjb 425179237Sjb ASSERT(pcpu->profc_probe == arg); 426179237Sjb kmem_free(pcpu, sizeof (profile_probe_percpu_t)); 427179237Sjb} 428179237Sjb 429179237Sjb/* ARGSUSED */ 430179237Sjbstatic void 431179237Sjbprofile_enable(void *arg, dtrace_id_t id, void *parg) 432179237Sjb{ 433179237Sjb profile_probe_t *prof = parg; 434179237Sjb cyc_omni_handler_t omni; 435179237Sjb cyc_handler_t hdlr; 436179237Sjb cyc_time_t when; 437179237Sjb 438179237Sjb ASSERT(prof->prof_interval != 0); 439179237Sjb ASSERT(MUTEX_HELD(&cpu_lock)); 440179237Sjb 441179237Sjb if (prof->prof_kind == PROF_TICK) { 442179237Sjb hdlr.cyh_func = profile_tick; 443179237Sjb hdlr.cyh_arg = prof; 444179237Sjb 445179237Sjb when.cyt_interval = prof->prof_interval; 446179237Sjb when.cyt_when = gethrtime() + when.cyt_interval; 447179237Sjb } else { 448179237Sjb ASSERT(prof->prof_kind == PROF_PROFILE); 449179237Sjb omni.cyo_online = profile_online; 450179237Sjb omni.cyo_offline = profile_offline; 451179237Sjb omni.cyo_arg = prof; 452179237Sjb } 453179237Sjb 454179237Sjb if (prof->prof_kind == PROF_TICK) { 455179237Sjb prof->prof_cyclic = cyclic_add(&hdlr, &when); 456179237Sjb } else { 457179237Sjb prof->prof_cyclic = cyclic_add_omni(&omni); 458179237Sjb } 459179237Sjb} 460179237Sjb 461179237Sjb/* ARGSUSED */ 462179237Sjbstatic void 463179237Sjbprofile_disable(void *arg, dtrace_id_t id, void *parg) 464179237Sjb{ 465179237Sjb profile_probe_t *prof = parg; 466179237Sjb 467179237Sjb ASSERT(prof->prof_cyclic != CYCLIC_NONE); 468179237Sjb ASSERT(MUTEX_HELD(&cpu_lock)); 469179237Sjb 470179237Sjb cyclic_remove(prof->prof_cyclic); 471179237Sjb prof->prof_cyclic = CYCLIC_NONE; 472179237Sjb} 473179237Sjb 474179237Sjbstatic void 475179237Sjbprofile_load(void *dummy) 476179237Sjb{ 477179237Sjb /* Create the /dev/dtrace/profile entry. */ 478179237Sjb profile_cdev = make_dev(&profile_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 479179237Sjb "dtrace/profile"); 480179237Sjb 481179237Sjb if (dtrace_register("profile", &profile_attr, DTRACE_PRIV_USER, 482179237Sjb NULL, &profile_pops, NULL, &profile_id) != 0) 483179237Sjb return; 484179237Sjb} 485179237Sjb 486179237Sjb 487179237Sjbstatic int 488179237Sjbprofile_unload() 489179237Sjb{ 490179237Sjb int error = 0; 491179237Sjb 492179237Sjb if ((error = dtrace_unregister(profile_id)) != 0) 493179237Sjb return (error); 494179237Sjb 495179237Sjb destroy_dev(profile_cdev); 496179237Sjb 497179237Sjb return (error); 498179237Sjb} 499179237Sjb 500179237Sjb/* ARGSUSED */ 501179237Sjbstatic int 502179237Sjbprofile_modevent(module_t mod __unused, int type, void *data __unused) 503179237Sjb{ 504179237Sjb int error = 0; 505179237Sjb 506179237Sjb switch (type) { 507179237Sjb case MOD_LOAD: 508179237Sjb break; 509179237Sjb 510179237Sjb case MOD_UNLOAD: 511179237Sjb break; 512179237Sjb 513179237Sjb case MOD_SHUTDOWN: 514179237Sjb break; 515179237Sjb 516179237Sjb default: 517179237Sjb error = EOPNOTSUPP; 518179237Sjb break; 519179237Sjb 520179237Sjb } 521179237Sjb return (error); 522179237Sjb} 523179237Sjb 524179237Sjb/* ARGSUSED */ 525179237Sjbstatic int 526179237Sjbprofile_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) 527179237Sjb{ 528179237Sjb return (0); 529179237Sjb} 530179237Sjb 531179237SjbSYSINIT(profile_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, profile_load, NULL); 532179237SjbSYSUNINIT(profile_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, profile_unload, NULL); 533179237Sjb 534179237SjbDEV_MODULE(profile, profile_modevent, NULL); 535179237SjbMODULE_VERSION(profile, 1); 536179237SjbMODULE_DEPEND(profile, dtrace, 1, 1, 1); 537179237SjbMODULE_DEPEND(profile, cyclic, 1, 1, 1); 538179237SjbMODULE_DEPEND(profile, opensolaris, 1, 1, 1); 539