/*
 * Agent library to collect jit code for the perf tool
 * 
 *
 *
 */

#include <stdio.h>
#include "/home/carll/JAVA_INCLUDES/include/jvmti.h"
#include "perf-jit-support.h"
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/prctl.h>
#include <fcntl.h>
#include <pthread.h>


#define TRUE  1
#define FALSE 0

/* This call back library is still under development.  The library inserts
 * a remap request after pr_count symbols have loaded.  This is just to force
 * remap requests to be sent to test the remapping in the perf code.
 *
 * This code will be updated to only send the remap request when the mapping
 * has changed to reuse an address range.  As long as new symbols do not use
 * an address range for a previously loaded and unloaded method no remap is 
 * required.  
 * 
 * This library is being submitted as is for the moment to show how the remap
 * requests are sent to perf.
 */

static int debug = TRUE;
static int symbol_count = 0, pr_count = 1;
static pthread_mutex_t perf_mutex = PTHREAD_MUTEX_INITIALIZER;
static FILE *perf_file = NULL;

/* flags for informatiion we can access */
static int source_file_name_avail = FALSE;

typedef void (*call_back) (int, int);

call_back back = NULL;

void set_callback_function(call_back back_arg) {
  back = back_arg;
}

void print_callback_function(void) {
  fprintf(stderr, " the call back function address is %p\n", back);
}

static int print_error(jvmtiError error, char const * msg)
{
  fprintf(stderr, "  %s:  err code %i\n", msg, error);
  fflush(stderr);
  return 0;

}


static void JNICALL
compiled_method_load_handler(jvmtiEnv * jvmti,
                             jmethodID method,
                             jint code_size,
                             void const * code_addr,
                             jint map_length,
                             jvmtiAddrLocationMap const * map,
                             void const * compile_info)
{

  jvmtiError rtn;
  jclass class_type;
  char * thread_ptr = NULL;
  char * class_signature_ptr = NULL;
  char * source_file_name = NULL;
  char * method_signature_ptr = NULL;
  char * method_name = NULL;

  char filename[20];
  char methodname[20];
  static FILE *perf_file_tmp;

  struct jit_data_st jit_data;
  struct sym_data_st sym_data, sym_data_array[200];

  int i, error;
  unsigned long zero = 0, size;

  if (debug)
    fprintf(stderr, "Called compiled_method_load_handler\n");

  rtn = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
                                          &class_type);
  if (back == NULL) {
    fprintf(stderr, "call back function is NULL\n");
  } else {
    fprintf(stderr, "call back function is not NULL\n");
    back (1, 2);
  }

  if (rtn != JVMTI_ERROR_NONE) {
    print_error(rtn, "Error: GetMethodDeclaringClass() failed");
  }

  rtn = (*jvmti)->GetClassSignature(jvmti, class_type,
                                    &class_signature_ptr, NULL);
  if (rtn != JVMTI_ERROR_NONE) {
    print_error(rtn, "Error: GetClassSignature() failed");
    (*jvmti)->Deallocate(jvmti, (unsigned char *) class_signature_ptr);
  }

  rtn = (*jvmti)->GetMethodName(jvmti, method, &method_name,
                                &method_signature_ptr, NULL);
  if (rtn != JVMTI_ERROR_NONE) {
    print_error(rtn, "Error: GetMethodName() failed");
    (*jvmti)->Deallocate(jvmti, (unsigned char *) class_signature_ptr);
    (*jvmti)->Deallocate(jvmti, (unsigned char *) method_signature_ptr);
  }

  /* get additional info if available */
  if (source_file_name_avail == TRUE) {
    //    rtn = (*jvmti)->GetSourceFileName(jvmti, class_type,
    //                                &sym_data.source_code_filename);
    // Work on gathering the source code.  FIX
    ;
  }

  if (rtn != JVMTI_ERROR_NONE) {
    print_error(rtn, "Error: GetSourceFileName() failed");
    source_file_name_avail == FALSE;
  }

  strcpy(sym_data.method_name, method_name);
  sym_data.virtual_mem_addr = (uint64_t)(uintptr_t) code_addr;
  sym_data.code_size = code_size;

  if (debug) {
    fprintf(stderr, "PID = %d\n", getpid());
    fprintf(stderr, "compiled_method_load_handler: class_type = %p\n",
            class_type);
    fprintf(stderr, "class signature = %s, method name = %s\n",
            class_signature_ptr, sym_data.method_name);

    fprintf(stderr, "method_signature = %s\n", method_signature_ptr);

    if (source_file_name_avail == TRUE)
      fprintf(stderr, "source file name = %s\n",
              sym_data.source_code_filename);

    fprintf(stderr, "code address = %p, code size = %x\n",
            sym_data.virtual_mem_addr, sym_data.code_size);
    fprintf(stderr, "\n");
  }

  size = (unsigned long) sizeof(sym_data);


  /* check if the perf file is open */
  if (perf_file == NULL) {
    sprintf(filename, "/tmp/perf-%d.map", getpid());
    fprintf(stderr, "CARLL, symbol file %s\n", filename);

    perf_file = fopen(filename, "w");

    if (perf_file == NULL) {
      fprintf(stderr, "ERROR, could not open %s\n", filename);
    }
  }

  sym_data_array[symbol_count].virtual_mem_addr = sym_data.virtual_mem_addr;
  sym_data_array[symbol_count].code_size = sym_data.code_size;
  strcpy(sym_data_array[symbol_count].method_name, sym_data.method_name);
  printf("CARLL, here 3\n");
  fflush(stdout);
  
  printf("CARLL, source_file_name_avail = %d\n", source_file_name_avail);
  fflush(stdout);

  if (source_file_name_avail == TRUE) {
    ;  
  }

  pthread_mutex_lock(&perf_mutex);

  if ((symbol_count % pr_count == 0) && (symbol_count != 0)){
    fclose(perf_file);
    sprintf(filename, "/tmp/perf-%d-%d.map", getpid(),
            (symbol_count/pr_count));
    perf_file = fopen(filename, "w");

    if (perf_file == NULL) {
      fprintf(stderr, "ERROR, could not open %s\n", filename);
    } 

    /* Send notification to perf.data file saying remap has occured.  Do
     * this as soon as possible so samples will be correctly aligned to 
     * the old/new maps.
     */
    strcpy(jit_data.map_filename, filename);  
    jit_data.pid = getpid();
    jit_data.tid = getpid()+1;   // temporary hack, the gettid() isn't compiling
    //      jit_data.tid = gettid();  // gettid() UNDEFINED, FIX, hack for now

    error = prctl(PR_TASK_PERF_UEVENT, zero, size,
                  (unsigned long)(&jit_data),   zero);
    if (error)
      fprintf(stderr, "ERROR, perf remap with file = %s FALED\n", filename);
    
    for (i = 0; i <= symbol_count; i++) {
      fprintf(perf_file, "%llx %x %s\n",
              sym_data_array[i].virtual_mem_addr,
              sym_data_array[i].code_size,
              sym_data_array[i].method_name);
    }
    fflush(stdout);

  } else {
    fprintf(perf_file, "%llx %x %s\n",
            sym_data.virtual_mem_addr,
            sym_data.code_size,
            sym_data.method_name);
  }
  pthread_mutex_unlock(&perf_mutex);

  symbol_count++;
}

