auto import from //depot/cupcake/@135843
diff --git a/daemon/opd_spu.c b/daemon/opd_spu.c
new file mode 100644
index 0000000..62a2c2b
--- /dev/null
+++ b/daemon/opd_spu.c
@@ -0,0 +1,176 @@
+/**
+ * @file daemon/opd_spu.c
+ * Processing the sample buffer for Cell BE SPU profile
+ *
+ * @remark Copyright 2007 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Maynard Johnson
+ * (C) Copyright IBM Corporation 2007
+ */
+
+#include "opd_interface.h"
+#include "opd_printf.h"
+#include "opd_sfile.h"
+#include "opd_stats.h"
+#include "opd_trans.h"
+#include "op_libiberty.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+struct spu_context_info {
+ pid_t tid;
+ pid_t tgid;
+ cookie_t app_cookie;
+ uint64_t embedded_offset;
+ cookie_t spu_cookie;
+};
+
+static struct spu_context_info * spu_context_cache;
+
+/* Forward declaration */
+static void process_spu_samples(struct transient * trans);
+
+void (*special_processor)(struct transient *);
+
+/*
+ * This function is called when the first value found in the
+ * buffer (after the beginning ESCAPE_CODE) is SPU_PROFILING_CODE.
+ * Once we get here, the rest of the processing of the buffer is
+ * Cell-SPU-specific, so we do not need to return until the
+ * trans.buffer is empty.
+ */
+void code_spu_profiling(struct transient * trans)
+{
+ /* Next value in buffer is the number of SPUs. */
+ unsigned long long num_spus = pop_buffer_value(trans);
+ /* Free the cache from previous run */
+ free(spu_context_cache);
+ spu_context_cache = xmalloc(sizeof(struct spu_context_info) * num_spus);
+ special_processor = process_spu_samples;
+ process_spu_samples(trans);
+}
+
+void code_spu_ctx_switch(struct transient * trans)
+{
+ clear_trans_current(trans);
+
+ if (!enough_remaining(trans, 6)) {
+ trans->remaining = 0;
+ return;
+ }
+
+ /* First value in the buffer for an SPU context switch is
+ * the SPU number. For SPU profiling, 'cpu' = 'spu'.
+ */
+ trans->cpu = pop_buffer_value(trans);
+ trans->tid = pop_buffer_value(trans);
+ trans->tgid = pop_buffer_value(trans);
+ trans->app_cookie = pop_buffer_value(trans);
+
+ if (vmisc) {
+ char const * app = find_cookie(trans->app_cookie);
+ printf("SPU_CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n",
+ (unsigned long)trans->tid, (unsigned long)trans->tgid,
+ trans->app_cookie, app ? app : "none");
+ }
+
+ /* The trans->cookie will point to the binary file where the SPU ELF
+ * can be found. If the SPU ELF is embedded, it may be embedded in
+ * either the executable application binary or a shared lib. If shared
+ * library, then trans->cookie will differ from the previously obtained
+ * trans->app_cookie. For the non-embedded case, trans->cookie always
+ * points to a separate binary file.
+ */
+ trans->cookie = pop_buffer_value(trans);
+ trans->embedded_offset = pop_buffer_value(trans);
+}
+
+
+static void cache_spu_context_info(struct transient * trans)
+{
+ int i = trans->cpu;
+ spu_context_cache[i].tid = trans->tid;
+ spu_context_cache[i].tgid = trans->tgid;
+ spu_context_cache[i].app_cookie = trans->app_cookie;
+ spu_context_cache[i].embedded_offset = trans->embedded_offset;
+ spu_context_cache[i].spu_cookie = trans->cookie;
+}
+
+static void update_trans_for_spu(struct transient * trans)
+{
+ int i = trans->cpu;
+ trans->tid = spu_context_cache[i].tid;
+ trans->tgid = spu_context_cache[i].tgid;
+ trans->app_cookie = spu_context_cache[i].app_cookie;
+ trans->embedded_offset = spu_context_cache[i].embedded_offset;
+ trans->cookie = spu_context_cache[i].spu_cookie;
+}
+#define SPU_NUM_MASK 0xFFFFFFFF00000000ULL
+#define SPU_CYCLES_COUNTER 0
+
+static void opd_put_spu_sample
+(struct transient * trans, unsigned long long pc)
+{
+ unsigned long spu_number = (pc & SPU_NUM_MASK) >> 32;
+ if (trans->cpu != spu_number) {
+ trans->cpu = spu_number;
+ clear_trans_current(trans);
+ update_trans_for_spu(trans);
+ }
+ /* get the current sfile if needed */
+ if (!trans->current)
+ trans->current = sfile_find(trans);
+
+ if (trans->tracing != TRACING_ON)
+ trans->event = SPU_CYCLES_COUNTER;
+
+ trans->pc = (pc & ~SPU_NUM_MASK);
+ /* log the sample or arc */
+ sfile_log_sample(trans);
+
+ /* switch to trace mode */
+ if (trans->tracing == TRACING_START)
+ trans->tracing = TRACING_ON;
+
+ update_trans_last(trans);
+}
+
+/*
+ * This function processes SPU context switches and
+ * SPU program counter samples. After processing a
+ * context switch (via handlers[code)), we cache the
+ * SPU context information that has been temporarily
+ * stored in trans.
+ */
+static void process_spu_samples(struct transient * trans)
+{
+ unsigned long long code;
+ trans->in_kernel = 0;
+ while (trans->remaining) {
+ code = pop_buffer_value(trans);
+
+ if (!is_escape_code(code)) {
+ opd_put_spu_sample(trans, code);
+ continue;
+ }
+
+ if (!trans->remaining) {
+ verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
+ opd_stats[OPD_DANGLING_CODE]++;
+ break;
+ }
+
+ /* started with ESCAPE_CODE, next is type */
+ code = pop_buffer_value(trans);
+
+ if (code >= LAST_CODE) {
+ fprintf(stderr, "Unknown code %llu\n", code);
+ abort();
+ }
+
+ handlers[code](trans);
+ cache_spu_context_info(trans);
+ }
+}