blob: 00ba8bf4dc405c784500661262646a45d4c960f4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Mikhail Y. Fursov
*/
#define LOG_DOMAIN "em"
#include "cxxlog.h"
#include "DrlEMImpl.h"
#include "EBProfileCollector.h"
#include "EdgeProfileCollector.h"
#include "NValueProfileCollector.h"
#include "open/vm_properties.h"
#include "open/vm_ee.h"
#include "open/ee_em_intf.h"
#include "em_intf.h"
#include "open/vm.h"
#include "open/vm_method_access.h"
#include "open/vm_class_manipulation.h"
#include "ini.h"
#include "vm_properties.h"
#include <algorithm>
#include <sstream>
#include <fstream>
#include "port_threadunsafe.h"
#include "port_mutex.h"
#define EDGE_PROFILER_STR "EDGE_PROFILER"
#define VALUE_PROFILER_STR "VALUE_PROFILER"
#define ENTRY_BACKEDGE_PROFILER_STR "EB_PROFILER"
#define EM_CONFIG_EXT std::string(".emconf")
DrlEMImpl* DrlEMFactory::emInstance = NULL;
// TODO you may get a question why we get the same execution manager
// for multiple VM instances the proper way is to get rid of static emInstance
DrlEMImpl* DrlEMFactory::createAndInitEMInstance() {
if (emInstance == NULL) {
emInstance = new DrlEMImpl();
if (!emInstance->init()) {
delete emInstance;
emInstance = NULL;
}
}
return emInstance;
}
DrlEMImpl* DrlEMFactory::getEMInstance() {
assert(emInstance!=NULL);
return emInstance;
}
void DrlEMFactory::deinitEMInstance() {
assert(emInstance!=NULL);
emInstance->deinit();
delete emInstance;
emInstance = NULL;
}
static EM_PCTYPE get_pc_type(EM_Handle _this, PC_Handle pc) {
assert(_this!=NULL);
assert(pc!=NULL);
return ((ProfileCollector*)pc)->type;
}
static PC_Handle get_pc(EM_Handle _this, EM_PCTYPE profile_type, JIT_Handle jh, EM_JIT_PC_Role jit_role) {
assert(_this!=NULL);
assert(jh!=NULL);
DrlEMImpl* em = (DrlEMImpl*) _this;
return (PC_Handle)em->getProfileCollector(profile_type, jh, jit_role);
}
static Method_Profile_Handle
get_method_profile(EM_Handle _this, PC_Handle pch, Method_Handle mh) {
assert(_this!=NULL);
assert(pch!=NULL);
assert(mh!=NULL);
ProfileCollector* pc = (ProfileCollector*)pch;
return (Method_Profile_Handle)pc->getMethodProfile(mh);
}
RStep::RStep(JIT_Handle _jit, const std::string& _jitName, RChain* _chain, apr_dso_handle_t* _libHandle)
: jit(_jit), jitName(_jitName), catName(std::string(LOG_DOMAIN)+"."+_jitName),
chain(_chain), loggingEnabled(false), enable_profiling(NULL),
libHandle(_libHandle)
{}
//todo!! replace inlined strings with defines!!
DrlEMImpl::DrlEMImpl() : jh(NULL), _execute_method(NULL), method_lookup_table() {
nMethodsCompiled=0;
nMethodsRecompiled=0;
tick=0;
port_mutex_create(&recompilationLock, APR_THREAD_MUTEX_NESTED);
initProfileAccess();
}
DrlEMImpl::~DrlEMImpl() {
deallocateResources();
port_mutex_destroy(&recompilationLock);
}
void DrlEMImpl::initProfileAccess() {
profileAccessInterface.get_pc_type = get_pc_type;
profileAccessInterface.get_pc = get_pc;
profileAccessInterface.get_method_profile = get_method_profile;
//EB profile
profileAccessInterface.eb_profiler_create_profile = eb_profiler_create_profile;
profileAccessInterface.eb_profiler_get_entry_counter_addr=eb_profiler_get_entry_counter_addr;
profileAccessInterface.eb_profiler_get_backedge_counter_addr = eb_profiler_get_backedge_counter_addr;
profileAccessInterface.eb_profiler_is_in_sync_mode= eb_profiler_is_in_sync_mode;
profileAccessInterface.eb_profiler_get_entry_threshold = eb_profiler_get_entry_threshold;
profileAccessInterface.eb_profiler_sync_mode_callback = (void (*)(Method_Profile_Handle))vm_create_helper_for_function((void *(*)(void *))eb_profiler_sync_mode_callback);
profileAccessInterface.eb_profiler_get_backedge_threshold = eb_profiler_get_backedge_threshold;
//EDGE profile
profileAccessInterface.edge_profiler_create_profile = edge_profiler_create_profile;
profileAccessInterface.edge_profiler_get_num_counters = edge_profiler_get_num_counters;
profileAccessInterface.edge_profiler_get_checksum = edge_profiler_get_checksum;
profileAccessInterface.edge_profiler_get_counter_addr = edge_profiler_get_counter_addr;
profileAccessInterface.edge_profiler_get_entry_counter_addr = edge_profiler_get_entry_counter_addr;
profileAccessInterface.edge_profiler_get_entry_threshold = edge_profiler_get_entry_threshold;
profileAccessInterface.edge_profiler_get_backedge_threshold = edge_profiler_get_backedge_threshold;
//Value profile
profileAccessInterface.value_profiler_create_profile = value_profiler_create_profile;
profileAccessInterface.value_profiler_add_value = value_profiler_add_value;
profileAccessInterface.value_profiler_get_top_value = value_profiler_get_top_value;
profileAccessInterface.value_profiler_dump_values = value_profiler_dump_values;
return;
}
void DrlEMImpl::deallocateResources() {
tbsClients.clear();
for (RChains::const_iterator cit = chains.begin(), cend = chains.end(); cit!=cend; ++cit) {
RChain* chain = *cit;
for (RSteps::const_iterator sit = chain->steps.begin(), send = chain->steps.end(); sit!=send; ++sit) {
RStep* step = *sit;
//todo:call deinit on JIT instance
delete step;
}
delete chain;
}
chains.clear();
for (ProfileCollectors::iterator it = collectors.begin(), end = collectors.end(); it!=end; ++it) {
ProfileCollector* pc = *it;
delete pc;
}
collectors.clear();
}
//_____________________________________________________________________
// Reading and parsing configuration
static bool endsWith(const std::string& str, const std::string& suffix) {
if (str.length() < suffix.length()) {
return false;
}
return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
}
std::string prepareLibPath(const std::string& origPath) {
#ifdef PLATFORM_NT
std::string separator("\\"), libPrefix(""), libSuffix(".dll");
#else
std::string separator("/"), libPrefix("lib"), libSuffix(".so");
#endif
std::string path = origPath;
if (path.find('/') == path.npos && path.find('\\') == path.npos ) {
char* c_string_tmp_value = vm_properties_get_value(O_A_H_VM_VMDIR, JAVA_PROPERTIES);
std::string dir = c_string_tmp_value == NULL ? "" : c_string_tmp_value;
vm_properties_destroy_value(c_string_tmp_value);
if (libPrefix.length() > 0 && !startsWith(path, libPrefix)) {
path = libPrefix + path;
}
if (!dir.empty()) {
path = dir + separator + path;
}
}
if (!endsWith(path, libSuffix)) {
path+=libSuffix;
}
return path;
}
static std::string getParam(const std::string& config, const std::string& name) {
std::istringstream is(config);
std::string propPrefix = name+"=";
size_t prefixLen = propPrefix.length();
std::string line;
while (std::getline(is, line)) {
if (line.length() > prefixLen && std::equal(propPrefix.begin(),propPrefix.end(), line.begin())) {
return line.substr(prefixLen);
}
}
return "";
}
typedef std::vector<std::string> StringList;
static StringList getParamAsList(const std::string& config, const std::string& name, char listSeparator, bool notEmpty) {
std::string value = getParam(config, name);
StringList res;
std::string token;
for (std::string::const_iterator it = value.begin(), end = value.end(); it!=end; ++it) {
char c = *it;
if (c == listSeparator) {
if (token.empty() && notEmpty) {
continue;
}
res.push_back(token);
token.clear();
} else {
token.push_back(c);
}
}
if (!token.empty()) { //last value
res.push_back(token);
}
return res;
}
static StringList getAllParamsAsList(const std::string& config, const std::string& name) {
StringList res;
std::istringstream is(config);
std::string propPrefix = name+"=";
size_t prefixLen = propPrefix.length();
std::string line;
while (std::getline(is, line)) {
if (line.length() > prefixLen && std::equal(propPrefix.begin(),propPrefix.end(), line.begin())) {
res.push_back(line.substr(prefixLen));
}
}
return res;
}
static std::string readFile(const std::string& fileName) {
std::string config;
std::ifstream configFile;
configFile.open(fileName.c_str(), std::ios::in);
bool rc = false;
if (configFile.is_open()) {
std::string line;
size_t idx = std::string::npos;
while (getline(configFile, line)) {
if (startsWith(line, "#")) {
continue;
} else if (startsWith(line, "-D") && (idx = line.find('=')) != std::string::npos) {
std::string name = line.substr(2, idx-2);
std::string value = line.substr(idx+1);
if (!vm_property_is_set(name.c_str(), JAVA_PROPERTIES)) {
vm_properties_set_value(name.c_str(), value.c_str(), JAVA_PROPERTIES);
}
continue;
} else if (startsWith(line, "-XD") && (idx = line.find('=')) != std::string::npos) {
std::string name = line.substr(3, idx-3);
std::string value = line.substr(idx+1);
if (!vm_property_is_set(name.c_str(),VM_PROPERTIES)) {
vm_properties_set_value(name.c_str(), value.c_str(), VM_PROPERTIES);
}
continue;
} else if (startsWith(line, "-XX:") && line.length() >= 5) {
idx = line.find('=');
std::string name;
std::string value;
if (idx != std::string::npos) {
name = line.substr(4, idx-4);
value = line.substr(idx+1);
} else {
if (line[4] == '-' ) {
value = "off";
name = line.substr(5);
} else if (line[4] == '+') {
value = "on";
name = line.substr(5);
} else {
value = "";
name = line.substr(4);
}
}
if (!vm_property_is_set(name.c_str(),VM_PROPERTIES)) {
vm_properties_set_value(name.c_str(), value.c_str(), VM_PROPERTIES);
}
continue;
}
config+=line + "\n";
}
rc = !config.empty();
}
if (!rc) {
LECHO(1, "EM: Can't read configuration from '{0}'" << fileName.c_str());
}
return config;
}
std::string DrlEMImpl::readConfiguration() {
char* c_string_tmp_value = vm_properties_get_value("em.properties", VM_PROPERTIES);
std::string configFileName = c_string_tmp_value == NULL ? "" : c_string_tmp_value;
vm_properties_destroy_value(c_string_tmp_value);
if (configFileName.empty()) {
bool jitTiMode = vm_property_get_boolean("vm.jvmti.enabled", FALSE, VM_PROPERTIES);
bool interpreterMode = vm_property_get_boolean("vm.use_interpreter", FALSE, VM_PROPERTIES);
configFileName = interpreterMode ? "interpreter" : (jitTiMode ? "ti" : "client");
}
if (!endsWith(configFileName, EM_CONFIG_EXT)) {
configFileName = configFileName+EM_CONFIG_EXT;
}
if (configFileName.find('/') == configFileName.npos && configFileName.find('\\') == configFileName.npos ) {
c_string_tmp_value = vm_properties_get_value(O_A_H_VM_VMDIR, JAVA_PROPERTIES);
std::string defaultConfigDir = c_string_tmp_value == NULL ? "" : c_string_tmp_value;
vm_properties_destroy_value(c_string_tmp_value);
configFileName = defaultConfigDir + "/" + configFileName;
}
std::string config = readFile(configFileName);
return config;
}
//_______________________________________________________________________
// EM initialization methods
bool DrlEMImpl::init() {
_execute_method = JIT_execute_method_default;
std::string config = readConfiguration();
if (!config.empty()) {
buildChains(config);
}
return !chains.empty();
}
static bool enable_profiling_stub(JIT_Handle jit, PC_Handle pc, EM_JIT_PC_Role role) {
return false;
}
static void profile_notification_callback_stub(JIT_Handle, PC_Handle, Method_Handle) {
}
bool DrlEMImpl::initJIT(const std::string& libName, apr_dso_handle_t* libHandle, RStep& step) {
apr_dso_handle_sym_t fn = NULL;
if (apr_dso_sym(&fn, libHandle, "JIT_init") != APR_SUCCESS) {
LECHO(2, "EM: Not a JIT shared lib: '{0}'" << libName.c_str());
return false;
}
void (*_init)(JIT_Handle, const char*, vm_adaptor_t) =
(void (*)(JIT_Handle, const char*, vm_adaptor_t)) fn;
_init(step.jit, step.jitName.c_str(), vm_get_interface);
bool pcEnabled = false;
if (apr_dso_sym(&fn, libHandle, "JIT_set_profile_access_interface") == APR_SUCCESS) {
pcEnabled = true;
void (*_setPAInterface)(JIT_Handle, EM_Handle, struct EM_ProfileAccessInterface*) = (void (*)(JIT_Handle, EM_Handle, struct EM_ProfileAccessInterface*))fn;
_setPAInterface(step.jit, (EM_Handle)this, &profileAccessInterface);
}
if (pcEnabled && apr_dso_sym(&fn, libHandle, "JIT_enable_profiling") == APR_SUCCESS) {
step.enable_profiling = (bool(*)(JIT_Handle, PC_Handle, EM_JIT_PC_Role))fn;
} else {
step.enable_profiling = enable_profiling_stub;
}
if (pcEnabled && apr_dso_sym(&fn, libHandle, "JIT_profile_notification_callback") == APR_SUCCESS) {
step.profile_notification_callback = (void(*)(JIT_Handle, PC_Handle, Method_Handle))fn;
} else {
step.profile_notification_callback = profile_notification_callback_stub;
}
return true;
}
std::string DrlEMImpl::getJITLibFromCmdLine(const std::string& jitName) const {
std::string propName = std::string("em.")+jitName+".jitPath";
char* c_string_tmp_value = vm_properties_get_value(propName.c_str(), VM_PROPERTIES);
std::string jitLib = c_string_tmp_value == NULL ? "" : c_string_tmp_value;
vm_properties_destroy_value(c_string_tmp_value);
if (jitLib.empty()) {
c_string_tmp_value = vm_properties_get_value("em.jitPath", VM_PROPERTIES);
jitLib = c_string_tmp_value == NULL ? "" : c_string_tmp_value;
vm_properties_destroy_value(c_string_tmp_value);
}
return jitLib;
}
void DrlEMImpl::buildChains(std::string& config) {
bool loggingEnabled = log_is_info_enabled(LOG_DOMAIN);
StringList chainNames = getParamAsList(config, "chains", ',', true);
if (chainNames.empty()) {
LECHO(3, "EM: No 'chains' property found in configuration");
return;
}
bool failed = false;
for (StringList::const_iterator chainIt = chainNames.begin(), chainEnd = chainNames.end(); chainIt!=chainEnd; ++chainIt) {
std::string chainName = *chainIt;
if (std::count(chainNames.begin(), chainNames.end(), chainName)!=1) {
failed = true;
break;
}
RChain* chain = new RChain();
chains.push_back(chain);
StringList jitsInChain= getParamAsList(config, chainName + ".jits", ',', true);
for (StringList::const_iterator jitIt = jitsInChain.begin(), jitEnd = jitsInChain.end(); jitIt!=jitEnd; ++jitIt) {
std::string jitName= *jitIt;
std::string jitLib = getJITLibFromCmdLine(jitName);
if (jitLib.empty()) {
jitLib = getParam(config, jitName+".file");
}
if (jitLib.empty()) {
LECHO(4, "EM: No JIT library specified for JIT :'{0}'" << jitLib.c_str());
failed = true;
break;
}
std::string fullJitLibPath = prepareLibPath(jitLib);
apr_dso_handle_t* libHandle;
JIT_Handle jh = vm_load_jit(fullJitLibPath.c_str(), &libHandle); //todo: do not load the same dll twice!!!
if (jh == NULL) {
LECHO(5, "EM: JIT library loading error:'{0}'" << fullJitLibPath.c_str());
failed = true;
break;
}
RStep* step = new RStep(jh, jitName, chain, libHandle);
step->loggingEnabled = loggingEnabled || log_is_info_enabled(step->catName.c_str());
chain->steps.push_back(step);
if (!initJIT(fullJitLibPath, libHandle, *step)) {
failed = true;
break;
}
}
failed = failed || chain->steps.empty();
if (!failed) {
// reading chain filters
StringList filters = getAllParamsAsList(config, chainName+".filter");
for (StringList::const_iterator filterIt = filters.begin(), filterEnd = filters.end(); filterIt!=filterEnd; ++filterIt) {
const std::string& filter = *filterIt;
bool res = chain->addMethodFilter(filter);
if (!res) {
LECHO(6, "EM: Invalid filter :'{0}'" << filter.c_str());
}
}
}
if (failed) {
break;
}
}
if (!failed) { //initialize profile collectors
for (RChains::const_iterator it = chains.begin(), end = chains.end(); it!=end; ++it) {
RChain* chain = *it;
failed = !initProfileCollectors(chain, config);
if (failed) {
break;
}
}
}
//The next lines do the following:
//If we have only 1 execution engine in CFG - check if it have JIT_execute_method
//This way interpreter mode is supported today.
//This code must be refactored when mixed (JIT/interpreter) mode is implemented
if (!failed && chains.size()==1) {
RChain* chain = *chains.begin();
assert(chain->steps.size() > 0);
RStep* step = *chain->steps.begin();
apr_dso_handle_sym_t fn = NULL;
apr_dso_sym(&fn, step->libHandle, "JIT_execute_method");
if (fn!=NULL) {
_execute_method = (void(*)(JIT_Handle,jmethodID, jvalue*, jvalue*)) fn;
}
}
if (failed) {
deallocateResources();
}
}
void DrlEMImpl::deinit() {
}
//______________________________________________________________________________
// EM runtime
void DrlEMImpl::executeMethod(jmethodID meth, jvalue *return_value, jvalue *args) {
//do not choose JIT here, this method will call-back from vm with compileMethod request.
_execute_method(0, meth, return_value, args);
}
JIT_Result DrlEMImpl::compileMethod(Method_Handle mh) {
//initial method compilation. Select chain to use.
UNSAFE_REGION_START
// May affect logging statistics, also used in debug-intended method filter
// Does not affect normal execution
nMethodsCompiled++;
UNSAFE_REGION_END
//these vars are used for logging
const char* methodName = NULL;
const char* className = NULL;
const char* signature = NULL;
size_t n = nMethodsCompiled;
assert(!chains.empty());
for (RChains::const_iterator it = chains.begin(), end = chains.end(); it!=end; ++it) {
RChain* chain = *it;
if (chain->acceptMethod(mh, nMethodsCompiled)) {
assert(!chain->steps.empty());
for (size_t i=0;i<chain->steps.size(); i++) {
RStep* step = chain->steps[i];
if (step->loggingEnabled) {
methodName = method_get_name(mh);
Class_Handle ch = method_get_class(mh);
className = class_get_name(ch);
signature = method_get_descriptor(mh);
std::ostringstream msg;
msg <<"EM: compile start:["<<step->jitName.c_str()<<" n="<<n<<"] "
<<className<<"."<<methodName<<signature;
INFO2(step->catName.c_str(), msg.str().c_str());
}
JIT_Result res = vm_compile_method(step->jit, mh);
if (step->loggingEnabled) {
std::ostringstream msg;
msg << "EM: compile done:["<<step->jitName.c_str()<<" n="<<n<<": "
<<(res ==JIT_SUCCESS ? "OK" : "FAILED")<<"] "<<className<<"."<<methodName<<signature;
INFO2(step->catName.c_str(), msg.str().c_str());
}
if (res == JIT_SUCCESS) {
return JIT_SUCCESS;
}
}
}
}
return JIT_FAILURE;
}
//______________________________________________________________________________
// Profile collectors initialization and recompilation
static U_32 toNum(const std::string& numStr, bool *rc ) {
if (isNum(numStr)) {
*rc = true;
return atoi(numStr.c_str());
}
*rc = false;
return 0;
}
ProfileCollector* DrlEMImpl::createProfileCollector(const std::string& profilerName, const std::string& config, RStep* step) {
ProfileCollector* pc = getProfileCollector(profilerName);
if (pc != NULL){
return NULL;
}
std::string profilerType = getParam(config, profilerName+".profilerType");
if (profilerType!=ENTRY_BACKEDGE_PROFILER_STR && profilerType!=EDGE_PROFILER_STR && profilerType!=VALUE_PROFILER_STR) {
LECHO(7, "EM: Unsupported profiler type");
return NULL;
}
if (profilerType == ENTRY_BACKEDGE_PROFILER_STR || profilerType == EDGE_PROFILER_STR) {
EBProfileCollector::EB_ProfilerMode ebMode = EBProfileCollector::EB_PCMODE_SYNC;
std::string mode = profilerType==EDGE_PROFILER_STR ? "ASYNC" : getParam(config, profilerName+".mode");
if (mode == "ASYNC") {
ebMode = EBProfileCollector::EB_PCMODE_ASYNC;
} else if (mode!="SYNC") {
LECHO(8, "EM: unsupported profiler mode");
return NULL;
}
bool ok = false;
U_32 eThreshold = toNum(getParam(config, profilerName+".entryThreshold"), &ok);//todo: default values..
if (!ok) {
LECHO(9, "EM: illegal '{0}' value" << "entryThreshold");
return NULL;
}
U_32 bThreshold = toNum(getParam(config, profilerName+".backedgeThreshold"), &ok);
if (!ok) {
LECHO(9, "EM: illegal '{0}' value" << "backedgeThreshold");
return NULL;
}
U_32 tbsTimeout = 0, tbsInitialTimeout = 0;
if (ebMode == EBProfileCollector::EB_PCMODE_ASYNC) {
tbsTimeout= toNum(getParam(config, profilerName+".tbsTimeout"), &ok);
if (!ok) {
LECHO(9, "EM: illegal '{0}' value" << "tbsTimeout");
return NULL;
}
tbsInitialTimeout= toNum(getParam(config, profilerName+".tbsInitialTimeout"), &ok);
if (!ok) {
LECHO(9, "EM: illegal '{0}' value" << "tbsInitialTimeout");
return NULL;
}
}
if (profilerType == EDGE_PROFILER_STR) {
pc = new EdgeProfileCollector(this, profilerName, step->jit, tbsInitialTimeout, tbsTimeout, eThreshold, bThreshold);
} else {
pc = new EBProfileCollector(this, profilerName, step->jit, ebMode, eThreshold, bThreshold, tbsInitialTimeout, tbsTimeout);
}
} else if (profilerType == VALUE_PROFILER_STR) {
typedef ValueProfileCollector VPC;
int vpSteadySize = 4, vpClearSize = 0, vpClearInterval = 0;
std::string vpalgo = getParam(config, profilerName+".vpalgo");
VPC::algotypes vpMode = VPC::TNV_FIRST_N;
if (vpalgo == "TNV_DIVIDED") {
vpMode = VPC::TNV_DIVIDED;
} else if (vpalgo != "TNV_FIRST_N") {
LECHO(10, "EM: unsupported value profiler algotype");
return NULL;
}
std::string strategy = getParam(config, profilerName+".updateStrategy");
ProfileUpdateStrategy updateStrategy = UPDATE_LOCKED;
if (strategy == "FLAGGED_ALL") {
updateStrategy = UPDATE_FLAGGED_ALL;
}else if (strategy == "FLAGGED_INSERT") {
updateStrategy = UPDATE_FLAGGED_INSERT;
}else if (strategy == "UNSAFE") {
updateStrategy = UPDATE_UNSAFE;
}else if (strategy == "LOCKED_INSERT") {
updateStrategy = UPDATE_LOCKED_INSERT;
}else if (strategy != "LOCKED") {
LECHO(10, "EM: unsupported value profiler updateStrategy");
return NULL;
}
if (vpMode != VPC::TNV_FIRST_N && updateStrategy != UPDATE_LOCKED) {
LECHO(10, "EM: unsupported value profiler combination of "
"vpalgo and updateStrategy, only TNV_FIRST_N vpalgo "
"curretly sypports other than LOCKED strategy");
return NULL;
}
bool ok = false;
vpSteadySize = toNum(getParam(config, profilerName+".vpSteadySize"), &ok);
if (!ok) {
LECHO(9, "EM: illegal '{0}' value" << "SteadySize");
return NULL;
}
if (vpMode == VPC::TNV_DIVIDED) {
vpClearSize = toNum(getParam(config, profilerName+".vpClearSize"), &ok);
if (!ok) {
LECHO(9, "EM: illegal '{0}' value" << "ClearSize");
return NULL;
}
vpClearInterval = toNum(getParam(config, profilerName+".vpClearInterval"), &ok);
if (!ok) {
LECHO(9, "EM: illegal '{0}' value" << "ClearInterval");
return NULL;
}
}
pc = new ValueProfileCollector(this, profilerName, step->jit, vpSteadySize,
vpClearSize, vpClearInterval, vpMode, updateStrategy);
}
return pc;
}
ProfileCollector* DrlEMImpl::getProfileCollector(const std::string& name) const {
for (ProfileCollectors::const_iterator it = collectors.begin(), end = collectors.end(); it!=end; ++it) {
ProfileCollector* c = *it;
if (c->name == name) {
return c;
}
}
return NULL;
}
bool DrlEMImpl::initProfileCollectors(RChain* chain, const std::string& config) {
bool failed = false;
for (RSteps::const_iterator it = chain->steps.begin(), end = chain->steps.end(); it!=end; ++it) {
RStep* step = *it;
StringList genProfNames = getParamAsList(config, step->jitName + ".genProfile", ',', false);
for (StringList::const_iterator profIt = genProfNames.begin(), profEnd = genProfNames.end(); profIt!=profEnd; ++profIt) {
std::string profilerName = *profIt;
if (!profilerName.empty()) {
ProfileCollector* pc = createProfileCollector(profilerName, config, step);
if (pc == NULL) {
LECHO(11, "EM: profile configuration failed: {0}" << profilerName.c_str());
failed = true;
break;
}
bool genOk = step->enable_profiling(step->jit, (PC_Handle)pc, EM_JIT_PROFILE_ROLE_GEN);
if (genOk) {
collectors.push_back(pc);
TbsEMClient* tbsClient = pc->getTbsEmClient();
if (tbsClient!=NULL) {
assert(tbsClient->getTimeout() != 0 && tbsClient->getTimeout()!=0);
tbsClient->setNextTick(tbsClient->getInitialTimeout());
tbsClients.push_back(tbsClient);
}
} else {
LECHO(12, "EM: profile generation is not supported: {0}" << profilerName.c_str());
delete pc;
failed = true;
break;
}
}
}
StringList useProfNames = getParamAsList(config, step->jitName + ".useProfile", ',', false);
for (StringList::const_iterator profIt = useProfNames.begin(), profEnd = useProfNames.end(); profIt!=profEnd; ++profIt) {
std::string profilerName = *profIt;
if (!profilerName.empty()) {
ProfileCollector* pc = getProfileCollector(profilerName);
bool invalidChain = true;
if (pc!=NULL) {
for(RSteps::const_iterator it2=chain->steps.begin(); it2 <it; ++it2) {
RStep* prevStep = *it2;
if (prevStep->jit == pc->genJit) {
invalidChain = false;
break;
}
}
}
bool useOk = !invalidChain && (pc!=NULL && step->enable_profiling(step->jit, (PC_Handle)pc, EM_JIT_PROFILE_ROLE_USE));
if (useOk) {
pc->addUseJit(step->jit);
} else {
if (pc == NULL) {
LECHO(13, "EM: profile not found: {0}" << profilerName.c_str());
} else if (invalidChain) {
LECHO(14, "EM: illegal use of profile: {0}" << profilerName.c_str());
} else {
LECHO(15, "EM: profile usage is not supported: {0}" << profilerName.c_str());
}
}
}
}
}
if (!failed && !tbsClients.empty()) {
//timer.start(this);
}
return !failed;
}
void DrlEMImpl::methodProfileIsReady(MethodProfile* mp) {
port_mutex_lock(&recompilationLock);
if (methodsInRecompile.find((Method_Profile_Handle)mp)!=methodsInRecompile.end()) {
//method is already recompiling by another thread or by this thread(recursion)
port_mutex_unlock(&recompilationLock);
return;
}
methodsInRecompile.insert((Method_Profile_Handle)mp);
nMethodsRecompiled++;
port_mutex_unlock(&recompilationLock);
const char* methodName = NULL;
const char* className = NULL;
const char* signature = NULL;
size_t n = nMethodsRecompiled;
JIT_Handle jit = mp->pc->genJit;
for (RChains::const_iterator it = chains.begin(), end = chains.end(); it!=end; ++it) {
RChain* chain = *it;
for (RSteps::const_iterator sit = chain->steps.begin(), send = chain->steps.end(); sit!=send; ++sit) {
RStep* step = *sit;
if (step->jit == jit) {
//notify JIT which has generated this profile that profile is ready.
step->profile_notification_callback(step->jit, mp->pc, mp->mh);
++sit;
RStep* nextStep = sit!=send ? *sit: NULL;
if (nextStep != NULL) {
if (nextStep->loggingEnabled) {
methodName = method_get_name(mp->mh);
Class_Handle ch = method_get_class(mp->mh);
className = class_get_name(ch);
signature = method_get_descriptor(mp->mh);
std::ostringstream msg;
msg <<"EM: recompile start:["<<nextStep->jitName.c_str()<<" n="<<n<<"] "
<<className<<"."<<methodName<<signature;
INFO2(nextStep->catName.c_str(), msg.str().c_str());
}
JIT_Result res = vm_compile_method(nextStep->jit, mp->mh);
if (nextStep->loggingEnabled) {
std::ostringstream msg;
msg << "EM: recompile done:["<<nextStep->jitName.c_str()<<" n="<<n<<": "
<<(res ==JIT_SUCCESS ? "OK" : "FAILED")<<"] "<<className<<"."<<methodName<<signature;
INFO2(nextStep->catName.c_str(), msg.str().c_str());
}
}
}
}
}
port_mutex_lock(&recompilationLock);
methodsInRecompile.erase((Method_Profile_Handle)mp);
port_mutex_unlock(&recompilationLock);
}
ProfileCollector* DrlEMImpl::getProfileCollector(EM_PCTYPE type, JIT_Handle jh, EM_JIT_PC_Role jitRole) const {
for (ProfileCollectors::const_iterator it = collectors.begin(), end = collectors.end(); it!=end; ++it) {
ProfileCollector* pc = *it;
if (pc->type == type) {
bool matched = false;
if (jitRole == EM_JIT_PROFILE_ROLE_GEN) {
matched = pc->genJit == jh;
} else {
matched = std::find(pc->useJits.begin(), pc->useJits.end(), jh)!=pc->useJits.end();
}
if (matched) {
return pc;
}
}
}
return NULL;
}
bool DrlEMImpl::needTbsThreadSupport() const {
return !tbsClients.empty();
}
void DrlEMImpl::tbsTimeout() {
for (TbsClients::const_iterator it = tbsClients.begin(), end = tbsClients.end(); it!=end; ++it) {
TbsEMClient* c = *it;
if (c->getNextTick() == tick) {
// printf("tick!\n");
c->onTimeout();
c->setNextTick(tick + c->getTimeout());
}
}
tick++;
}
int DrlEMImpl::getTbsTimeout() const {
return 100;
}
void DrlEMImpl::classloaderUnloadingCallback(Class_Loader_Handle class_handle) {
//notify every profile collector about classloader unloading
}
void DrlEMImpl::registerCodeChunk(Method_Handle method_handle, void *code_addr,
size_t size, void *data)
{
method_lookup_table.add(method_handle, code_addr, size, data);
}
Method_Handle DrlEMImpl::lookupCodeChunk(void *ip, Boolean is_ip_past,
void **code_addr, size_t *size, void **data)
{
return method_lookup_table.find(ip, is_ip_past, code_addr, size, data);
}
Boolean DrlEMImpl::unregisterCodeChunk(void *addr)
{
return method_lookup_table.remove(addr);
}