static void JNICALL
compiled_method_unload_handler(jvmtiEnv * jvmti_env,
                               jmethodID method,
                               void const * code_addr)
{
  if (debug)
    fprintf(stderr, "called compiled_method_unload_handler addr=%p\n",
            code_addr);
}



JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * jvm, char * options, void * reserved)
{
  jint  rc;
  jvmtiEventCallbacks callbacks;
  jvmtiEnv * jvmti = NULL;
  jvmtiError rtn;
  jvmtiCapabilities capabilities;

  if (options) {
    /* check the passed options */
    if (strcmp("debug", options) == 0)
      debug = TRUE;
  }

  if (debug)
    fprintf(stderr, "Called Agent_OnLoad for libjvmti-perf\n");

  rc = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);

  if (rc != JNI_OK) {
    print_error(rtn, "Error: GetEnv failed");
    return -1;
  }

  /* setup capabilities */
  memset(&capabilities, '\0', sizeof(capabilities));
  capabilities.can_generate_compiled_method_load_events = 1;
  rtn = (*jvmti)->AddCapabilities(jvmti, &capabilities);

  if (rtn != JVMTI_ERROR_NONE) {
    print_error(rtn, "Error: AddCapabilities, 
can_generate_compiled_method_load_events failed");
    return -1;
  }

  capabilities.can_get_source_file_name = 1;
  rtn = (*jvmti)->AddCapabilities(jvmti, &capabilities);

  if (rtn == JVMTI_ERROR_NONE)
    source_file_name_avail = TRUE;

  if (debug) {
    fprintf(stderr, "Capabilities: \n");

    if (source_file_name_avail == TRUE)  
      fprintf(stderr, " get_source_file_name\n");

    fprintf(stderr, "\n\n");
  }
  /* setup callbacks to collect information needed by perf */
  memset(&callbacks, 0, sizeof(callbacks));
  callbacks.CompiledMethodLoad = compiled_method_load_handler;
  callbacks.CompiledMethodUnload = compiled_method_unload_handler;

  rtn = (*jvmti)->SetEventCallbacks(jvmti, &callbacks,
                                      sizeof(callbacks));

  if (rtn != JVMTI_ERROR_NONE) {
    print_error(rtn, "Error: SetEventCallbacks failed");
    return -1;
  }

  rtn = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
                                           JVMTI_EVENT_COMPILED_METHOD_LOAD,
                                           NULL);

  if (rtn != JVMTI_ERROR_NONE) {
    print_error(rtn, "Error: Enabling method load callback failed");
    return -1;
  }

  rtn = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
                                           JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
                                           NULL);
  if (rtn != JVMTI_ERROR_NONE) {
    print_error(rtn, "Error: Enabling method unload callback failed");
    return -1;
  }

  return 0;  /* success */
}


--
To unsubscribe from this list: send the line "unsubscribe linux-perf-users" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to