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$ 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 122242723Sjhibbits#ifdef __powerpc__ 123242723Sjhibbits/* 124242723Sjhibbits * This value is bogus just to make module compilable on powerpc 125242723Sjhibbits */ 126242723Sjhibbits#define PROF_ARTIFICIAL_FRAMES 3 127242723Sjhibbits#endif 128242723Sjhibbits 129179237Sjbtypedef struct profile_probe { 130179237Sjb char prof_name[PROF_NAMELEN]; 131179237Sjb dtrace_id_t prof_id; 132179237Sjb int prof_kind; 133179237Sjb hrtime_t prof_interval; 134179237Sjb cyclic_id_t prof_cyclic; 135179237Sjb} profile_probe_t; 136179237Sjb 137179237Sjbtypedef struct profile_probe_percpu { 138179237Sjb hrtime_t profc_expected; 139179237Sjb hrtime_t profc_interval; 140179237Sjb profile_probe_t *profc_probe; 141179237Sjb} profile_probe_percpu_t; 142179237Sjb 143179237Sjbstatic d_open_t profile_open; 144179237Sjbstatic int profile_unload(void); 145179237Sjbstatic void profile_create(hrtime_t, char *, int); 146179237Sjbstatic void profile_destroy(void *, dtrace_id_t, void *); 147179237Sjbstatic void profile_enable(void *, dtrace_id_t, void *); 148179237Sjbstatic void profile_disable(void *, dtrace_id_t, void *); 149179237Sjbstatic void profile_load(void *); 150179237Sjbstatic void profile_provide(void *, dtrace_probedesc_t *); 151179237Sjb 152179237Sjbstatic int profile_rates[] = { 153179237Sjb 97, 199, 499, 997, 1999, 154179237Sjb 4001, 4999, 0, 0, 0, 155179237Sjb 0, 0, 0, 0, 0, 156179237Sjb 0, 0, 0, 0, 0 157179237Sjb}; 158179237Sjb 159179237Sjbstatic int profile_ticks[] = { 160179237Sjb 1, 10, 100, 500, 1000, 161179237Sjb 5000, 0, 0, 0, 0, 162179237Sjb 0, 0, 0, 0, 0 163179237Sjb}; 164179237Sjb 165179237Sjb/* 166179237Sjb * profile_max defines the upper bound on the number of profile probes that 167179237Sjb * can exist (this is to prevent malicious or clumsy users from exhausing 168179237Sjb * system resources by creating a slew of profile probes). At mod load time, 169179237Sjb * this gets its value from PROFILE_MAX_DEFAULT or profile-max-probes if it's 170179237Sjb * present in the profile.conf file. 171179237Sjb */ 172179237Sjb#define PROFILE_MAX_DEFAULT 1000 /* default max. number of probes */ 173179237Sjbstatic uint32_t profile_max = PROFILE_MAX_DEFAULT; 174179237Sjb /* maximum number of profile probes */ 175179237Sjbstatic uint32_t profile_total; /* current number of profile probes */ 176179237Sjb 177179237Sjbstatic struct cdevsw profile_cdevsw = { 178179237Sjb .d_version = D_VERSION, 179179237Sjb .d_open = profile_open, 180179237Sjb .d_name = "profile", 181179237Sjb}; 182179237Sjb 183179237Sjbstatic dtrace_pattr_t profile_attr = { 184179237Sjb{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 185179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 186179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 187179237Sjb{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 188179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 189179237Sjb}; 190179237Sjb 191179237Sjbstatic dtrace_pops_t profile_pops = { 192179237Sjb profile_provide, 193179237Sjb NULL, 194179237Sjb profile_enable, 195179237Sjb profile_disable, 196179237Sjb NULL, 197179237Sjb NULL, 198179237Sjb NULL, 199179237Sjb NULL, 200179237Sjb NULL, 201179237Sjb profile_destroy 202179237Sjb}; 203179237Sjb 204179237Sjbstatic struct cdev *profile_cdev; 205179237Sjbstatic dtrace_provider_id_t profile_id; 206179237Sjbstatic hrtime_t profile_interval_min = NANOSEC / 5000; /* 5000 hz */ 207179237Sjbstatic int profile_aframes = 0; /* override */ 208179237Sjb 209179237Sjbstatic void 210179237Sjbprofile_fire(void *arg) 211179237Sjb{ 212179237Sjb profile_probe_percpu_t *pcpu = arg; 213179237Sjb profile_probe_t *prof = pcpu->profc_probe; 214179237Sjb hrtime_t late; 215179237Sjb solaris_cpu_t *c = &solaris_cpu[curcpu]; 216179237Sjb 217179237Sjb late = gethrtime() - pcpu->profc_expected; 218179237Sjb pcpu->profc_expected += pcpu->profc_interval; 219179237Sjb 220179237Sjb dtrace_probe(prof->prof_id, c->cpu_profile_pc, 221179237Sjb c->cpu_profile_upc, late, 0, 0); 222179237Sjb} 223179237Sjb 224179237Sjbstatic void 225179237Sjbprofile_tick(void *arg) 226179237Sjb{ 227179237Sjb profile_probe_t *prof = arg; 228179237Sjb solaris_cpu_t *c = &solaris_cpu[curcpu]; 229179237Sjb 230179237Sjb dtrace_probe(prof->prof_id, c->cpu_profile_pc, 231179237Sjb c->cpu_profile_upc, 0, 0, 0); 232179237Sjb} 233179237Sjb 234179237Sjbstatic void 235179237Sjbprofile_create(hrtime_t interval, char *name, int kind) 236179237Sjb{ 237179237Sjb profile_probe_t *prof; 238179237Sjb 239179237Sjb if (interval < profile_interval_min) 240179237Sjb return; 241179237Sjb 242179237Sjb if (dtrace_probe_lookup(profile_id, NULL, NULL, name) != 0) 243179237Sjb return; 244179237Sjb 245179237Sjb atomic_add_32(&profile_total, 1); 246179237Sjb if (profile_total > profile_max) { 247179237Sjb atomic_add_32(&profile_total, -1); 248179237Sjb return; 249179237Sjb } 250179237Sjb 251179237Sjb prof = kmem_zalloc(sizeof (profile_probe_t), KM_SLEEP); 252179237Sjb (void) strcpy(prof->prof_name, name); 253179237Sjb prof->prof_interval = interval; 254179237Sjb prof->prof_cyclic = CYCLIC_NONE; 255179237Sjb prof->prof_kind = kind; 256179237Sjb prof->prof_id = dtrace_probe_create(profile_id, 257179237Sjb NULL, NULL, name, 258179237Sjb profile_aframes ? profile_aframes : PROF_ARTIFICIAL_FRAMES, prof); 259179237Sjb} 260179237Sjb 261179237Sjb/*ARGSUSED*/ 262179237Sjbstatic void 263179237Sjbprofile_provide(void *arg, dtrace_probedesc_t *desc) 264179237Sjb{ 265179237Sjb int i, j, rate, kind; 266179237Sjb hrtime_t val = 0, mult = 1, len = 0; 267179237Sjb char *name, *suffix = NULL; 268179237Sjb 269179237Sjb const struct { 270179237Sjb char *prefix; 271179237Sjb int kind; 272179237Sjb } types[] = { 273179237Sjb { PROF_PREFIX_PROFILE, PROF_PROFILE }, 274179237Sjb { PROF_PREFIX_TICK, PROF_TICK }, 275179237Sjb { 0, 0 } 276179237Sjb }; 277179237Sjb 278179237Sjb const struct { 279179237Sjb char *name; 280179237Sjb hrtime_t mult; 281179237Sjb } suffixes[] = { 282179237Sjb { "ns", NANOSEC / NANOSEC }, 283179237Sjb { "nsec", NANOSEC / NANOSEC }, 284179237Sjb { "us", NANOSEC / MICROSEC }, 285179237Sjb { "usec", NANOSEC / MICROSEC }, 286179237Sjb { "ms", NANOSEC / MILLISEC }, 287179237Sjb { "msec", NANOSEC / MILLISEC }, 288179237Sjb { "s", NANOSEC / SEC }, 289179237Sjb { "sec", NANOSEC / SEC }, 290179237Sjb { "m", NANOSEC * (hrtime_t)60 }, 291179237Sjb { "min", NANOSEC * (hrtime_t)60 }, 292179237Sjb { "h", NANOSEC * (hrtime_t)(60 * 60) }, 293179237Sjb { "hour", NANOSEC * (hrtime_t)(60 * 60) }, 294179237Sjb { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 295179237Sjb { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 296179237Sjb { "hz", 0 }, 297179237Sjb { NULL } 298179237Sjb }; 299179237Sjb 300179237Sjb if (desc == NULL) { 301179237Sjb char n[PROF_NAMELEN]; 302179237Sjb 303179237Sjb /* 304179237Sjb * If no description was provided, provide all of our probes. 305179237Sjb */ 306179237Sjb for (i = 0; i < sizeof (profile_rates) / sizeof (int); i++) { 307179237Sjb if ((rate = profile_rates[i]) == 0) 308179237Sjb continue; 309179237Sjb 310179237Sjb (void) snprintf(n, PROF_NAMELEN, "%s%d", 311179237Sjb PROF_PREFIX_PROFILE, rate); 312179237Sjb profile_create(NANOSEC / rate, n, PROF_PROFILE); 313179237Sjb } 314179237Sjb 315179237Sjb for (i = 0; i < sizeof (profile_ticks) / sizeof (int); i++) { 316179237Sjb if ((rate = profile_ticks[i]) == 0) 317179237Sjb continue; 318179237Sjb 319179237Sjb (void) snprintf(n, PROF_NAMELEN, "%s%d", 320179237Sjb PROF_PREFIX_TICK, rate); 321179237Sjb profile_create(NANOSEC / rate, n, PROF_TICK); 322179237Sjb } 323179237Sjb 324179237Sjb return; 325179237Sjb } 326179237Sjb 327179237Sjb name = desc->dtpd_name; 328179237Sjb 329179237Sjb for (i = 0; types[i].prefix != NULL; i++) { 330179237Sjb len = strlen(types[i].prefix); 331179237Sjb 332179237Sjb if (strncmp(name, types[i].prefix, len) != 0) 333179237Sjb continue; 334179237Sjb break; 335179237Sjb } 336179237Sjb 337179237Sjb if (types[i].prefix == NULL) 338179237Sjb return; 339179237Sjb 340179237Sjb kind = types[i].kind; 341179237Sjb j = strlen(name) - len; 342179237Sjb 343179237Sjb /* 344179237Sjb * We need to start before any time suffix. 345179237Sjb */ 346179237Sjb for (j = strlen(name); j >= len; j--) { 347179237Sjb if (name[j] >= '0' && name[j] <= '9') 348179237Sjb break; 349179237Sjb suffix = &name[j]; 350179237Sjb } 351179237Sjb 352179237Sjb ASSERT(suffix != NULL); 353179237Sjb 354179237Sjb /* 355179237Sjb * Now determine the numerical value present in the probe name. 356179237Sjb */ 357179237Sjb for (; j >= len; j--) { 358179237Sjb if (name[j] < '0' || name[j] > '9') 359179237Sjb return; 360179237Sjb 361179237Sjb val += (name[j] - '0') * mult; 362179237Sjb mult *= (hrtime_t)10; 363179237Sjb } 364179237Sjb 365179237Sjb if (val == 0) 366179237Sjb return; 367179237Sjb 368179237Sjb /* 369179237Sjb * Look-up the suffix to determine the multiplier. 370179237Sjb */ 371179237Sjb for (i = 0, mult = 0; suffixes[i].name != NULL; i++) { 372179237Sjb if (strcasecmp(suffixes[i].name, suffix) == 0) { 373179237Sjb mult = suffixes[i].mult; 374179237Sjb break; 375179237Sjb } 376179237Sjb } 377179237Sjb 378179237Sjb if (suffixes[i].name == NULL && *suffix != '\0') 379179237Sjb return; 380179237Sjb 381179237Sjb if (mult == 0) { 382179237Sjb /* 383179237Sjb * The default is frequency-per-second. 384179237Sjb */ 385179237Sjb val = NANOSEC / val; 386179237Sjb } else { 387179237Sjb val *= mult; 388179237Sjb } 389179237Sjb 390179237Sjb profile_create(val, name, kind); 391179237Sjb} 392179237Sjb 393179237Sjb/* ARGSUSED */ 394179237Sjbstatic void 395179237Sjbprofile_destroy(void *arg, dtrace_id_t id, void *parg) 396179237Sjb{ 397179237Sjb profile_probe_t *prof = parg; 398179237Sjb 399179237Sjb ASSERT(prof->prof_cyclic == CYCLIC_NONE); 400179237Sjb kmem_free(prof, sizeof (profile_probe_t)); 401179237Sjb 402179237Sjb ASSERT(profile_total >= 1); 403179237Sjb atomic_add_32(&profile_total, -1); 404179237Sjb} 405179237Sjb 406179237Sjb/*ARGSUSED*/ 407179237Sjbstatic void 408179237Sjbprofile_online(void *arg, cpu_t *cpu, cyc_handler_t *hdlr, cyc_time_t *when) 409179237Sjb{ 410179237Sjb profile_probe_t *prof = arg; 411179237Sjb profile_probe_percpu_t *pcpu; 412179237Sjb 413179237Sjb pcpu = kmem_zalloc(sizeof (profile_probe_percpu_t), KM_SLEEP); 414179237Sjb pcpu->profc_probe = prof; 415179237Sjb 416179237Sjb hdlr->cyh_func = profile_fire; 417179237Sjb hdlr->cyh_arg = pcpu; 418179237Sjb 419179237Sjb when->cyt_interval = prof->prof_interval; 420179237Sjb when->cyt_when = gethrtime() + when->cyt_interval; 421179237Sjb 422179237Sjb pcpu->profc_expected = when->cyt_when; 423179237Sjb pcpu->profc_interval = when->cyt_interval; 424179237Sjb} 425179237Sjb 426179237Sjb/*ARGSUSED*/ 427179237Sjbstatic void 428179237Sjbprofile_offline(void *arg, cpu_t *cpu, void *oarg) 429179237Sjb{ 430179237Sjb profile_probe_percpu_t *pcpu = oarg; 431179237Sjb 432179237Sjb ASSERT(pcpu->profc_probe == arg); 433179237Sjb kmem_free(pcpu, sizeof (profile_probe_percpu_t)); 434179237Sjb} 435179237Sjb 436179237Sjb/* ARGSUSED */ 437179237Sjbstatic void 438179237Sjbprofile_enable(void *arg, dtrace_id_t id, void *parg) 439179237Sjb{ 440179237Sjb profile_probe_t *prof = parg; 441179237Sjb cyc_omni_handler_t omni; 442179237Sjb cyc_handler_t hdlr; 443179237Sjb cyc_time_t when; 444179237Sjb 445179237Sjb ASSERT(prof->prof_interval != 0); 446179237Sjb ASSERT(MUTEX_HELD(&cpu_lock)); 447179237Sjb 448179237Sjb if (prof->prof_kind == PROF_TICK) { 449179237Sjb hdlr.cyh_func = profile_tick; 450179237Sjb hdlr.cyh_arg = prof; 451179237Sjb 452179237Sjb when.cyt_interval = prof->prof_interval; 453179237Sjb when.cyt_when = gethrtime() + when.cyt_interval; 454179237Sjb } else { 455179237Sjb ASSERT(prof->prof_kind == PROF_PROFILE); 456179237Sjb omni.cyo_online = profile_online; 457179237Sjb omni.cyo_offline = profile_offline; 458179237Sjb omni.cyo_arg = prof; 459179237Sjb } 460179237Sjb 461179237Sjb if (prof->prof_kind == PROF_TICK) { 462179237Sjb prof->prof_cyclic = cyclic_add(&hdlr, &when); 463179237Sjb } else { 464179237Sjb prof->prof_cyclic = cyclic_add_omni(&omni); 465179237Sjb } 466179237Sjb} 467179237Sjb 468179237Sjb/* ARGSUSED */ 469179237Sjbstatic void 470179237Sjbprofile_disable(void *arg, dtrace_id_t id, void *parg) 471179237Sjb{ 472179237Sjb profile_probe_t *prof = parg; 473179237Sjb 474179237Sjb ASSERT(prof->prof_cyclic != CYCLIC_NONE); 475179237Sjb ASSERT(MUTEX_HELD(&cpu_lock)); 476179237Sjb 477179237Sjb cyclic_remove(prof->prof_cyclic); 478179237Sjb prof->prof_cyclic = CYCLIC_NONE; 479179237Sjb} 480179237Sjb 481179237Sjbstatic void 482179237Sjbprofile_load(void *dummy) 483179237Sjb{ 484179237Sjb /* Create the /dev/dtrace/profile entry. */ 485179237Sjb profile_cdev = make_dev(&profile_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 486179237Sjb "dtrace/profile"); 487179237Sjb 488179237Sjb if (dtrace_register("profile", &profile_attr, DTRACE_PRIV_USER, 489179237Sjb NULL, &profile_pops, NULL, &profile_id) != 0) 490179237Sjb return; 491179237Sjb} 492179237Sjb 493179237Sjb 494179237Sjbstatic int 495179237Sjbprofile_unload() 496179237Sjb{ 497179237Sjb int error = 0; 498179237Sjb 499179237Sjb if ((error = dtrace_unregister(profile_id)) != 0) 500179237Sjb return (error); 501179237Sjb 502179237Sjb destroy_dev(profile_cdev); 503179237Sjb 504179237Sjb return (error); 505179237Sjb} 506179237Sjb 507179237Sjb/* ARGSUSED */ 508179237Sjbstatic int 509179237Sjbprofile_modevent(module_t mod __unused, int type, void *data __unused) 510179237Sjb{ 511179237Sjb int error = 0; 512179237Sjb 513179237Sjb switch (type) { 514179237Sjb case MOD_LOAD: 515179237Sjb break; 516179237Sjb 517179237Sjb case MOD_UNLOAD: 518179237Sjb break; 519179237Sjb 520179237Sjb case MOD_SHUTDOWN: 521179237Sjb break; 522179237Sjb 523179237Sjb default: 524179237Sjb error = EOPNOTSUPP; 525179237Sjb break; 526179237Sjb 527179237Sjb } 528179237Sjb return (error); 529179237Sjb} 530179237Sjb 531179237Sjb/* ARGSUSED */ 532179237Sjbstatic int 533179237Sjbprofile_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) 534179237Sjb{ 535179237Sjb return (0); 536179237Sjb} 537179237Sjb 538179237SjbSYSINIT(profile_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, profile_load, NULL); 539179237SjbSYSUNINIT(profile_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, profile_unload, NULL); 540179237Sjb 541179237SjbDEV_MODULE(profile, profile_modevent, NULL); 542179237SjbMODULE_VERSION(profile, 1); 543179237SjbMODULE_DEPEND(profile, dtrace, 1, 1, 1); 544179237SjbMODULE_DEPEND(profile, cyclic, 1, 1, 1); 545179237SjbMODULE_DEPEND(profile, opensolaris, 1, 1, 1); 546