jvmpi_oprofile.cpp

Go to the documentation of this file.
00001 
00027 #include <iostream>
00028 #include <map>
00029 #include <string>
00030 #include <cstring>
00031 #include <stdexcept>
00032 #include <cerrno>
00033 
00034 extern "C" {
00035 #include <stdint.h>
00036 #include <jvmpi.h>
00037 #include <opagent.h>
00038 }
00039 
00040 using namespace std;
00041 
00042 static bool debug = false;
00043 static op_agent_t agent_hdl;
00044 
00045 class class_details {
00046 public:
00047     string name;
00048     map<jmethodID, string> method_names;
00049     map<jmethodID, string> method_signatures;
00050 };
00051 
00052 
00053 static pthread_mutex_t class_map_mutex = PTHREAD_MUTEX_INITIALIZER;
00054 static map <jobjectID, class_details> loaded_classes;
00055 
00056 void class_load(JVMPI_Event * event)
00057 {
00058     class_details cls;
00059     cls.name = event->u.class_load.class_name;
00060     JVMPI_Method * passed_methods = event->u.class_load.methods;
00061     for (int i = 0; i < event->u.class_load.num_methods;
00062          i++, passed_methods++) {
00063         cls.method_names[passed_methods->method_id] =
00064             passed_methods->method_name;
00065         cls.method_signatures[passed_methods->method_id] =
00066             passed_methods->method_signature;
00067     }
00068 
00069     pthread_mutex_lock(&class_map_mutex);
00070     loaded_classes[event->u.class_load.class_id] = cls;
00071     pthread_mutex_unlock(&class_map_mutex);
00072 }
00073 
00074 void class_unload(JVMPI_Event * event)
00075 {
00076     pthread_mutex_lock(&class_map_mutex);
00077     loaded_classes.erase(event->u.class_load.class_id);
00078     pthread_mutex_unlock(&class_map_mutex);
00079 }
00080 
00081 JVMPI_Interface * jvmpi;
00082 
00083 void compiled_method_load(JVMPI_Event * event)
00084 {
00085     jmethodID method = event->u.compiled_method_load.method_id;
00086     void * code_addr =  event->u.compiled_method_load.code_addr;
00087     jint code_size =  event->u.compiled_method_load.code_size;
00088 
00089     jvmpi->DisableGC();
00090      /* Get the class of the method */
00091     jobjectID classID = jvmpi->GetMethodClass(method);
00092     jvmpi->EnableGC();
00093 
00094     pthread_mutex_lock(&class_map_mutex);
00095     map<jobjectID, class_details>::iterator iter =
00096         loaded_classes.find(classID);
00097     if (iter == loaded_classes.end()) {
00098         throw runtime_error("Error: Cannot find class for compiled"
00099                     " method\n");
00100     }
00101 
00102     class_details cls_info = ((class_details)iter->second);
00103     map<jmethodID, string>::iterator method_it =
00104         cls_info.method_names.find(method);
00105     if (method_it == cls_info.method_names.end()) {
00106         throw runtime_error("Error: Cannot find method name for "
00107                     "compiled method\n");
00108     }
00109     char const * method_name = ((string)method_it->second).c_str();
00110     method_it = cls_info.method_signatures.find(method);
00111     if (method_it == cls_info.method_signatures.end()) {
00112         throw runtime_error("Error: Cannot find method signature "
00113                     "for compiled method\n");
00114     }
00115     char const * method_signature = ((string)method_it->second).c_str();
00116 
00117     string const class_signature = "L" + cls_info.name + ";";
00118     pthread_mutex_unlock(&class_map_mutex);
00119 
00120     if (debug) {
00121         cerr << "load: class=" << class_signature << ", method ="
00122              << method_name << ", method signature = "
00123              << method_signature
00124              << ", addr=" << code_addr << ", size="
00125              << code_size << endl;
00126     }
00127 
00128     // produce a symbol name out of class name and method name
00129     int cnt = strlen(method_name) + strlen(class_signature.c_str()) +
00130         strlen(method_signature) + 2;
00131     char buf[cnt];
00132     strncpy(buf, class_signature.c_str(), cnt - 1);
00133     strncat(buf, method_name, cnt - strlen(buf) - 1);
00134     strncat(buf, method_signature, cnt - strlen(buf) - 1);
00135     if (op_write_native_code(agent_hdl, buf, (uint64_t) code_addr,
00136                  code_addr, code_size))
00137         perror("Error: op_write_native_code()");
00138 }
00139 
00140 void compiled_method_unload(JVMPI_Event * event)
00141 {
00142     void * code_addr =  event->u.compiled_method_load.code_addr;
00143     if (debug) {
00144         cerr << "unload: addr="
00145             << (unsigned long long) (uintptr_t) code_addr
00146             << endl;
00147     }
00148     if (op_unload_native_code(agent_hdl, (uint64_t)code_addr))
00149         perror("Error: op_unload_native_code()");
00150 }
00151 
00152 void jvm_shutdown(JVMPI_Event * event)
00153 {
00154     /* Checking event here is not really necessary; added only to silence
00155      * the 'unused parameter' compiler warning.
00156      */
00157     if (event)
00158         if (op_close_agent(agent_hdl))
00159             perror("Error: op_close_agent()");
00160 }
00161 
00162 
00163 void jvm_notify_event(JVMPI_Event * event)
00164 {
00165     switch (event->event_type) {
00166     case JVMPI_EVENT_COMPILED_METHOD_LOAD:
00167         compiled_method_load(event);
00168         break;
00169     case JVMPI_EVENT_COMPILED_METHOD_UNLOAD:
00170         compiled_method_unload(event);
00171         break;
00172     case JVMPI_EVENT_JVM_SHUT_DOWN:
00173         jvm_shutdown(event);
00174         break;
00175     case JVMPI_EVENT_CLASS_LOAD:
00176         class_load(event);
00177         break;
00178     case JVMPI_EVENT_CLASS_UNLOAD:
00179         class_unload(event);
00180         break;
00181     default:
00182         break;
00183     }
00184 }
00185 
00186 extern "C" {
00187 JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM * jvm, char * options,
00188                                   void * reserved)
00189 {
00190     int err;
00191 
00192     if (options && strstr(options, "version")) {
00193         cerr << "jvmpi_oprofile: current libopagent version "
00194                  << op_major_version() << "." << op_minor_version()
00195                  << endl;
00196         throw runtime_error("Exiting");
00197     }
00198 
00199     if (options && strstr(options, "debug=yes")) {
00200         debug = true;
00201         /* Add something braindead to silence the 'unused parameter'
00202          * compiler warning.
00203          */
00204         if (reserved)
00205             debug = true;
00206     }
00207 
00208     if (debug)
00209         cerr << "jvmpi_oprofile: agent activated" << endl;
00210 
00211     agent_hdl = op_open_agent();
00212     if (!agent_hdl) {
00213         perror("Error: op_open_agent()");
00214         throw runtime_error("Exiting");
00215     }
00216 
00217     /* The union below is used to avoid the 'dereferencing type-punned
00218      * pointer will break strict-aliasing rules' compiler warning on the
00219      * GetEnv call.
00220      */
00221     union {
00222         JVMPI_Interface * jvmpi_ifc;
00223         void * jvmpi_ifc_ptr;
00224     } jvmpi_GetEnv_arg;
00225     err = jvm->GetEnv(&jvmpi_GetEnv_arg.jvmpi_ifc_ptr, JVMPI_VERSION_1);
00226     if (err < 0) {
00227         cerr << "GetEnv failed with rc=" << err << endl;
00228         throw runtime_error("Exiting");
00229     }
00230     jvmpi = jvmpi_GetEnv_arg.jvmpi_ifc;
00231     jvmpi->EnableEvent(JVMPI_EVENT_COMPILED_METHOD_LOAD, NULL);
00232     jvmpi->EnableEvent(JVMPI_EVENT_COMPILED_METHOD_UNLOAD, NULL);
00233     jvmpi->EnableEvent(JVMPI_EVENT_JVM_SHUT_DOWN, NULL);
00234     jvmpi->EnableEvent(JVMPI_EVENT_CLASS_LOAD, NULL);
00235 
00236     jvmpi->NotifyEvent = jvm_notify_event;
00237     return JNI_OK;
00238 }
00239 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1