Permalink
Browse files

Code drop from //branches/cupcake/...@124589

  • Loading branch information...
1 parent 48ae5fc commit 7984f7ab3e13cda0c3b04ffeb2608f232e57f93a The Android Open Source Project committed Dec 18, 2008
Showing with 2,506 additions and 532 deletions.
  1. +4 −2 daemon/Android.mk
  2. +107 −10 daemon/init.c
  3. +26 −19 daemon/opd_anon.c
  4. +4 −0 daemon/opd_anon.h
  5. +13 −1 daemon/opd_cookie.c
  6. +4 −1 daemon/opd_events.c
  7. +3 −1 daemon/opd_events.h
  8. +22 −3 daemon/opd_interface.h
  9. +37 −4 daemon/opd_kernel.c
  10. +5 −0 daemon/opd_kernel.h
  11. +11 −2 daemon/opd_mangling.c
  12. +32 −0 daemon/opd_perfmon.c
  13. +96 −0 daemon/opd_pipe.c
  14. +45 −0 daemon/opd_pipe.h
  15. +30 −19 daemon/opd_sfile.c
  16. +7 −2 daemon/opd_sfile.h
  17. +176 −0 daemon/opd_spu.c
  18. +8 −8 daemon/opd_stats.c
  19. +51 −21 daemon/opd_trans.c
  20. +25 −0 daemon/opd_trans.h
  21. +61 −17 daemon/oprofiled.c
  22. +7 −0 daemon/oprofiled.h
  23. +2 −2 {libabic → libabi}/Android.mk
  24. +75 −0 libabi/abi.cpp
  25. +42 −0 libabi/abi.h
  26. +94 −0 libabi/op_abi.c
  27. +13 −0 {libabic → libabi}/op_abi.h
  28. +225 −0 libabi/opimport.cpp
  29. +0 −84 libabic/op_abi.cpp
  30. +6 −8 libdb/db_debug.c
  31. +61 −25 libdb/db_insert.c
  32. +51 −53 libdb/db_manage.c
  33. +3 −2 libdb/db_stat.c
  34. +36 −16 libdb/odb.h
  35. +1 −0 libop/Android.mk
  36. +47 −3 libop/op_alloc_counter.c
  37. +77 −0 libop/op_config.c
  38. +32 −12 libop/op_config.h
  39. +18 −12 libop/op_config_24.h
  40. +20 −4 libop/op_cpu_type.c
  41. +22 −1 libop/op_cpu_type.h
  42. +60 −25 libop/op_events.c
  43. +8 −8 libop/op_events.h
  44. +1 −4 libop/op_get_interface.c
  45. +15 −8 libop/op_mangle.c
  46. +1 −0 libop/op_mangle.h
  47. +4 −0 libop/op_sample_file.h
  48. +113 −1 libutil/op_file.c
  49. +45 −0 libutil/op_file.h
  50. +46 −0 libutil/op_growable_buffer.c
  51. +45 −0 libutil/op_growable_buffer.h
  52. +0 −25 libutil/op_libiberty.c
  53. +9 −0 libutil/op_libiberty.h
  54. +1 −1 libutil/op_list.h
  55. +3 −0 libutil/op_types.h
  56. +1 −1 opcontrol/Android.mk
  57. +485 −127 opcontrol/opcontrol.cpp
  58. +70 −0 opimport_pull
