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
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
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
00155
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
00202
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
00218
00219
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 }