- PR -

JVMPIについて

投稿者投稿内容
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2003-10-28 18:12
J2SDK1.4.1_05、Cygwin g++ (GCC) 3.3.1 (cygming special) では
「がっさん」さんと同じように、エラーがでました。

でMethodEntryHandlerでp_ctrがNULLのときは確保するようにしたところ、
動作するようになりました。

コード:

/* メソッド開始イベント */
void MethodEntryHandler(jmethodID method_id, JNIEnv *thread_id)
{
fprintf(stderr, "aaa\n");
int *p_ctr = (int *)CALL(GetThreadLocalStorage)(thread_id);
if (!p_ctr) {
p_ctr = (int *)malloc(sizeof(int));
*p_ctr = 0;
CALL(SetThreadLocalStorage)(thread_id, p_ctr);
}
(*p_ctr)++;
}



で、これをJ2SDK1.4.1_05のヘッダ + Cygwin g++ (GCC) 3.3.1 (cygming special) で
コンパイルして、WindowsXP Pro上のJ2SDK1.4.2_02, 1.4.1_05, 1.3.1_09で
試してみましたら、各イベントは次の順序で呼ばれていました。

1.3.1_09: ddd ccc aaa ...(aaaが連続) ... bbb ...
1.4.1_05: ddd ccc aaa ...(aaaが連続) ... bbb ...
1.4.2_02: ddd ccc aaa bbb aaa ... (aaaが連続)

【2003/10/31修正】
J2SDK 1.4.2_02 では、簡単なプログラム(HelloWorld.java)で確認する限り
thread_idを表示して確認したところ、以下のように
期待した順序 (THREAD_START→METHOD_ENTRY) で呼ばれていました。

ddd
ccc
bbb thread_id='009F04D0'
bbb thread_id='009EF0A0'
bbb thread_id='000352D8'
aaa thread_id='000352D8'


[ メッセージ編集済み 編集者: ちいにぃ 編集日時 2003-10-30 12:50 ]
がっさん
常連さん
会議室デビュー日: 2003/10/03
投稿数: 24
投稿日時: 2003-10-28 18:37
引用:

ちいにぃさんの書き込み (2003-10-28 18:12) より:
とりあえず、p_ctrがNULLのときは確保するようにしてみました。

コード:

/* メソッド開始イベント */
void MethodEntryHandler(jmethodID method_id, JNIEnv *thread_id)
{
fprintf(stderr, "aaan");
int *p_ctr = (int *)CALL(GetThreadLocalStorage)(thread_id);
if (!p_ctr) {
p_ctr = (int *)malloc(sizeof(int));
*p_ctr = 0;
CALL(SetThreadLocalStorage)(thread_id, p_ctr);
}
(*p_ctr)++;
}






ご返答ありがとうございます。

私も同じように考えました。
やはり、スレッド開始メソッドが呼ばれなかった時の処置としてその方法しかないのでしょうか。
#さくらばさんの言う通り、なぜ呼ばれないイベントが出てきてしまうのでしょう。。




_________________
学生

[ メッセージ編集済み 編集者: がっさん 編集日時 2003-10-28 18:44 ]
がっさん
常連さん
会議室デビュー日: 2003/10/03
投稿数: 24
投稿日時: 2003-10-30 19:39
引用:

ちいにぃさんの書き込み (2003-10-28 18:12) より:

【2003/10/31修正】
J2SDK 1.4.2_02 では、簡単なプログラム(HelloWorld.java)で確認する限り
thread_idを表示して確認したところ、以下のように
期待した順序 (THREAD_START→METHOD_ENTRY) で呼ばれていました。

ddd
ccc
bbb thread_id='009F04D0'
bbb thread_id='009EF0A0'
bbb thread_id='000352D8'
aaa thread_id='000352D8'



ご親切にありがとうございます。
私もjdk1.4.2で試したところ、ちいにぃさんのようにスレッドのイベントが
きちんと呼び出されていました。

しかし、私の場合mainのスレッドの中で呼び出されたメソッドの回数を表示したところで
前に述べたようなエラーログが生成されてしまいました。

以下のようなエラーログです。

ddd
ccc
bbb
bbb
bbb
bbb
Hello, World!
Thread 285a40 executed 4705 method