View
6 daemon/Android.mk
@@ -9,20 +9,22 @@ LOCAL_SRC_FILES:= \
opd_kernel.c \
opd_mangling.c \
opd_perfmon.c \
+ opd_pipe.c \
opd_sfile.c \
+ opd_spu.c \
opd_stats.c \
opd_trans.c \
oprofiled.c
LOCAL_STATIC_LIBRARIES := \
- libpopt libutil libdb libabic libop
+ libpopt libutil libdb libabi libop
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/.. \
$(LOCAL_PATH)/../libdb \
$(LOCAL_PATH)/../libutil \
$(LOCAL_PATH)/../libop \
- $(LOCAL_PATH)/../libabic
+ $(LOCAL_PATH)/../libabi
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := debug
View
117 daemon/init.c
@@ -7,13 +7,18 @@
*
* @author John Levon
* @author Philippe Elie
+ * @Modifications Daniel Hansel
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
*/
#include "config.h"
#include "oprofiled.h"
#include "opd_stats.h"
#include "opd_sfile.h"
+#include "opd_pipe.h"
#include "opd_kernel.h"
#include "opd_trans.h"
#include "opd_anon.h"
@@ -30,17 +35,30 @@
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
+#include <limits.h>
#include <stdlib.h>
+#include <sys/time.h>
+#if ANDROID
+#include <sys/wait.h>
+#else
+#include <wait.h>
+#endif
+#include <string.h>
size_t kernel_pointer_size;
static fd_t devfd;
static char * sbuf;
static size_t s_buf_bytesize;
+extern char * session_dir;
+static char start_time_str[32];
+static int jit_conversion_running;
static void opd_sighup(void);
static void opd_alarm(void);
static void opd_sigterm(void);
+static void opd_sigchild(void);
+static void opd_do_jitdumps(void);
/**
* opd_open_files - open necessary files
@@ -50,7 +68,7 @@ static void opd_sigterm(void);
*/
static void opd_open_files(void)
{
- devfd = op_open_device(OP_DRIVER_BASE"/buffer");
+ devfd = op_open_device("/dev/oprofile/buffer");
if (devfd == -1) {
if (errno == EINVAL)
fprintf(stderr, "Failed to open device. Possibly you have passed incorrect\n"
@@ -61,7 +79,7 @@ static void opd_open_files(void)
}
/* give output before re-opening stdout as the logfile */
- printf("Using log file " OP_LOG_FILE "\n");
+ printf("Using log file %s\n", op_log_file);
/* set up logfile */
close(0);
@@ -73,6 +91,7 @@ static void opd_open_files(void)
}
opd_open_logfile();
+ opd_create_pipe();
printf("oprofiled started %s", op_get_time());
printf("kernel pointer size: %lu\n",
@@ -87,12 +106,12 @@ static void complete_dump(void)
FILE * status_file;
retry:
- status_file = fopen(OP_DUMP_STATUS, "w");
+ status_file = fopen(op_dump_status, "w");
if (!status_file && errno == EMFILE) {
if (sfile_lru_clear()) {
printf("LRU cleared but file open fails for %s.\n",
- OP_DUMP_STATUS);
+ op_dump_status);
abort();
}
goto retry;
@@ -130,6 +149,48 @@ static void opd_do_samples(char const * opd_buf, ssize_t count)
complete_dump();
}
+static void opd_do_jitdumps(void)
+{
+ pid_t childpid;
+ int arg_num;
+ unsigned long long end_time = 0ULL;
+ struct timeval tv;
+ char end_time_str[32];
+ char opjitconv_path[PATH_MAX + 1];
+ char * exec_args[6];
+
+ if (jit_conversion_running)
+ return;
+ jit_conversion_running = 1;
+
+ childpid = fork();
+ switch (childpid) {
+ case -1:
+ perror("Error forking JIT dump process!");
+ break;
+ case 0:
+ gettimeofday(&tv, NULL);
+ end_time = tv.tv_sec;
+ sprintf(end_time_str, "%llu", end_time);
+ sprintf(opjitconv_path, "%s/%s", OP_BINDIR, "opjitconv");
+ arg_num = 0;
+ exec_args[arg_num++] = opjitconv_path;
+ if (vmisc)
+ exec_args[arg_num++] = "-d";
+ exec_args[arg_num++] = session_dir;
+ exec_args[arg_num++] = start_time_str;
+ exec_args[arg_num++] = end_time_str;
+ exec_args[arg_num] = (char *) NULL;
+ execvp("opjitconv", exec_args);
+ fprintf(stderr, "Failed to exec %s: %s\n",
+ exec_args[0], strerror(errno));
+ /* We don't want any cleanup in the child */
+ _exit(EXIT_FAILURE);
+ default:
+ break;
+ }
+
+}
/**
* opd_do_read - enter processing loop
@@ -141,6 +202,8 @@ static void opd_do_samples(char const * opd_buf, ssize_t count)
*/
static void opd_do_read(char * buf, size_t size)
{
+ opd_open_pipe();
+
while (1) {
ssize_t count = -1;
@@ -164,6 +227,9 @@ static void opd_do_read(char * buf, size_t size)
if (signal_term)
opd_sigterm();
+ if (signal_child)
+ opd_sigchild();
+
if (signal_usr1) {
signal_usr1 = 0;
perfmon_start();
@@ -173,10 +239,17 @@ static void opd_do_read(char * buf, size_t size)
signal_usr2 = 0;
perfmon_stop();
}
+
+ if (is_jitconv_requested()) {
+ verbprintf(vmisc, "Start opjitconv was triggered\n");
+ opd_do_jitdumps();
+ }
}
opd_do_samples(buf, count);
}
+
+ opd_close_pipe();
}
@@ -204,27 +277,45 @@ static void opd_sighup(void)
static void clean_exit(void)
{
perfmon_exit();
- unlink(OP_LOCK_FILE);
+ unlink(op_lock_file);
}
static void opd_sigterm(void)
{
+ opd_do_jitdumps();
opd_print_stats();
printf("oprofiled stopped %s", op_get_time());
exit(EXIT_FAILURE);
}
-
+/* SIGCHLD received from JIT dump child process. */
+static void opd_sigchild(void)
+{
+ int child_status;
+ wait(&child_status);
+ jit_conversion_running = 0;
+ if (WIFEXITED(child_status) && (!WEXITSTATUS(child_status))) {
+ verbprintf(vmisc, "JIT dump processing complete.\n");
+ } else {
+ printf("JIT dump processing exited abnormally: %d\n",
+ WEXITSTATUS(child_status));
+ }
+
+}
+
static void opd_26_init(void)
{
size_t i;
size_t opd_buf_size;
+ unsigned long long start_time = 0ULL;
+ struct timeval tv;
opd_create_vmlinux(vmlinux, kernel_range);
+ opd_create_xen(xenimage, xen_range);
- opd_buf_size = opd_read_fs_int(OP_DRIVER_BASE"/", "buffer_size", 1);
- kernel_pointer_size = opd_read_fs_int(OP_DRIVER_BASE"/", "pointer_size", 1);
+ opd_buf_size = opd_read_fs_int("/dev/oprofile/", "buffer_size", 1);
+ kernel_pointer_size = opd_read_fs_int("/dev/oprofile/", "pointer_size", 1);
s_buf_bytesize = opd_buf_size * kernel_pointer_size;
@@ -247,13 +338,19 @@ static void opd_26_init(void)
perror("oprofiled: couldn't set exit cleanup: ");
exit(EXIT_FAILURE);
}
+
+ /* trigger kernel module setup before returning control to opcontrol */
+ opd_open_files();
+ gettimeofday(&tv, NULL);
+ start_time = 0ULL;
+ start_time = tv.tv_sec;
+ sprintf(start_time_str, "%llu", start_time);
+
}
static void opd_26_start(void)
{
- opd_open_files();
-
/* simple sleep-then-process loop */
opd_do_read(sbuf, s_buf_bytesize);
}
View
45 daemon/opd_anon.c
@@ -14,6 +14,7 @@
* @remark Read the file COPYING
*
* @author John Levon
+ * @Modifications Gisle Dankel
*/
#include "opd_anon.h"
@@ -25,21 +26,24 @@
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#define HASH_SIZE 1024
#define HASH_BITS (HASH_SIZE - 1)
-#define LRU_SIZE 1000
-#define LRU_AMOUNT (LRU_SIZE/5)
+/*
+ * Note that this value is tempered by the fact that when we miss in the
+ * anon cache, we'll tear down all the mappings for that tgid. Thus, LRU
+ * of a mapping can potentially clear out a much larger number of
+ * mappings.
+ */
+#define LRU_SIZE 8192
+#define LRU_AMOUNT (LRU_SIZE/8)
static struct list_head hashes[HASH_SIZE];
static struct list_head lru;
static size_t nr_lru;
-/* never called in buffer-processing context, so we don't need
- * to update struct transient. Note the 'U' of LRU is based on
- * parsing time, not actual use.
- */
static void do_lru(struct transient * trans)
{
size_t nr_to_kill = LRU_AMOUNT;
@@ -53,15 +57,14 @@ static void do_lru(struct transient * trans)
clear_trans_current(trans);
if (trans->last_anon == entry)
clear_trans_last(trans);
+ sfile_clear_anon(entry);
list_del(&entry->list);
list_del(&entry->lru_list);
--nr_lru;
free(entry);
if (nr_to_kill-- == 0)
break;
}
-
- sfile_clear_anon();
}
@@ -87,14 +90,14 @@ static void clear_anon_maps(struct transient * trans)
if (entry->tgid == tgid && entry->app_cookie == app) {
if (trans->last_anon == entry)
clear_trans_last(trans);
+ sfile_clear_anon(entry);
list_del(&entry->list);
list_del(&entry->lru_list);
--nr_lru;
free(entry);
}
}
- sfile_clear_anon();
if (vmisc) {
char const * name = verbose_cookie(app);
printf("Cleared anon maps for tgid %u (%s).\n", tgid, name);
@@ -103,14 +106,15 @@ static void clear_anon_maps(struct transient * trans)
static void
-add_anon_mapping(struct transient * trans, vma_t start, vma_t end)
+add_anon_mapping(struct transient * trans, vma_t start, vma_t end, char * name)
{
unsigned long hash = hash_anon(trans->tgid, trans->app_cookie);
struct anon_mapping * m = xmalloc(sizeof(struct anon_mapping));
m->tgid = trans->tgid;
m->app_cookie = trans->app_cookie;
m->start = start;
m->end = end;
+ strncpy(m->name, name, MAX_IMAGE_NAME_SIZE + 1);
list_add_tail(&m->list, &hashes[hash]);
list_add_tail(&m->lru_list, &lru);
if (++nr_lru == LRU_SIZE)
@@ -128,8 +132,7 @@ static void get_anon_maps(struct transient * trans)
{
FILE * fp = NULL;
char buf[PATH_MAX];
- unsigned long start;
- unsigned long end;
+ vma_t start, end;
int ret;
snprintf(buf, PATH_MAX, "/proc/%d/maps", trans->tgid);
@@ -138,16 +141,20 @@ static void get_anon_maps(struct transient * trans)
return;
while (fgets(buf, PATH_MAX, fp) != NULL) {
- char tmp[20];
- /* Note that this actually includes all mappings,
- * since we want stuff like [heap]
+ char tmp[MAX_IMAGE_NAME_SIZE + 1];
+ char name[MAX_IMAGE_NAME_SIZE + 1];
+ /* Some anon maps have labels like
+ * [heap], [stack], [vdso], [vsyscall] ...
+ * Keep track of these labels. If a map has no name, call it "anon".
+ * Ignore all mappings starting with "/" (file or shared memory object)
*/
- ret = sscanf(buf, "%lx-%lx %19s %19s %19s %19s %19s",
- &start, &end, tmp, tmp, tmp, tmp, tmp);
- if (ret < 6)
+ strcpy(name, "anon");
+ ret = sscanf(buf, "%llx-%llx %20s %20s %20s %20s %20s",
+ &start, &end, tmp, tmp, tmp, tmp, name);
+ if (ret < 6 || name[0] == '/')
continue;
- add_anon_mapping(trans, start, end);
+ add_anon_mapping(trans, start, end, name);
}
fclose(fp);
View
4 daemon/opd_anon.h
@@ -25,6 +25,9 @@ struct transient;
*/
#define VMA_SHIFT 13
+/* Maximum size of the image name considered */
+#define MAX_IMAGE_NAME_SIZE 20
+
struct anon_mapping {
/** start of the mapping */
vma_t start;
@@ -38,6 +41,7 @@ struct anon_mapping {
struct list_head list;
/** lru list */
struct list_head lru_list;
+ char name[MAX_IMAGE_NAME_SIZE+1];
};
/**
View
14 daemon/opd_cookie.c
@@ -60,12 +60,24 @@
#endif /* __NR_lookup_dcookie */
#if (defined(__powerpc__) && !defined(__powerpc64__)) || defined(__hppa__)\
- || (defined(__s390__) && !defined(__s390x__))
+ || (defined(__s390__) && !defined(__s390x__)) \
+ || (defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32) \
+ && defined(__MIPSEB__)) \
+ || (defined(__arm__) && defined(__ARM_EABI__) \
+ && defined(__ARMEB__))
static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
{
return syscall(__NR_lookup_dcookie, (unsigned long)(cookie >> 32),
(unsigned long)(cookie & 0xffffffff), buf, size);
}
+#elif (defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)) \
+ || (defined(__arm__) && defined(__ARM_EABI__))
+static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
+{
+ return syscall(__NR_lookup_dcookie,
+ (unsigned long)(cookie & 0xffffffff),
+ (unsigned long)(cookie >> 32), buf, size);
+}
#else
static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
{
View
5 daemon/opd_events.c
@@ -142,7 +142,8 @@ struct opd_event * find_counter_event(unsigned long counter)
void fill_header(struct opd_header * header, unsigned long counter,
vma_t anon_start, vma_t cg_to_anon_start,
- int is_kernel, int cg_to_is_kernel, time_t mtime)
+ int is_kernel, int cg_to_is_kernel,
+ int spu_samples, uint64_t embed_offset, time_t mtime)
{
struct opd_event * event = find_counter_event(counter);
@@ -158,5 +159,7 @@ void fill_header(struct opd_header * header, unsigned long counter,
header->cpu_speed = cpu_speed;
header->mtime = mtime;
header->anon_start = anon_start;
+ header->spu_profile = spu_samples;
+ header->embedded_offset = embed_offset;
header->cg_to_anon_start = cg_to_anon_start;
}
View
4 daemon/opd_events.h
@@ -13,6 +13,7 @@
#include "op_types.h"
+#include <stdint.h>
#include <time.h>
/** event description for setup (perfmon) and mangling */
@@ -40,6 +41,7 @@ struct opd_header;
/** fill the sample file header with event info etc. */
void fill_header(struct opd_header * header, unsigned long counter,
vma_t anon_start, vma_t anon_end,
- int is_kernel, int cg_to_is_kernel, time_t mtime);
+ int is_kernel, int cg_to_is_kernel,
+ int spu_samples, uint64_t embed_offset, time_t mtime);
#endif /* OPD_EVENTS_H */
View
25 daemon/opd_interface.h
@@ -8,6 +8,9 @@
*
* @author John Levon
* @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
*/
#ifndef OPD_INTERFACE_H
@@ -17,10 +20,26 @@
#define CPU_SWITCH_CODE 2
#define COOKIE_SWITCH_CODE 3
#define KERNEL_ENTER_SWITCH_CODE 4
-#define KERNEL_EXIT_SWITCH_CODE 5
-#define MODULE_LOADED_CODE 6
+#define USER_ENTER_SWITCH_CODE 5
+#define MODULE_LOADED_CODE 6
#define CTX_TGID_CODE 7
#define TRACE_BEGIN_CODE 8
-#define LAST_CODE 9
+/* Code 9 used to be TRACE_END_CODE which is not used anymore */
+/* Code 9 is now considered an unknown escape code */
+#define XEN_ENTER_SWITCH_CODE 10
+/*
+ * Ugly work-around for the unfortunate collision between Xenoprof's
+ * DOMAIN_SWITCH_CODE (in use on x86) and Cell's SPU_PROFILING_CODE
+ * (in use with Power):
+ */
+#if defined(__powerpc__)
+#define SPU_PROFILING_CODE 11
+#define SPU_CTX_SWITCH_CODE 12
+#define DOMAIN_SWITCH_CODE 13
+#define LAST_CODE 14
+#else
+#define DOMAIN_SWITCH_CODE 11
+#define LAST_CODE 12
+#endif
#endif /* OPD_INTERFACE_H */
View
41 daemon/opd_kernel.c
@@ -7,6 +7,9 @@
*
* @author John Levon
* @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
*/
#include "opd_kernel.h"
@@ -29,6 +32,8 @@ static LIST_HEAD(modules);
static struct kernel_image vmlinux_image;
+static struct kernel_image xen_image;
+
void opd_create_vmlinux(char const * name, char const * arg)
{
/* vmlinux is *not* on the list of modules */
@@ -54,6 +59,31 @@ void opd_create_vmlinux(char const * name, char const * arg)
}
}
+void opd_create_xen(char const * name, char const * arg)
+{
+ /* xen is *not* on the list of modules */
+ list_init(&xen_image.list);
+
+ /* for no xen */
+ if (no_xen) {
+ xen_image.name = "no-xen";
+ return;
+ }
+
+ xen_image.name = xstrdup(name);
+
+ sscanf(arg, "%llx,%llx", &xen_image.start, &xen_image.end);
+
+ verbprintf(vmisc, "xen_start = %llx, xen_end = %llx\n",
+ xen_image.start, xen_image.end);
+
+ if (!xen_image.start && !xen_image.end) {
+ fprintf(stderr, "error: mis-parsed xen range: %llx-%llx\n",
+ xen_image.start, xen_image.end);
+ exit(EXIT_FAILURE);
+ }
+}
+
/**
* Allocate and initialise a kernel image description
@@ -112,11 +142,11 @@ void opd_reread_module_info(void)
char * line;
struct kernel_image * image;
int module_size;
- char ref_count[32];
+ char ref_count[32+1];
int ret;
char module_name[256+1];
- char live_info[32];
- char dependencies[4096];
+ char live_info[32+1];
+ char dependencies[4096+1];
unsigned long long start_address;
if (no_vmlinux)
@@ -145,7 +175,7 @@ void opd_reread_module_info(void)
continue;
}
- ret = sscanf(line, "%256s %u %31s %4095s %31s %llx",
+ ret = sscanf(line, "%256s %u %32s %4096s %32s %llx",
module_name, &module_size, ref_count,
dependencies, live_info, &start_address);
if (ret != 6) {
@@ -192,5 +222,8 @@ struct kernel_image * find_kernel_image(struct transient const * trans)
return image;
}
+ if (xen_image.start <= trans->pc && xen_image.end > trans->pc)
+ return &xen_image;
+
return NULL;
}
View
5 daemon/opd_kernel.h
@@ -7,6 +7,9 @@
*
* @author John Levon
* @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
*/
#ifndef OPD_KERNEL_H
@@ -20,6 +23,8 @@ struct transient;
/** create the kernel image */
void opd_create_vmlinux(char const * name, char const * arg);
+void opd_create_xen(char const * name, char const * arg);
+
/** opd_reread_module_info - parse /proc/modules for kernel modules */
void opd_reread_module_info(void);
View
13 daemon/opd_mangling.c
@@ -57,8 +57,10 @@ static char const * get_dep_name(struct sfile const * sf)
static char * mangle_anon(struct anon_mapping const * anon)
{
char * name = xmalloc(PATH_MAX);
+
snprintf(name, 1024, "%u.0x%llx.0x%llx", (unsigned int)anon->tgid,
- anon->start, anon->end);
+ anon->start, anon->end);
+
return name;
}
@@ -78,6 +80,7 @@ mangle_filename(struct sfile * last, struct sfile const * sf, int counter, int c
} else if (sf->anon) {
values.flags |= MANGLE_ANON;
values.image_name = mangle_anon(sf->anon);
+ values.anon_name = sf->anon->name;
} else {
values.image_name = find_cookie(sf->cookie);
}
@@ -108,6 +111,7 @@ mangle_filename(struct sfile * last, struct sfile const * sf, int counter, int c
} else if (last->anon) {
values.flags |= MANGLE_CG_ANON;
values.cg_image_name = mangle_anon(last->anon);
+ values.anon_name = last->anon->name;
} else {
values.cg_image_name = find_cookie(last->cookie);
}
@@ -139,6 +143,7 @@ int opd_open_sample_file(odb_t * file, struct sfile * last,
{
char * mangled;
char const * binary;
+ int spu_profile = 0;
vma_t last_start = 0;
int err;
@@ -182,10 +187,14 @@ int opd_open_sample_file(odb_t * file, struct sfile * last,
if (last && last->anon)
last_start = last->anon->start;
+ if (sf->embedded_offset != UNUSED_EMBEDDED_OFFSET)
+ spu_profile = 1;
+
fill_header(odb_get_data(file), counter,
sf->anon ? sf->anon->start : 0, last_start,
!!sf->kernel, last ? !!last->kernel : 0,
- binary ? op_get_mtime(binary) : 0);
+ spu_profile, sf->embedded_offset,
+ binary ? op_get_mtime(binary) : 0);
out:
sfile_put(sf);
View
32 daemon/opd_perfmon.c
@@ -380,6 +380,7 @@ static void wait_for_child(struct child * child)
close(child->up_pipe[1]);
}
+static struct child* xen_ctx;
void perfmon_init(void)
{
@@ -389,6 +390,24 @@ void perfmon_init(void)
if (cpu_type == CPU_TIMER_INT)
return;
+ if (!no_xen) {
+ xen_ctx = xmalloc(sizeof(struct child));
+ xen_ctx->pid = getpid();
+ xen_ctx->up_pipe[0] = -1;
+ xen_ctx->up_pipe[1] = -1;
+ xen_ctx->sigusr1 = 0;
+ xen_ctx->sigusr2 = 0;
+ xen_ctx->sigterm = 0;
+
+ create_context(xen_ctx);
+
+ write_pmu(xen_ctx);
+
+ load_context(xen_ctx);
+ return;
+ }
+
+
nr = sysconf(_SC_NPROCESSORS_ONLN);
if (nr == -1) {
fprintf(stderr, "Couldn't determine number of CPUs.\n");
@@ -431,6 +450,9 @@ void perfmon_exit(void)
if (cpu_type == CPU_TIMER_INT)
return;
+ if (!no_xen)
+ return;
+
for (i = 0; i < nr_cpus; ++i) {
kill(children[i].pid, SIGKILL);
waitpid(children[i].pid, NULL, 0);
@@ -445,6 +467,11 @@ void perfmon_start(void)
if (cpu_type == CPU_TIMER_INT)
return;
+ if (!no_xen) {
+ perfmon_start_child(xen_ctx->ctx_fd);
+ return;
+ }
+
for (i = 0; i < nr_cpus; ++i)
kill(children[i].pid, SIGUSR1);
}
@@ -457,6 +484,11 @@ void perfmon_stop(void)
if (cpu_type == CPU_TIMER_INT)
return;
+ if (!no_xen) {
+ perfmon_stop_child(xen_ctx->ctx_fd);
+ return;
+ }
+
for (i = 0; i < nr_cpus; ++i)
kill(children[i].pid, SIGUSR2);
}
View
96 daemon/opd_pipe.c
@@ -0,0 +1,96 @@
+/**
+ * @file daemon/opd_pipe.c
+ * Functions handling the $SESSIONDIR/opd_pipe FIFO special file.
+ * NOTE: This code is dealing with potentially insecure input.
+ *
+ * @remark Copyright 2008 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Daniel Hansel
+ */
+
+#include "opd_pipe.h"
+#include "opd_printf.h"
+#include "op_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+static int fifo;
+
+void opd_create_pipe(void)
+{
+ mode_t orig_umask = umask(0111);
+ if (mkfifo(op_pipe_file, 0666) == -1) {
+ if (errno != EEXIST) {
+ perror("oprofiled: couldn't create pipe: ");
+ exit(EXIT_FAILURE);
+ }
+ }
+ umask(orig_umask);
+}
+
+
+void opd_open_pipe(void)
+{
+ fifo = open(op_pipe_file, O_RDONLY | O_NONBLOCK);
+ if (fifo == -1) {
+ perror("oprofiled: couldn't open pipe: ");
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+void opd_close_pipe(void)
+{
+ close(fifo);
+}
+
+
+int is_jitconv_requested(void)
+{
+ /* number of dropped (unknown) requests */
+ static long nr_drops = 0;
+ /* modulus to output only a few warnings to avoid flooding oprofiled.log */
+ static int mod_cnt_drops = 1;
+ FILE * fd;
+ char line[256];
+ int i, ret = 0;
+
+ /* get a file descriptor to the pipe */
+ fd = fdopen(fifo, "r");
+
+ if (fd == NULL) {
+ perror("oprofiled: couldn't create file descriptor: ");
+ exit(EXIT_FAILURE);
+ }
+
+ /* read up to 99 lines to check for 'do_jitconv' */
+ for (i = 0; i < 99; i++) {
+ /* just break if no new line is found */
+ if (fgets(line, 256, fd) == NULL)
+ break;
+ line[strlen(line) - 1] = '\0';
+
+ if (strstr(line, "do_jitconv") != NULL) {
+ ret = 1;
+ } else {
+ nr_drops++;
+
+ if (nr_drops % mod_cnt_drops == 0) {
+ printf(
+ "Warning: invalid pipe request received (dropped request(s): %ld)\n",
+ nr_drops);
+ /* increase modulus to avoid flooding log file */
+ mod_cnt_drops *= 5;
+ }
+ }
+ }
+
+ return ret;
+}
View
45 daemon/opd_pipe.h
@@ -0,0 +1,45 @@
+/**
+ * @file daemon/opd_pipe.h
+ * Functions handling the $SESSIONDIR/opd_pipe FIFO special file.
+ * NOTE: This code is dealing with potencially insecure input.
+ *
+ * @remark Copyright 2008 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Daniel Hansel
+ */
+
+#ifndef OPD_PIPE_H_
+#define OPD_PIPE_H_
+
+/**
+ * opd_create_pipe - creates the oprofiled fifo file
+ *
+ * Creates the Oprofile daemon fifo pipe to enable communication between
+ * the daemon and the 'opcontrol --dump' command. Failure to create the pipe
+ * is a fatal error.
+ */
+void opd_create_pipe(void);
+
+/**
+ * opd_open_pipe - opens the oprofiled fifo file
+ */
+void opd_open_pipe(void);
+
+/**
+ * opd_close_pipe - closes the oprofiled fifo file
+ *
+ * Closes the Oprofile daemon fifo pipe.
+ */
+void opd_close_pipe(void);
+
+/**
+ * is_jitconv_requested - check for request to jit conversion
+ *
+ * Checks the Oprofile daemon fifo pipe for do_jitconv request.
+ * If jit conversion is requested ('do_jitconv' is sent) the check returns 1.
+ * Otherwise it returns 0.
+ */
+int is_jitconv_requested(void);
+
+#endif /*OPD_PIPE_H_*/
View
49 daemon/opd_sfile.c
@@ -199,6 +199,14 @@ create_sfile(unsigned long hash, struct transient const * trans,
sf->ignored = is_sf_ignored(sf);
+ sf->embedded_offset = trans->embedded_offset;
+
+ /* If embedded_offset is a valid value, it means we're
+ * processing a Cell BE SPU profile; in which case, we
+ * want sf->app_cookie to hold trans->app_cookie.
+ */
+ if (trans->embedded_offset != UNUSED_EMBEDDED_OFFSET)
+ sf->app_cookie = trans->app_cookie;
return sf;
}
@@ -399,7 +407,7 @@ static void sfile_log_arc(struct transient const * trans)
key = to & (0xffffffff);
key |= ((uint64_t)from) << 32;
- err = odb_insert(file, key, 1);
+ err = odb_update_node(file, key);
if (err) {
fprintf(stderr, "%s: %s\n", __FUNCTION__, strerror(err));
abort();
@@ -438,15 +446,15 @@ void sfile_log_sample(struct transient const * trans)
return;
}
- err = odb_insert(file, (uint64_t)pc, 1);
+ err = odb_update_node(file, (uint64_t)pc);
if (err) {
fprintf(stderr, "%s: %s\n", __FUNCTION__, strerror(err));
abort();
}
}
-static int close_sfile(struct sfile * sf)
+static int close_sfile(struct sfile * sf, void * data __attribute__((unused)))
{
size_t i;
@@ -460,13 +468,13 @@ static int close_sfile(struct sfile * sf)
static void kill_sfile(struct sfile * sf)
{
- close_sfile(sf);
+ close_sfile(sf, NULL);
list_del(&sf->hash);
list_del(&sf->lru);
}
-static int sync_sfile(struct sfile * sf)
+static int sync_sfile(struct sfile * sf, void * data __attribute__((unused)))
{
size_t i;
@@ -477,30 +485,33 @@ static int sync_sfile(struct sfile * sf)
}
-static int is_sfile_kernel(struct sfile * sf)
+static int is_sfile_kernel(struct sfile * sf, void * data __attribute__((unused)))
{
return !!sf->kernel;
}
-static int is_sfile_anon(struct sfile * sf)
+static int is_sfile_anon(struct sfile * sf, void * data)
{
- return !!sf->anon;
+ return sf->anon == data;
}
-static void for_one_sfile(struct sfile * sf, int (*func)(struct sfile *))
+typedef int (*sfile_func)(struct sfile *, void *);
+
+static void
+for_one_sfile(struct sfile * sf, sfile_func func, void * data)
{
size_t i;
- int free_sf = func(sf);
+ int free_sf = func(sf, data);
for (i = 0; i < CG_HASH_SIZE; ++i) {
struct list_head * pos;
struct list_head * pos2;
list_for_each_safe(pos, pos2, &sf->cg_hash[i]) {
struct cg_entry * cg =
list_entry(pos, struct cg_entry, hash);
- if (free_sf || func(&cg->to)) {
+ if (free_sf || func(&cg->to, data)) {
kill_sfile(&cg->to);
list_del(&cg->hash);
free(cg);
@@ -515,39 +526,39 @@ static void for_one_sfile(struct sfile * sf, int (*func)(struct sfile *))
}
-static void for_each_sfile(int (*func)(struct sfile *))
+static void for_each_sfile(sfile_func func, void * data)
{
struct list_head * pos;
struct list_head * pos2;
list_for_each_safe(pos, pos2, &lru_list) {
struct sfile * sf = list_entry(pos, struct sfile, lru);
- for_one_sfile(sf, func);
+ for_one_sfile(sf, func, data);
}
}
void sfile_clear_kernel(void)
{
- for_each_sfile(is_sfile_kernel);
+ for_each_sfile(is_sfile_kernel, NULL);
}
-void sfile_clear_anon(void)
+void sfile_clear_anon(struct anon_mapping * anon)
{
- for_each_sfile(is_sfile_anon);
+ for_each_sfile(is_sfile_anon, anon);
}
void sfile_sync_files(void)
{
- for_each_sfile(sync_sfile);
+ for_each_sfile(sync_sfile, NULL);
}
void sfile_close_files(void)
{
- for_each_sfile(close_sfile);
+ for_each_sfile(close_sfile, NULL);
}
@@ -578,7 +589,7 @@ int sfile_lru_clear(void)
if (!--amount)
break;
sf = list_entry(pos, struct sfile, lru);
- for_one_sfile(sf, (int (*)(struct sfile *))always_true);
+ for_one_sfile(sf, (sfile_func)always_true, NULL);
}
return 0;
View
9 daemon/opd_sfile.h
@@ -25,6 +25,7 @@ struct kernel_image;
struct transient;
#define CG_HASH_SIZE 16
+#define UNUSED_EMBEDDED_OFFSET ~0LLU
/**
* Each set of sample files (where a set is over the physical counter
@@ -50,6 +51,8 @@ struct sfile {
struct kernel_image * kernel;
/** anonymous mapping */
struct anon_mapping * anon;
+ /** embedded offset for Cell BE SPU */
+ uint64_t embedded_offset;
/** hash table link */
struct list_head hash;
@@ -74,8 +77,10 @@ struct cg_entry {
/** clear any sfiles that are for the kernel */
void sfile_clear_kernel(void);
-/** clear any sfiles that are for anon mappings */
-void sfile_clear_anon(void);
+struct anon_mapping;
+
+/** clear any sfiles for the given anon mapping */
+void sfile_clear_anon(struct anon_mapping *);
/** sync sample files */
void sfile_sync_files(void);
View
176 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);
+ }
+}
View
16 daemon/opd_stats.c
@@ -9,12 +9,10 @@
* @author Philippe Elie
*/
-#include "config.h"
#include "opd_stats.h"
#include "oprofiled.h"
#include "op_get_time.h"
-#include "op_config.h"
#include <dirent.h>
#include <stdlib.h>
@@ -53,22 +51,22 @@ void opd_print_stats(void)
printf("Nr. samples lost due to no permanent mapping: %lu\n",
opd_stats[OPD_LOST_NO_MAPPING]);
print_if("Nr. event lost due to buffer overflow: %u\n",
- OP_DRIVER_BASE"/stats", "event_lost_overflow", 1);
+ "/dev/oprofile/stats", "event_lost_overflow", 1);
print_if("Nr. samples lost due to no mapping: %u\n",
- OP_DRIVER_BASE"/stats", "sample_lost_no_mapping", 1);
+ "/dev/oprofile/stats", "sample_lost_no_mapping", 1);
print_if("Nr. backtraces skipped due to no file mapping: %u\n",
- OP_DRIVER_BASE"/stats", "bt_lost_no_mapping", 0);
+ "/dev/oprofile/stats", "bt_lost_no_mapping", 0);
print_if("Nr. samples lost due to no mm: %u\n",
- OP_DRIVER_BASE"/stats", "sample_lost_no_mm", 1);
+ "/dev/oprofile/stats", "sample_lost_no_mm", 1);
- if (!(dir = opendir(OP_DRIVER_BASE"/stats/")))
+ if (!(dir = opendir("/dev/oprofile/stats/")))
goto out;
while ((dirent = readdir(dir))) {
int cpu_nr;
char path[256];
if (sscanf(dirent->d_name, "cpu%d", &cpu_nr) != 1)
continue;
- snprintf(path, 256, OP_DRIVER_BASE"/stats/%s", dirent->d_name);
+ snprintf(path, 256, "/dev/oprofile/stats/%s", dirent->d_name);
print_if("Nr. samples lost cpu buffer overflow: %u\n",
path, "sample_lost_overflow", 1);
@@ -78,6 +76,8 @@ void opd_print_stats(void)
path, "sample_received", 1);
print_if("Nr. backtrace aborted: %u\n",
path, "backtrace_aborted", 0);
+ print_if("Nr. samples lost invalid pc: %u\n",
+ path, "sample_invalid_eip", 0);
}
closedir(dir);
out:
View
72 daemon/opd_trans.c
@@ -7,6 +7,13 @@
*
* @author John Levon
* @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
+ *
+ * Modified by Maynard Johnson <maynardj@us.ibm.com>
+ * These modifications are:
+ * (C) Copyright IBM Corporation 2007
*/
#include "opd_trans.h"
@@ -41,21 +48,7 @@ void clear_trans_current(struct transient * trans)
}
-void update_trans_last(struct transient * trans)
-{
- trans->last = trans->current;
- trans->last_anon = trans->anon;
- trans->last_pc = trans->pc;
-}
-
-
-static inline int is_escape_code(uint64_t code)
-{
- return kernel_pointer_size == 4 ? code == ~0LU : code == ~0LLU;
-}
-
-
-static uint64_t pop_buffer_value(struct transient * trans)
+uint64_t pop_buffer_value(struct transient * trans)
{
uint64_t val;
@@ -78,7 +71,7 @@ static uint64_t pop_buffer_value(struct transient * trans)
}
-static int enough_remaining(struct transient * trans, size_t size)
+int enough_remaining(struct transient * trans, size_t size)
{
if (trans->remaining >= size)
return 1;
@@ -219,9 +212,9 @@ static void code_kernel_enter(struct transient * trans)
}
-static void code_kernel_exit(struct transient * trans)
+static void code_user_enter(struct transient * trans)
{
- verbprintf(vmisc, "KERNEL_EXIT_SWITCH to user-space\n");
+ verbprintf(vmisc, "USER_ENTER_SWITCH to user-space\n");
trans->in_kernel = 0;
clear_trans_current(trans);
clear_trans_last(trans);
@@ -248,22 +241,44 @@ static void code_trace_begin(struct transient * trans)
trans->tracing = TRACING_START;
}
+static void code_xen_enter(struct transient * trans)
+{
+ verbprintf(vmisc, "XEN_ENTER_SWITCH to xen\n");
+ trans->in_kernel = 1;
+ trans->current = NULL;
+ /* subtlety: we must keep trans->cookie cached, even though it's
+ * meaningless for Xen - we won't necessarily get a cookie switch
+ * on Xen exit. See comments in opd_sfile.c. It seems that we can
+ * get away with in_kernel = 1 as long as we supply the correct
+ * Xen image, and its address range in startup find_kernel_image
+ * is modified to look in the Xen image also
+ */
+}
-typedef void (*handler_t)(struct transient *);
+extern void code_spu_profiling(struct transient * trans);
+extern void code_spu_ctx_switch(struct transient * trans);
-static handler_t handlers[LAST_CODE + 1] = {
+handler_t handlers[LAST_CODE + 1] = {
&code_unknown,
&code_ctx_switch,
&code_cpu_switch,
&code_cookie_switch,
&code_kernel_enter,
- &code_kernel_exit,
+ &code_user_enter,
&code_module_loaded,
/* tgid handled differently */
&code_unknown,
&code_trace_begin,
+ &code_unknown,
+ &code_xen_enter,
+#if defined(__powerpc__)
+ &code_spu_profiling,
+ &code_spu_ctx_switch,
+#endif
+ &code_unknown,
};
+extern void (*special_processor)(struct transient *);
void opd_process_samples(char const * buffer, size_t count)
{
@@ -283,6 +298,7 @@ void opd_process_samples(char const * buffer, size_t count)
.in_kernel = -1,
.cpu = -1,
.tid = -1,
+ .embedded_offset = UNUSED_EMBEDDED_OFFSET,
.tgid = -1
};
@@ -292,9 +308,22 @@ void opd_process_samples(char const * buffer, size_t count)
*/
unsigned long long code;
+ if (special_processor) {
+ special_processor(&trans);
+ return;
+ }
+
+ int i;
+
+ for (i = 0; i < count && i < 200; i++) {
+ verbprintf(vmisc, "buffer[%d] is %x\n", i, buffer[i]);
+ }
+
while (trans.remaining) {
code = pop_buffer_value(&trans);
+ verbprintf(vmisc, "In opd_process_samples (code is %lld)\n", code);
+
if (!is_escape_code(code)) {
opd_put_sample(&trans, code);
continue;
@@ -309,6 +338,7 @@ void opd_process_samples(char const * buffer, size_t count)
// started with ESCAPE_CODE, next is type
code = pop_buffer_value(&trans);
+ verbprintf(vmisc, "next code is %lld\n", code);
if (code >= LAST_CODE) {
fprintf(stderr, "Unknown code %llu\n", code);
abort();
View
25 daemon/opd_trans.h
@@ -7,6 +7,10 @@
*
* @author John Levon
* @author Philippe Elie
+ *
+ * Modified by Maynard Johnson <maynardj@us.ibm.com>
+ * These modifications are:
+ * (C) Copyright IBM Corporation 2007
*/
#ifndef OPD_TRANS_H
@@ -15,6 +19,8 @@
#include "opd_cookie.h"
#include "op_types.h"
+#include <stdint.h>
+
struct sfile;
struct anon_mapping;
@@ -47,8 +53,27 @@ struct transient {
unsigned long cpu;
pid_t tid;
pid_t tgid;
+ uint64_t embedded_offset;
};
+typedef void (*handler_t)(struct transient *);
+extern handler_t handlers[];
+
+uint64_t pop_buffer_value(struct transient * trans);
+int enough_remaining(struct transient * trans, size_t size);
+static inline void update_trans_last(struct transient * trans)
+{
+ trans->last = trans->current;
+ trans->last_anon = trans->anon;
+ trans->last_pc = trans->pc;
+}
+
+extern size_t kernel_pointer_size;
+static inline int is_escape_code(uint64_t code)
+{
+ return kernel_pointer_size == 4 ? code == ~0LU : code == ~0LLU;
+}
+
void opd_process_samples(char const * buffer, size_t count);
/** used when we need to clear data that's been freed */
View
78 daemon/oprofiled.c
@@ -7,6 +7,9 @@
*
* @author John Levon
* @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
*/
#include "config.h"
@@ -43,6 +46,7 @@
sig_atomic_t signal_alarm;
sig_atomic_t signal_hup;
sig_atomic_t signal_term;
+sig_atomic_t signal_child;
sig_atomic_t signal_usr1;
sig_atomic_t signal_usr2;
@@ -60,6 +64,10 @@ int separate_cpu;
int no_vmlinux;
char * vmlinux;
char * kernel_range;
+char * session_dir;
+int no_xen;
+char * xenimage;
+char * xen_range;
static char * verbose;
static char * binary_name_filter;
static char * events;
@@ -72,9 +80,12 @@ extern struct oprofiled_ops opd_26_ops;
static struct list_head images_filter[OPD_IMAGE_FILTER_HASH_SIZE];
static struct poptOption options[] = {
+ { "session-dir", 0, POPT_ARG_STRING, &session_dir, 0, "place sample database in dir instead of default location", "/var/lib/oprofile", },
{ "kernel-range", 'r', POPT_ARG_STRING, &kernel_range, 0, "Kernel VMA range", "start-end", },
{ "vmlinux", 'k', POPT_ARG_STRING, &vmlinux, 0, "vmlinux kernel image", "file", },
{ "no-vmlinux", 0, POPT_ARG_NONE, &no_vmlinux, 0, "vmlinux kernel image file not available", NULL, },
+ { "xen-range", 0, POPT_ARG_STRING, &xen_range, 0, "Xen VMA range", "start-end", },
+ { "xen-image", 0, POPT_ARG_STRING, &xenimage, 0, "Xen image", "file", },
{ "image", 0, POPT_ARG_STRING, &binary_name_filter, 0, "image name filter", "profile these comma separated image" },
{ "separate-lib", 0, POPT_ARG_INT, &separate_lib, 0, "separate library samples for each distinct application", "[0|1]", },
{ "separate-kernel", 0, POPT_ARG_INT, &separate_kernel, 0, "separate kernel samples for each distinct application", "[0|1]", },
@@ -90,7 +101,7 @@ static struct poptOption options[] = {
void opd_open_logfile(void)
{
- if (open(OP_LOG_FILE, O_WRONLY|O_CREAT|O_NOCTTY|O_APPEND, 0755) == -1) {
+ if (open(op_log_file, O_WRONLY|O_CREAT|O_NOCTTY|O_APPEND, 0644) == -1) {
perror("oprofiled: couldn't re-open stdout: ");
exit(EXIT_FAILURE);
}
@@ -129,9 +140,9 @@ static void opd_go_daemon(void)
{
opd_fork();
- if (chdir(OP_BASE_DIR)) {
- fprintf(stderr, "oprofiled: opd_go_daemon: couldn't chdir to "
- OP_BASE_DIR ": %s", strerror(errno));
+ if (chdir(op_session_dir)) {
+ fprintf(stderr, "oprofiled: opd_go_daemon: couldn't chdir to %s: %s",
+ op_session_dir, strerror(errno));
exit(EXIT_FAILURE);
}
@@ -146,15 +157,13 @@ static void opd_go_daemon(void)
static void opd_write_abi(void)
{
-#ifdef OPROF_ABI
char * cbuf;
- cbuf = xmalloc(strlen(OP_BASE_DIR) + 5);
- strcpy(cbuf, OP_BASE_DIR);
+ cbuf = xmalloc(strlen(op_session_dir) + 5);
+ strcpy(cbuf, op_session_dir);
strcat(cbuf, "/abi");
op_write_abi_to_file(cbuf);
free(cbuf);
-#endif
}
@@ -178,6 +187,11 @@ static void opd_sigterm(int val __attribute__((unused)))
{
signal_term = 1;
}
+
+static void opd_sigchild(int val __attribute__((unused)))
+{
+ signal_child = 1;
+}
static void opd_sigusr1(int val __attribute__((unused)))
@@ -225,6 +239,16 @@ static void opd_setup_signals(void)
exit(EXIT_FAILURE);
}
+ act.sa_handler = opd_sigchild;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask, SIGCHLD);
+
+ if (sigaction(SIGCHLD, &act, NULL)) {
+ perror("oprofiled: install of SIGCHLD handler failed: ");
+ exit(EXIT_FAILURE);
+ }
+
act.sa_handler = opd_sigusr1;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
@@ -241,7 +265,7 @@ static void opd_setup_signals(void)
sigaddset(&act.sa_mask, SIGTERM);
if (sigaction(SIGUSR2, &act, NULL)) {
- perror("oprofiled: install of SIGUSR1 handler failed: ");
+ perror("oprofiled: install of SIGUSR2 handler failed: ");
exit(EXIT_FAILURE);
}
}
@@ -407,7 +431,26 @@ static void opd_options(int argc, char const * argv[])
poptPrintHelp(optcon, stderr, 0);
exit(EXIT_FAILURE);
}
-
+
+ if (!xenimage || !strcmp("", xenimage)) {
+ no_xen = 1;
+ } else {
+ no_xen = 0;
+
+ /* canonicalise xen image filename. */
+ tmp = xmalloc(PATH_MAX);
+ if (realpath(xenimage, tmp))
+ xenimage = tmp;
+ else
+ free(tmp);
+
+ if (!xen_range || !strcmp("", xen_range)) {
+ fprintf(stderr, "oprofiled: no Xen VMA range specified.\n");
+ poptPrintHelp(optcon, stderr, 0);
+ exit(EXIT_FAILURE);
+ }
+ }
+
opd_parse_events(events);
opd_parse_image_filter();
@@ -422,10 +465,11 @@ static void opd_options(int argc, char const * argv[])
static struct oprofiled_ops * get_ops(void)
{
switch (op_get_interface()) {
+#ifndef ANDROID
case OP_INTERFACE_24:
printf("Using 2.4 OProfile kernel interface.\n");
- //return &opd_24_ops;
- return 0; // android. we should never need that.
+ return &opd_24_ops;
+#endif
case OP_INTERFACE_26:
printf("Using 2.6+ OProfile kernel interface.\n");
return &opd_26_ops;
@@ -445,13 +489,13 @@ int main(int argc, char const * argv[])
struct rlimit rlim = { 2048, 2048 };
opd_options(argc, argv);
+ init_op_config_dirs(session_dir);
opd_setup_signals();
err = setrlimit(RLIMIT_NOFILE, &rlim);
- if (err) {
+ if (err)
perror("warning: could not set RLIMIT_NOFILE to 2048: ");
- }
opd_write_abi();
@@ -464,9 +508,9 @@ int main(int argc, char const * argv[])
/* clean up every 10 minutes */
alarm(60 * 10);
- if (op_write_lock_file(OP_LOCK_FILE)) {
- fprintf(stderr, "oprofiled: could not create lock file "
- OP_LOCK_FILE "\n");
+ if (op_write_lock_file(op_lock_file)) {
+ fprintf(stderr, "oprofiled: could not create lock file %s\n",
+ op_lock_file);
exit(EXIT_FAILURE);
}
View
7 daemon/oprofiled.h
@@ -7,6 +7,9 @@
*
* @author John Levon
* @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
*/
#ifndef OPROFILED_H
@@ -47,6 +50,7 @@ int opd_read_fs_int(char const * path, char const * name, int is_fatal);
extern sig_atomic_t signal_alarm;
extern sig_atomic_t signal_hup;
extern sig_atomic_t signal_term;
+extern sig_atomic_t signal_child;
extern sig_atomic_t signal_usr1;
extern sig_atomic_t signal_usr2;
@@ -58,5 +62,8 @@ extern int separate_cpu;
extern int no_vmlinux;
extern char * vmlinux;
extern char * kernel_range;
+extern int no_xen;
+extern char * xenimage;
+extern char * xen_range;
#endif /* OPROFILED_H */
View
4 libabic/Android.mk → libabi/Android.mk
@@ -1,9 +1,9 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= op_abi.cpp
+LOCAL_SRC_FILES:= op_abi.c
-LOCAL_MODULE := libabic
+LOCAL_MODULE := libabi
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/.. \
View
75 libabi/abi.cpp
@@ -0,0 +1,75 @@
+/**
+ * @file abi.cpp
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ * @author John Levon
+ * @author Philippe Elie
+ */
+
+#include "abi.h"
+#include "op_abi.h"
+#include "odb.h"
+#include "op_sample_file.h"
+
+#include <iostream>
+#include <cassert>
+
+using namespace std;
+
+typedef map<string, int> abi_map;
+typedef abi_map::const_iterator abi_iter;
+
+abi_exception::abi_exception(string const d) : desc(d) {}
+
+
+abi::abi()
+{
+ op_abi_entry const * entry = get_abi();
+ for ( ; entry->name != 0; ++entry)
+ slots[entry->name] = entry->offset;
+
+ slots["little_endian"] = op_little_endian();
+}
+
+
+int abi::need(string const key) const throw (abi_exception)
+{
+ if (slots.find(key) != slots.end())
+ return slots.find(key)->second;
+ else
+ throw abi_exception(string("missing ABI key: ") + key);
+}
+
+
+bool abi::operator==(abi const & other) const
+{
+ return slots == other.slots;
+}
+
+
+ostream & operator<<(ostream & o, abi const & abi)
+{
+ abi_iter i = abi.slots.begin();
+ abi_iter e = abi.slots.end();
+
+ for (; i != e; ++i)
+ o << i->first << " " << i->second << endl;
+
+ return o;
+}
+
+
+istream & operator>>(istream & i, abi & abi)
+{
+ string key;
+ int val;
+ abi.slots.clear();
+
+ while(i >> key >> val)
+ abi.slots[key] = val;
+
+ return i;
+}
View
42 libabi/abi.h
@@ -0,0 +1,42 @@
+/**
+ * @file abi.h
+ *
+ * Contains internal ABI management class
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ */
+
+#ifndef OPROF_ABI_H
+#define OPROF_ABI_H
+
+#include <string>
+#include <map>
+#include <iosfwd>
+
+struct abi_exception : std::exception {
+ std::string const desc;
+
+ explicit abi_exception(std::string const d);
+
+ ~abi_exception() throw() {}
+};
+
+
+class abi {
+public:
+ abi();
+
+ int need(std::string const key) const throw (abi_exception);
+
+ bool operator==(abi const & other) const;
+ friend std::ostream & operator<<(std::ostream & o, abi const & abi);
+ friend std::istream & operator>>(std::istream & i, abi & abi);
+
+private:
+ std::map<std::string, int> slots;
+};
+
+#endif // OPROF_ABI_H
View
94 libabi/op_abi.c
@@ -0,0 +1,94 @@
+/**
+ * @file op_abi.c
+ * This file contains a simple C interface to the ABI-describing functionality,
+ * the majority of which is implemented in C++. This is the file which is
+ * intended for use in files outside the /libabi directory.
+ *
+ * @remark Copyright 2002, 2005 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ * @author Philippe Elie
+ */
+
+#include "op_abi.h"
+#include "odb.h"
+#include "op_sample_file.h"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <assert.h>
+
+static struct op_abi_entry const abi_entries[] = {
+ { "sizeof_double", sizeof(double) },
+ { "sizeof_time_t", sizeof(time_t) },
+ { "sizeof_u8", sizeof(u8) },
+ { "sizeof_u32", sizeof(u32) },
+ { "sizeof_int", sizeof(int) },
+ { "sizeof_unsigned_int", sizeof(unsigned int) },
+ { "sizeof_odb_key_t", sizeof(odb_key_t) },
+ { "sizeof_odb_index_t", sizeof(odb_index_t) },
+ { "sizeof_odb_value_t", sizeof(odb_value_t) },
+ { "sizeof_odb_node_nr_t", sizeof(odb_node_nr_t) },
+ { "sizeof_odb_descr_t", sizeof(odb_descr_t) },
+ { "sizeof_odb_node_t", sizeof(odb_node_t) },
+ { "sizeof_struct_opd_header", sizeof(struct opd_header) },
+
+ { "offsetof_node_key", offsetof(odb_node_t, key) },
+ { "offsetof_node_value", offsetof(odb_node_t, value) },
+ { "offsetof_node_next", offsetof(odb_node_t, next) },
+
+ { "offsetof_descr_size", offsetof(odb_descr_t, size) },
+ { "offsetof_descr_current_size", offsetof(odb_descr_t, current_size) },
+
+ { "offsetof_header_magic", offsetof(struct opd_header, magic) },
+ { "offsetof_header_version", offsetof(struct opd_header, version) },
+ { "offsetof_header_cpu_type", offsetof(struct opd_header, cpu_type) },
+ { "offsetof_header_ctr_event", offsetof(struct opd_header, ctr_event) },
+ { "offsetof_header_ctr_um", offsetof(struct opd_header, ctr_um) },
+ { "offsetof_header_ctr_count", offsetof(struct opd_header, ctr_count) },
+ { "offsetof_header_is_kernel", offsetof(struct opd_header, is_kernel) },
+ { "offsetof_header_cpu_speed", offsetof(struct opd_header, cpu_speed) },
+ { "offsetof_header_mtime", offsetof(struct opd_header, mtime) },
+ { "offsetof_header_cg_to_is_kernel", offsetof(struct opd_header, cg_to_is_kernel), },
+ { "offsetof_header_anon_start", offsetof(struct opd_header, anon_start) },
+ { "offsetof_header_cg_to_anon_start", offsetof(struct opd_header, cg_to_anon_start) },
+
+ { NULL, 0 },
+};
+
+
+struct op_abi_entry const * get_abi(void)
+{
+ return abi_entries;
+}
+
+
+int op_little_endian(void)
+{
+ unsigned int probe = 0xff;
+ size_t sz = sizeof(unsigned int);
+ unsigned char * probe_byte = (unsigned char *)&probe;
+
+ assert(probe_byte[0] == 0xff || probe_byte[sz - 1] == 0xff);
+
+ return probe_byte[0] == 0xff;
+}
+
+
+int op_write_abi_to_file(char const * abi_file)
+{
+ FILE * fp;
+ struct op_abi_entry const * abi_entry;
+
+ if ((fp = fopen(abi_file, "w")) == NULL)
+ return 0;
+
+ for (abi_entry = get_abi() ; abi_entry->name != NULL; ++abi_entry)
+ fprintf(fp, "%s %u\n", abi_entry->name, abi_entry->offset);
+ fprintf(fp, "little_endian %d\n", op_little_endian());
+
+ fclose(fp);
+
+ return 1;
+}
View
13 libabic/op_abi.h → libabi/op_abi.h
@@ -8,15 +8,28 @@
* @remark Read the file COPYING
*
* @author Graydon Hoare
+ * @author Philippe Elie
*/
#ifndef OP_ABI_H
#define OP_ABI_H
+struct op_abi_entry {
+ char const * name;
+ /// offset or size of the named entry
+ int offset;
+};
+
#ifdef __cplusplus
extern "C" {
#endif
+/// return array is terminated by a NULL entry in name field
+struct op_abi_entry const * get_abi(void);
+
+/// return non zero if the abi is little endian
+int op_little_endian(void);
+
/**
* Write current abi to file.
* return 1 on success, 0 on failure
View
225 libabi/opimport.cpp
@@ -0,0 +1,225 @@
+/**
+ * @file opimport.cpp
+ * Import sample files from other ABI
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ */
+
+#include "abi.h"
+#include "odb.h"
+#include "popt_options.h"
+#include "op_sample_file.h"
+
+#include <fstream>
+#include <iostream>
+#include <vector>