2016-12-26 14 views
2

Я развернул простой агент JVMTI для тестирования инструментария байт-кода. Моей стратегией является вызов функции RetransformClasses в CompiledMethodLoad для вызова ClassFileLoadHook. Я написал следующий код, чтобы сделать это:JVMTI RetransformClasses() занимает много времени

err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &klass); 
    check_jvmti_error(jvmti, err, "Get Declaring Class"); 

    err = (*jvmti)->RetransformClasses(jvmti, 1, &klass); 
    check_jvmti_error(jvmti, err, "Retransform class"); 

Эта функция работает правильно, вызывая ClassFileLoadHook событие, но это занимает много времени, пока я просто мимо того же класса внутри него. Моя функция обратного вызова ClassFileLoadHook пуста. Я рассчитываю время простого алгоритма умножения матрицы. Комментируя функцию RetransformClasses, я получаю время выполнения порядка 0.8 seconds. В то время как просто запись этой функции увеличивает время выполнения примерно до 15 seconds.

Предполагается, что это займет слишком много накладных расходов или я делаю что-то неправильно?

С уважением

Код:

static int x = 1; 
void JNICALL 
compiled_method_load(jvmtiEnv *jvmti, jmethodID method, jint code_size, 
     const void* code_addr, jint map_length, const jvmtiAddrLocationMap* map, 
     const void* compile_info) { 
    jvmtiError err; 
    jclass klass; 

    char* name = NULL; 
    char* signature = NULL; 
    char* generic_ptr = NULL; 

    err = (*jvmti)->RawMonitorEnter(jvmti, lock); 
    check_jvmti_error(jvmti, err, "raw monitor enter"); 

    err = (*jvmti)->GetMethodName(jvmti, method, &name, &signature, 
      &generic_ptr); 
    check_jvmti_error(jvmti, err, "Get Method Name"); 

    printf("\nCompiled method load event\n"); 
    printf("Method name %s %s %s\n\n", name, signature, 
      generic_ptr == NULL ? "" : generic_ptr); 

    if (strstr(name, "main") != NULL && x == 1) { 
     x++; 
     err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &klass); 
     check_jvmti_error(jvmti, err, "Get Declaring Class"); 

     err = (*jvmti)->RetransformClasses(jvmti, 1, &klass); 
     check_jvmti_error(jvmti, err, "Retransform class"); 

    } 

    if (name != NULL) { 
     err = (*jvmti)->Deallocate(jvmti, (unsigned char*) name); 
     check_jvmti_error(jvmti, err, "deallocate name"); 
    } 
    if (signature != NULL) { 
     err = (*jvmti)->Deallocate(jvmti, (unsigned char*) signature); 
     check_jvmti_error(jvmti, err, "deallocate signature"); 
    } 
    if (generic_ptr != NULL) { 
     err = (*jvmti)->Deallocate(jvmti, (unsigned char*) generic_ptr); 
     check_jvmti_error(jvmti, err, "deallocate generic_ptr"); 
    } 

    err = (*jvmti)->RawMonitorExit(jvmti, lock); 
    check_jvmti_error(jvmti, err, "raw monitor exit"); 
} 
+0

Ну, ретрансформация не из дешевых. Выполняете ли вы код выше для всех скомпилированных методов?'CompiledMethodLoad' вызывается для горячих методов, которые сильно влияют на время выполнения, и, ретранслируя их классы, вы 1) платите стоимость воссоздания класса 2) бросаете скомпилированные методы, эффективно заставляя VM выполнять горячие методы в интерпретаторе –

+0

Я просто переформатирование одного файла класса и он содержит только один метод. Это не должно быть дорого. Нет никакого сравнения между «0,8 секунды» и «15» секунд. Это не похоже на стоимость. Более того, даже если программа запускается в интерпретаторе, из-за режима «TieredCompilation», он должен снова вернуться в скомпилированный режим. Поправьте меня если я ошибаюсь. \\ На самом деле я хочу использовать только «горячие» методы. Есть ли способ использовать JIT даже после повторного преобразования? –

+0

Я ожидаю некоторую частичную ситуацию с мертвой блокировкой. [Тупик агента JVMTI] (http://stackoverflow.com/questions/12291756/jvmti-agent-deadlock) –

ответ

0

Чтобы ответ мой вопрос:

Нет, я не делал ничего плохого. Предполагается, что это займет много времени.

И вот доказательство:

Я использовал Jitwatch, чтобы получить некоторое представление в этой проблеме. Я профилировал как ClassLoad измерительные приборы времени, так и инструменты после вызова JIT. Я использую тот же код приложения в обоих случаях.

Класс Время загрузки Инструментарий

JIT invocation during class load time

Время выполнения: 18 секунд ок.

Инструментарий Во время вызова JIT

JIT invocation during instrumentation after JIT is invoked

Время выполнения: 80 секунд ок.

Заключение

Мы ясно видим, что, когда я пытаюсь инструмент моего кода, вызывая RetransformClasses ->CLassFileLoadHook последовательности в CompiledLoadEvent, JIT просто останавливается, а затем никогда не будет вызываться для функции Я попытался инструмент. После этого компиляции OSR даже не компилируются. Я подытожил причину такого поведения JIT в этом answer. Следующий вопрос задан here. Кто-нибудь, кто знает обходное решение, с удовольствием ответит.