An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION (0xc0000005) occurred at PC=0x64C
C11F5
Function=[Unknown.]





mainスレッドの中で呼び出されたメソッドの回数はうまくいっていますが、
その他のスレッドの部分でエラーが出ているみたいです。



_________________
学生

[ メッセージ編集済み 編集者: がっさん 編集日時 2003-10-30 19:42 ]
がっさん
常連さん
会議室デビュー日: 2003/10/03
投稿数: 24
投稿日時: 2003-11-05 13:44
こんにちは、お世話になっています。

今まで、MinGWというWindows用のGCCコンパイラを使用していたのですが、
他のツールでも試してみたいと思い、VC++5.0 Pro をインストールしました。
しかし、Makefileを用いたコンパイルの仕方がどうもよく分かりません。

コマンドライン上でnmakeと打ったところ、(ファイル名:myprofiler.cpp)
NMAKE : fatal error U1073: '.myprofiler.cpp' のビルド方法が指定されていません。
とエラーが返ってきました。

コマンドライン上で実行する事自体間違っているのでしょうか。
ご指導のほどよろしくお願いします。

_________________
学生
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2003-11-06 15:49
こんにちは、さくらばです。

引用:

がっさんさんの書き込み (2003-11-05 13:44) より:
しかし、Makefileを用いたコンパイルの仕方がどうもよく分かりません。

コマンドライン上でnmakeと打ったところ、(ファイル名:myprofiler.cpp)
NMAKE : fatal error U1073: '.myprofiler.cpp' のビルド方法が指定されていません。
とエラーが返ってきました。

コマンドライン上で実行する事自体間違っているのでしょうか。



わたしはコマンドラインでも使っています。Makefile はがっさんさんが
一番はじめに示された Makefile とほぼ同じものを使っています
(ディレクトリが違うぐらい)。いちおう載せておきますけど、情報量は
無いに等しいですね

コード:
JDK_HOME = c:\progra~1\j2sdk1.4.2
LIB_DIR = $(JDK_HOME)\lib

INCLUDES = -I. -I$(JDK_HOME)\include -I$(JDK_HOME)\include\win32

SRC_DIR = .

all: myprofiler.dll

myprofiler.dll: $(SRC_DIR)\myprofiler.cpp
        cl -LDd -Zi -Zp1 $(INCLUDES) -Tp$(SRC_DIR)\myprofiler.cpp -o $@ /link /libpath:$(LIB_DIR) jvm.lib

raccoon
ベテラン
会議室デビュー日: 2002/12/18
投稿数: 58
投稿日時: 2003-11-06 20:47
ども。役に立たないかも知れませんが・・・

引用:

がっさんさんの書き込み (2003-11-05 13:44) より:
NMAKE : fatal error U1073: '.myprofiler.cpp' のビルド方法が指定されていません。
とエラーが返ってきました。

コマンドライン上で実行する事自体間違っているのでしょうか。



コマンドラインで実行すること自体は別に間違っていません。

このメッセージで'.\myprofiler.cpp'とか'myprofiler.cpp'と
表示されているのなら,普通はファイル名が違うとか,または
nmakeを実行するディレクトリが違うことが考えられます。

でも今回の場合は'.myprofiler.cpp'と表示されているんですね?
この表示ならばnmakeコマンドは,'.\myprofiler.cpp'ではなく
'.myprofiler.cpp'というファイルを探そうとしていることになります。

この場合は,makefile中で
myprofiler.dll : $(SRC_DIR)\myprofiler.cpp
と書くべきところが
myprofiler.dll : $(SRC_DIR)myprofiler.cpp
になっているというのがありがちです。
(ビミョーな違いでわかりにくいかも知れませんが)

でも,同じmakefileでもMinGWでは成功しているんですよね?
ならばmakefileは間違っていないのか・・・

ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2003-11-07 00:22
引用:

がっさんさんの書き込み (2003-11-05 13:44) より:
NMAKE : fatal error U1073: '.myprofiler.cpp' のビルド方法が指定されていません。
とエラーが返ってきました。



nmakeの実行時のカレントディレクトリに myprofiler.cppが存在していますか?

たとえば、次のMakefileでは、a.cppが存在しない場合、同様のエラーがでます。
コード:
all : a.cpp
	echo "compile"


