summaryrefslogtreecommitdiff
path: root/kern/pc_sample.c
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
committerThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
commitf07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch)
tree12b07c7e578fc1a5f53dbfde2632408491ff2a70 /kern/pc_sample.c
Initial source
Diffstat (limited to 'kern/pc_sample.c')
-rw-r--r--kern/pc_sample.c299
1 files changed, 299 insertions, 0 deletions
diff --git a/kern/pc_sample.c b/kern/pc_sample.c
new file mode 100644
index 0000000..01b9acb
--- /dev/null
+++ b/kern/pc_sample.c
@@ -0,0 +1,299 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+
+
+#include <mach_pcsample.h>
+
+#include <mach/mach_types.h> /* vm_address_t */
+#include <mach/std_types.h> /* pointer_t */
+#include <mach/pc_sample.h>
+#include <kern/host.h>
+#include <kern/thread.h>
+#include <kern/pc_sample.h>
+
+#if MACH_PCSAMPLE
+
+#define MAX_PC_SAMPLES 512
+
+typedef sampled_pc_t sampled_pcs[MAX_PC_SAMPLES];
+
+int pc_sampling_enabled = 0;
+decl_simple_lock_data(, pc_sampling_lock) /* lock for enabling */
+
+void take_pc_sample(
+ register thread_t t,
+ register sample_control_t *cp,
+ sampled_pc_flavor_t flavor)
+{
+ vm_offset_t pc;
+ struct sampled_pc *sample;
+
+ pc = interrupted_pc(t);
+ cp->seqno++;
+ sample = &((sampled_pc_t *)cp->buffer)[cp->seqno % MAX_PC_SAMPLES];
+ sample->id = (natural_t)t;
+ sample->pc = pc;
+ sample->sampletype = flavor;
+}
+
+kern_return_t
+thread_enable_pc_sampling(
+ thread_t thread,
+ int *tickp,
+ sampled_pc_flavor_t flavors)
+{
+ vm_offset_t buf;
+ extern int tick;
+
+ if (thread == THREAD_NULL) {
+ return KERN_INVALID_ARGUMENT;
+ }
+ if (thread->pc_sample.buffer == 0) {
+ buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
+ if (buf == 0) {
+ printf("thread_enable_pc_sampling: kalloc failed\n");
+ return KERN_INVALID_ARGUMENT;
+ }
+ thread->pc_sample.buffer = buf;
+ thread->pc_sample.seqno = 0;
+ }
+ *tickp = tick;
+ thread->pc_sample.sampletypes = flavors;
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+task_enable_pc_sampling(
+ task_t task,
+ int *tickp,
+ sampled_pc_flavor_t flavors)
+{
+ vm_offset_t buf;
+ extern int tick;
+
+ if (task == TASK_NULL) {
+ return KERN_INVALID_ARGUMENT;
+ }
+ if (task->pc_sample.buffer == 0) {
+ buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
+ if (buf == 0) {
+ printf("task_enable_pc_sampling: kalloc failed\n");
+ return KERN_INVALID_ARGUMENT;
+ }
+ task->pc_sample.buffer = buf;
+ task->pc_sample.seqno = 0;
+ }
+ *tickp = tick;
+ task->pc_sample.sampletypes = flavors;
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+thread_disable_pc_sampling(
+ thread_t thread,
+ int *samplecntp)
+{
+ vm_offset_t buf;
+
+ if (thread == THREAD_NULL) {
+ return KERN_INVALID_ARGUMENT;
+ }
+ if ((buf = thread->pc_sample.buffer) != 0)
+ kfree(buf, sizeof (sampled_pcs));
+ thread->pc_sample.buffer = (vm_offset_t) 0;
+ thread->pc_sample.seqno = 0;
+ thread->pc_sample.sampletypes = 0; /* shut off sampling */
+
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+task_disable_pc_sampling(
+ task_t task,
+ int *samplecntp)
+{
+ vm_offset_t buf;
+
+ if (task == TASK_NULL) {
+ return KERN_INVALID_ARGUMENT;
+ }
+ if ((buf = task->pc_sample.buffer) != 0)
+ kfree(buf, sizeof (sampled_pcs));
+ task->pc_sample.buffer = (vm_offset_t) 0;
+ task->pc_sample.seqno = 0;
+ task->pc_sample.sampletypes = 0; /* shut off sampling */
+
+ return KERN_SUCCESS;
+}
+
+static kern_return_t
+get_sampled_pcs(
+ sample_control_t *cp,
+ sampled_pc_seqno_t *seqnop,
+ sampled_pc_array_t sampled_pcs_out,
+ int *sampled_pcs_cntp)
+{
+ int nsamples;
+ sampled_pc_seqno_t seqidx1, seqidx2;
+
+ nsamples = cp->seqno - *seqnop;
+ seqidx1 = *seqnop % MAX_PC_SAMPLES; /* index of *seqnop */
+ seqidx2 = cp->seqno % MAX_PC_SAMPLES; /* index of cp->seqno */
+
+ if (nsamples > MAX_PC_SAMPLES) {
+ nsamples = MAX_PC_SAMPLES;
+ seqidx1 = (seqidx2 + 1) % MAX_PC_SAMPLES;
+ }
+
+ if (nsamples > 0) {
+ /*
+ * Carefully copy sampled_pcs into sampled_pcs_msgbuf IN ORDER.
+ */
+ if (seqidx1 < seqidx2) {
+ /*
+ * Simple case: no wraparound.
+ * Copy from seqidx1 to seqidx2.
+ */
+ bcopy((sampled_pc_array_t)cp->buffer + seqidx1 + 1,
+ sampled_pcs_out,
+ nsamples * sizeof(sampled_pc_t));
+ } else {
+ /* seqidx1 > seqidx2 -- Handle wraparound. */
+
+ bcopy((sampled_pc_array_t)cp->buffer + seqidx1 + 1,
+ sampled_pcs_out,
+ (MAX_PC_SAMPLES - seqidx1 - 1) * sizeof(sampled_pc_t));
+
+ bcopy((sampled_pc_array_t)cp->buffer,
+ sampled_pcs_out + (MAX_PC_SAMPLES - seqidx1 - 1),
+ (seqidx2 + 1) * sizeof(sampled_pc_t));
+ }
+ } else {
+ /* could either be zero because of overflow, or because
+ * we are being lied to. In either case, return nothing.
+ * If overflow, only once in a blue moon. If being lied to,
+ * then we have no obligation to return anything useful anyway.
+ */
+ ;
+ }
+
+ *sampled_pcs_cntp = nsamples;
+ *seqnop = cp->seqno;
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+thread_get_sampled_pcs(
+ thread_t thread,
+ sampled_pc_seqno_t *seqnop,
+ sampled_pc_array_t sampled_pcs_out,
+ int *sampled_pcs_cntp)
+{
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ if (thread->pc_sample.buffer == 0)
+ return KERN_FAILURE;
+
+ return get_sampled_pcs(&thread->pc_sample, seqnop, sampled_pcs_out,
+ sampled_pcs_cntp);
+}
+
+kern_return_t
+task_get_sampled_pcs(
+ task_t task,
+ sampled_pc_seqno_t *seqnop,
+ sampled_pc_array_t sampled_pcs_out,
+ int *sampled_pcs_cntp)
+{
+ if (task == TASK_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ if (task->pc_sample.buffer == 0)
+ return KERN_FAILURE;
+
+ return get_sampled_pcs(&task->pc_sample, seqnop, sampled_pcs_out,
+ sampled_pcs_cntp);
+}
+
+#else /* MACH_PCSAMPLE */
+
+kern_return_t
+thread_enable_pc_sampling(
+ thread_t thread,
+ int *tickp,
+ sampled_pc_flavor_t flavors)
+{
+ return KERN_FAILURE; /* not implemented */
+}
+
+kern_return_t
+task_enable_pc_sampling(
+ task_t task,
+ int *tickp,
+ sampled_pc_flavor_t flavors)
+{
+ return KERN_FAILURE; /* not implemented */
+}
+
+kern_return_t
+thread_disable_pc_sampling(
+ thread_t thread,
+ int *samplecntp)
+{
+ return KERN_FAILURE; /* not implemented */
+}
+
+kern_return_t
+task_disable_pc_sampling(
+ task_t task,
+ int *samplecntp)
+{
+ return KERN_FAILURE; /* not implemented */
+}
+
+kern_return_t
+thread_get_sampled_pcs(
+ thread_t thread,
+ sampled_pc_seqno_t *seqnop,
+ sampled_pc_array_t sampled_pcs_out,
+ int *sampled_pcs_cntp)
+{
+ return KERN_FAILURE; /* not implemented */
+}
+
+kern_return_t
+task_get_sampled_pcs(
+ task_t task,
+ sampled_pc_seqno_t *seqnop,
+ sampled_pc_array_t sampled_pcs_out,
+ int *sampled_pcs_cntp)
+{
+ return KERN_FAILURE; /* not implemented */
+}
+
+#endif /* MACH_PCSAMPLE */