がっさん
常連さん
会議室デビュー日: 2003/10/03
投稿数: 24
投稿日時: 2003-11-07 18:08
こんにちは。

Visual C++の件に関してご返答ありがとうございます。
オプションの設定により、ツール上からもできました。
お騒がせしてすいません。

今、以下のようなソース(myprofiler.cpp)を作り、CATALINA_OPTSの設定により
Tomcatに付属しているHelloWorldExampleを実行してみました。
ソースの結果は以下です。

コード:

#include <jvmpi.h>
#include <jni.h>
#include <string.h>
#include <stdlib.h>

/****************** スレッドの情報を保持する構造体 *******************/
typedef struct thread_storage
{
jint call; /* メソッドが呼ばれた回数 */
jlong time; /* スレッドの実行時間 */
jlong start; /* スレッドの開始時間 */

} ThreadStorage;

/***************** jvmpiインタフェース型のポインタ *******************/
JVMPI_Interface *jvmpi_interface;
#define CALL(f) (jvmpi_interface->f)

/********************* データアクセスロック用 ************************/
JVMPI_RawMonitor data_access_lock;

/*********************** グローバル変数 ******************************/
FILE *fp;
JNIEnv *ThreadID[1000];
int thread_count = 0;

/********************** スレッド開始イベント *************************/
void notifyThreadStart(JNIEnv *env_id, jobjectID thread_id, char *thread_name)
{
int i;
ThreadStorage *info;

/* 同じIDのスレッドの時は終了 */
for(i=0; i<thread_count; i++) {
if(ThreadID[i] == env_id)
return;
}

fprintf(fp, "thread start %x(env_id), %s(thread_name)\n", env_id, thread_name);

info = (ThreadStorage *)malloc(sizeof(ThreadStorage));
info->call = 0;
info->time = (jlong)0;
info->start = CALL(GetCurrentThreadCpuTime)();

CALL(SetThreadLocalStorage)(env_id, info);
}

/********************* メソッド開始イベント ***************************/
void notifyMethodEntry(jmethodID method_id, JNIEnv *env_id)
{
int i;
ThreadStorage *info;

/* 同じIDのスレッドの時は終了 */
for(i=0; i<thread_count; i++) {
if(ThreadID[i] == env_id)
return;
}

info = (ThreadStorage *)CALL(GetThreadLocalStorage)(env_id);
info->call++;
info->time = (CALL(GetCurrentThreadCpuTime)() - info->start);


}

/********************** スレッド終了イベント **************************/
void notifyThreadEnd(JNIEnv *env_id)
{
int i;
ThreadStorage *info;

/* 同じIDのスレッドの時は終了 */
for(i=0; i<thread_count; i++) {
if(ThreadID[i] == env_id)
return;
}

info= (ThreadStorage *)CALL(GetThreadLocalStorage)(env_id);

fprintf(fp, "Thread %x executed %d method\n", env_id, info->call);
fprintf(fp, "Thread %x execution time %f\n", env_id, (float)info->time/1000000000.0);

/* スレッドIDの登録 */
ThreadID[thread_count++] = env_id;

free(info);
}


/********************** イベントハンドリング関数 **************************/
void notifyEvent(JVMPI_Event *event)
{
switch(event->event_type) {
case JVMPI_EVENT_THREAD_START:
CALL(RawMonitorEnter)(data_access_lock);
notifyThreadStart(event->u.thread_start.thread_env_id, event->u.thread_start.thread_id, event->u.thread_start.thread_name);
CALL(RawMonitorExit)(data_access_lock);
break;

case JVMPI_EVENT_METHOD_ENTRY:
CALL(RawMonitorEnter)(data_access_lock);
notifyMethodEntry(event->u.method.method_id, event->env_id);
CALL(RawMonitorEnter)(data_access_lock);
break;

case JVMPI_EVENT_THREAD_END:
CALL(RawMonitorEnter)(data_access_lock);
notifyThreadEnd(event->env_id);
CALL(RawMonitorExit)(data_access_lock);
break;
}
}

extern "C"
{

/*************** プロファイラエージェントエントリーポイント *****************/
JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved)
{

/* jvmpiのポインタの取得 */
if ((jvm->GetEnv((void **)&jvmpi_interface, JVMPI_VERSION_1)) < 0) {
fprintf(stderr, "error in obtaining jvmpi interface pointer\n");
return JNI_ERR;
}

fp = fopen("C:\\jvmpi\\myprofiler.log", "w");

/* イベントコールバック関数の登録 */
jvmpi_interface->NotifyEvent = notifyEvent;

/* イベントの設定 */
jvmpi_interface->EnableEvent(JVMPI_EVENT_THREAD_START, NULL);
jvmpi_interface->EnableEvent(JVMPI_EVENT_METHOD_ENTRY, NULL);
jvmpi_interface->EnableEvent(JVMPI_EVENT_THREAD_END, NULL);

return JNI_OK;
}
}



--------------------------------結果---------------------------------------
thread start 805a48(env_id), Finalizer(thread_name)
thread start 8046e0(env_id), Reference Handler(thread_name)
thread start 286208(env_id), main(thread_name)
thread start 8b9f30(env_id), Signal Dispatcher(thread_name)
thread start 1831a390(env_id), WebappLoader[/examples](thread_name)
thread start 182a9930(env_id), StandardManager[/examples](thread_name)
thread start 182ace80(env_id), StandardManager[/admin](thread_name)
thread start 186ba0a0(env_id), StandardManager[/manager](thread_name)
thread start 18347858(env_id), StandardManager[](thread_name)
thread start 182e7b80(env_id), StandardManager[/tomcat-docs](thread_name)
thread start 182b3320(env_id), StandardManager[/webdav](thread_name)
thread start 182b3628(env_id), HostConfig[localhost](thread_name)
thread start 186810a0(env_id), Thread-2(thread_name)
thread start 182b4250(env_id), Thread-3(thread_name)
thread start 182b4c50(env_id), Thread-4(thread_name)
thread start 18674990(env_id), Thread-5(thread_name)
thread start 18354248(env_id), MonitorRunnable(thread_name)
thread start 18356cd0(env_id), Thread-10(thread_name)
thread start 182d26f0(env_id), Thread-9(thread_name)
thread start 182d24d0(env_id), Thread-8(thread_name)
thread start 185931e8(env_id), Thread-7(thread_name)
thread start 182e3848(env_id), MonitorRunnable(thread_name)
Thread 18354248 executed 6 method
Thread 18354248 execution time 0.000000
Thread 186810a0 executed 17 method
Thread 186810a0 execution time 0.000000
Thread 182b4c50 executed 235 method
Thread 182b4c50 execution time 0.000000
Thread 182e3848 executed 6 method
Thread 182e3848 execution time 0.000000
Thread 185931e8 executed 17 method
Thread 185931e8 execution time 0.000000
Thread 182d24d0 executed 17 method
Thread 182d24d0 execution time 0.000000
Thread 18356cd0 executed 124 method
Thread 18356cd0 execution time 0.000000
Thread 182b3628 executed 5794 method
Thread 182b3628 execution time 0.015625
Thread 182ace80 executed 25 method
Thread 182ace80 execution time 0.000000
Thread 182b3320 executed 25 method
Thread 182b3320 execution time 0.000000
Thread 182a9930 executed 25 method
Thread 182a9930 execution time 0.000000
Thread 1831a390 executed 8574 method
Thread 1831a390 execution time 0.000000
Thread 182e7b80 executed 25 method
Thread 182e7b80 execution time 0.000000
Thread 18347858 executed 25 method
Thread 18347858 execution time 0.000000
Thread 186ba0a0 executed 25 method
Thread 186ba0a0 execution time 0.000000
Thread 286208 executed 13829231 method
Thread 286208 execution time 17.718750
---------------------------------------------------------------------------

ここで質問なのですが、最初のスレッドの呼び出しでmainが呼び出されていますが
これはHelloWorldExampleを実行する際のmainでよろしいのでしょうか。
(解釈が間違っているかもしれません)
よろしくお願いします。




_________________
学生

[ メッセージ編集済み 編集者: がっさん 編集日時 2003-11-07 18:12 ]

[ メッセージ編集済み 編集者: がっさん 編集日時 2003-11-07 18:15 ]

スキルアップ/キャリアアップ(JOB@IT)