@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

JVMPIについて

投稿者投稿内容
がっさん
常連さん
会議室デビュー日: 2003/10/03
投稿数: 24
投稿日時: 2003-10-23 17:35
引用:

ちいにぃさんの書き込み (2003-10-23 14:38) より:
1) とりあえず、myprofiler.logを絶対パスで固定してみましょう。
たとえばこんなふうに。
fp = fopen("c:\myprofiler.log", "w");

2) Tomcat 4を「サービスとして起動」しているなら、
JavaVMへのオプションはサービスのレジストリにあります。
KEY_LOCAL_MACHINESYSTEMCurrentControlSetServices 以下を
探してみてください。




1) 絶対パス指定で実行してみましたがファイルが生成されませんでした。
  
2) こちらのほうは、ちょっと分かりませんでした。




_________________
学生
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2003-10-23 23:01
引用:

引用:
ちいにぃさんの書き込み (2003-10-23 14:38) より:
1) とりあえず、myprofiler.logを絶対パスで固定してみましょう。
たとえばこんなふうに。
fp = fopen("c:\myprofiler.log", "w");

2) Tomcat 4を「サービスとして起動」しているなら、
JavaVMへのオプションはサービスのレジストリにあります。
KEY_LOCAL_MACHINESYSTEMCurrentControlSetServices 以下を
探してみてください。


1) 絶対パス指定で実行してみましたがファイルが生成されませんでした。
  
2) こちらのほうは、ちょっと分かりませんでした。


1) ¥ は2つ必要です。
  つまり、"c:\myprofiler.log"ではなく、"c:\\myprofiler.log"なのですが、
  実際のコードではそのように記述していますか?

2) 「ちょっとわからない」と言われると答えようがないですよ‥‥。
  Tomcat4をどのようにして起動していますか?

  a) OSを起動するとTomcat4が勝手に起動する。(=サービスとして起動)
  b) スタートボタンから「Start Tomcat」で起動している。
  c) catalina.bat か startup.bat を実行している。
  d) その他(eclipse + Tomcat pluginから起動しているとか)

  a) であれば、レジストリをregeditで書き換える必要があります。
   a1) レジストリ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Apache Tomcat 4.1\Parameterを開く。
   a2) 文字列型の項目"JVM Option Number 3"を作り、-Xrunmyprofilerと書く。
   a3) 既存の項目"JVM Option Count"の要素数を増やす(4にする)
   a4) レジストリエディタを閉じ、Tomcatサービスを再起動する。
   
  b) であれば、Start Tomcatショートカットのリンク先の内容に
   -Xrunmyprofilerを追加する。
    (場所は-jarの直前がいいでしょう)

  c) であれば、環境変数CATALINA_OPTSに-Xrunmyprofilerをセットするか、
    setenv.batを作成しCATALINA_OPTSをセットする行を記入する。

・Tomcat4のJavaVMに対して-Xrunmyprofilerが効いている場合、
myprofiler.dllが見つからないときはTomcatが起動しません。
よって、いったんmyprofiler.dllを消してからTomcatを起動し、
Tomcatが起動しなくなることを確認してみるとよいかも。

以上は sun J2SDK 1.4.1_04、
Tomcat 4.1.27-LE (jakarta-tomcat-4.1.27-LE-jdk14.exe + 4.1.27-hotfix-22096.zip)
で確認しました。


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

ちいにぃさんの書き込み (2003-10-23 23:01) より:
1) ¥ は2つ必要です。
  つまり、"c:myprofiler.log"ではなく、"c:\myprofiler.log"なのですが、
  実際のコードではそのように記述していますか?

2)
  a) OSを起動するとTomcat4が勝手に起動する。(=サービスとして起動)
  b) スタートボタンから「Start Tomcat」で起動している。
  c) catalina.bat か startup.bat を実行している。
  d) その他(eclipse + Tomcat pluginから起動しているとか)

  a) であれば、レジストリをregeditで書き換える必要があります。
   a1) レジストリ HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesApache Tomcat 4.1Parameterを開く。
   a2) 文字列型の項目"JVM Option Number 3"を作り、-Xrunmyprofilerと書く。
   a3) 既存の項目"JVM Option Count"の要素数を増やす(4にする)
   a4) レジストリエディタを閉じ、Tomcatサービスを再起動する。
   
  b) であれば、Start Tomcatショートカットのリンク先の内容に
   -Xrunmyprofilerを追加する。
    (場所は-jarの直前がいいでしょう)

  c) であれば、環境変数CATALINA_OPTSに-Xrunmyprofilerをセットするか、
    (未確認ですが)setenv.batを作成しCATALINA_OPTSをセットする行を記入する。

・Tomcat4のJavaVMに対して-Xrunmyprofilerが効いている場合、
myprofiler.dllが見つからないときはTomcatが起動しません。
よって、いったんmyprofiler.dllを消してからTomcatを起動し、
Tomcatが起動しなくなることを確認してみるとよいかも。




いつもお世話になっています。
サービスとして起動はしていませんでした。(知識が乏しいためすみません。)

c)の方法で環境変数CATALINA_OPTSに-Xrunmyprofilerを設定し
Tomcatを起動したところ、myprofiler.logファイルを作成することができました。
でも、Tomcatを起動した段階で作成されているみたいです。(1300行くらい)

Webブラウザからサーブレットを実行した時に初めてmyprofiler.logに
情報を取得したいのですが、Tomcatを起動した段階でファイルが作成される
ということは、Tomcatがロードされる経緯が取得されてしまった
ということなのでしょうか。(うーん・・)

Tomcatが立ち上がってる状態でHelloWorldExampleを実行したところ
ログは取れてないみたいなのですが、Tomcatをシャットダウンした後に
myprofiler.logの中身を見てみるとHelloWorldExampleが呼ばれた経緯が
採取されていました。(どういうことなのでしょう・・)

あと、myprofiler.dllを消してからTomcatを起動し、
Tomcatが起動しなくなることは確認してしてみました。




_________________
学生

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

[ メッセージ編集済み 編集者: がっさん 編集日時 2003-10-24 15:26 ]
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2003-10-24 15:56
こんにちは、さくらばです。

引用:

がっさんさんの書き込み (2003-10-24 15:10) より:

c)の方法で環境変数CATALINA_OPTSに-Xrunmyprofilerを設定し
Tomcatを起動したところ、myprofiler.logファイルを作成することができました。
でも、Tomcatを起動した段階で作成されているみたいです。(1300行くらい)

Webブラウザからサーブレットを実行した時に初めてmyprofiler.logに
情報を取得したいのですが、Tomcatを起動した段階でファイルが作成される
ということは、Tomcatがロードされる経緯が取得されてしまった
ということなのでしょうか。(うーん・・)




そりゃそうです
サーブレットが実行されたときからプロファイリングを開始するのであれば、
JVMPI_EVENT_CLASS_LOAD イベントでプロファイルしたいサーブレットのクラスが
ロードされるのを待つようにして、ロードされたらファイルをオープンするように
したらどうでしょう。

# 一度ロードされるとずっとファイルに書き出してしまいますが...
# アンロードはそんなにされないし...

コード:
void notifyEvent(JVMPI_Event *event) {
    switch(event->event_type) {
      case JVMPI_EVENT_CLASS_LOAD: 
        jvmpi_interface->RawMonitorEnter(data_access_lock); 

        if (strcmp(event->u.class_load.class_name, servletname) == 0) {
	    fp = fopen(logfile, "w");
        }
        jvmpi_interface->RawMonitorExit(data_access_lock);
        return;

      case JVMPI_EVENT_GC_FINISH:
        jvmpi_interface->RawMonitorEnter(data_access_lock); 
        if (fp != NULL) {
            fprintf(fp, "GC: used obj %d used obj space %d total obj size: %d\n",
	            event->u.gc_info.used_objects,
	            event->u.gc_info.used_object_space);
	            event->u.gc_info.total_object_space);
        }
        jvmpi_interface->RawMonitorExit(data_access_lock);
        return;
    }                       
}



JVMPI_EVENT_OBJECT_ALLOC で監視していてもいいのですが、こちらはクラスの ID しか
参照できません。そのため、JVMPI_EVENT_CLASS_LOAD が呼ばれたときにクラス ID と
名前のテーブルを作っておいて、JVMPI_EVENT_OBJCET_ALLOC が呼ばれたときはこのテー
ブルから名前を取り出すようにします。

たまに JVMPI_EVENT_CLASS_LOAD が抜けたりするんです。そのときは RequestEvent を
使ってリクエストしなくてはいけないのですが、めんどうですね


引用:

Tomcatが立ち上がってる状態でHelloWorldExampleを実行したところ
ログは取れてないみたいなのですが、Tomcatをシャットダウンした後に
myprofiler.logの中身を見てみるとHelloWorldExampleが呼ばれた経緯が
採取されていました。(どういうことなのでしょう・・)



バッファにたまっていたのではないかと。fflush してみたらどうですか。
がっさん
常連さん
会議室デビュー日: 2003/10/03
投稿数: 24
投稿日時: 2003-10-27 17:18
いつもご丁寧にありがとうございます。

引用:

さくらばさんの書き込み (2003-10-24 15:56) より:

サーブレットが実行されたときからプロファイリングを開始するのであれば、
JVMPI_EVENT_CLASS_LOAD イベントでプロファイルしたいサーブレットのクラスが
ロードされるのを待つようにして、ロードされたらファイルをオープンするように
したらどうでしょう。




さくらばさんのおっしゃる通り、イベントを判断する部分で
以下のようにしたところ実行後のログのみ取ることができました。
(Tomcatシャットダウン後にしかログを見ることができないのですが・・)

コード:

switch(event->event_type) {
  case JVMPI_EVENT_CLASS_LOAD:
    if(strcmp(event->u.class_load.class_name, servletname) == 0) {
      fp = fopen("C:\\c_c++\\myprofiler.log", "w");
      flag = 1;
    }
    
    if(flag != 0)
      notifyClassLoad(event);
    break;





引用:

JVMPI_EVENT_OBJECT_ALLOC で監視していてもいいのですが、こちらはクラスの ID しか
参照できません。そのため、JVMPI_EVENT_CLASS_LOAD が呼ばれたときにクラス ID と
名前のテーブルを作っておいて、JVMPI_EVENT_OBJCET_ALLOC が呼ばれたときはこのテー
ブルから名前を取り出すようにします。

たまに JVMPI_EVENT_CLASS_LOAD が抜けたりするんです。そのときは RequestEvent を
使ってリクエストしなくてはいけないのですが、めんどうですね



JVMPIについて勉強し始めたばかりもあるのですが、私はまだまだ勉強不足ですね。
リファレンスを読んでみます。


_________________
学生
がっさん
常連さん
会議室デビュー日: 2003/10/03
投稿数: 24
投稿日時: 2003-10-28 12:15
こんにちは、いつもお世話になっています。

すみませんがまた質問があります。
Sun MicrosystemsのJVMPIのリファレンスに出てくるコードを試したのですが
EXCEPTION_ACCESS_VIOLATIONというエラーログが生成されてしまいます。
ネットでも検索してみたのですが、良い例が見つかりませんでした。
コード、エラーの詳細、デバックプリントの結果は以下のようになっています。

[環境]
Windows2000 Professional
MinGwコンパイラ
jdk1.4.1

(profileTest1.cpp)
コード:
#include <jvmpi.h>
#include <jni.h>
#include <stdlib.h>

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

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

/* スレッド開始イベント */
void ThreadStartHandler(JNIEnv *thread_id)
{
  fprintf(stderr, "bbb\n");
  int *p_ctr = (int *)malloc(sizeof(int));
  *p_ctr = 0;
  
  CALL(SetThreadLocalStorage)(thread_id, p_ctr);
}

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

/* スレッド終了イベント */
void ThreadEndHandler(JNIEnv *thread_id)
{
  int *p_ctr = (int *)CALL(GetThreadLocalStorage)(thread_id);
  fprintf(stderr, "Thread %x executed %d method\n", thread_id, (*p_ctr));
  
  free(p_ctr);
}

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

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

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

/* プロファイラエージェントエントリーポイント */
extern "C"
{

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

    fprintf(stderr, "ccc\n");
    /* イベントコールバック関数の登録 */
    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;
  }
}



ここで、 java -XrunprofileTest1 クラス名
とすると

------------------------- エラーログ -----------------------------------
ddd
ccc
aaa

An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION occurred at PC=0x6AF81214
Function=[Unknown.]
Library=C:\c_c++\profileTest1.dll

NOTE: We are unable to locate the function name symbol for the error
just occurred. Please refer to release documentation for possible
reason and solutions.


Current Java thread:
at java.lang.Thread.<init>(Unknown Source)

Dynamic libraries:
0x00400000 - 0x00406000 C:\WINNT\system32\java.exe
:
:
:
:

Local Time = Tue Oct 28 11:43:22 2003
Elapsed Time = 1
#
# The exception above was detected in native code outside the VM
#
# Java VM: Java HotSpot(TM) Client VM (1.4.1_01-b01 mixed mode)
#
----------------------------------------------------------------------

多分、デバックプリントの結果が
ddd
ccc
bbb
aaa
なると思うのですが、実際は
ddd
ccc
aaa
となっています。

よろしくお願いします。。



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

WinXP Prof, J2SE 1.4.2_02, VC++ 7.0 で行った場合はちゃんと動作しましたよ。

引用:

がっさんさんの書き込み (2003-10-28 12:15) より:

(profileTest1.cpp)
コード:

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





bbb がコールされていないということは、まだ p_ctr が malloc されて
いないので NULL のままであろうと予測できます。

NULL チェックを入れれば動作するのではないでしょうか。

それにしても JVMPI_EVENT_THREAD_START イベントが発生しないのは
よく分からないですね。

# 結構イベントが抜けることがあるんですが、なぜなんでしょう ????
# 私も理由をしりたいです
がっさん
常連さん
会議室デビュー日: 2003/10/03
投稿数: 24
投稿日時: 2003-10-28 17:11
引用:

さくらばさんの書き込み (2003-10-28 14:53) より:
こんにちは、さくらばです。

WinXP Prof, J2SE 1.4.2_02, VC++ 7.0 で行った場合はちゃんと動作しましたよ。



そうなんですかぁ。

引用:

bbb がコールされていないということは、まだ p_ctr が malloc されて
いないので NULL のままであろうと予測できます。

NULL チェックを入れれば動作するのではないでしょうか。

それにしても JVMPI_EVENT_THREAD_START イベントが発生しないのは
よく分からないですね。



JVMPI_EVENT_THREAD_START が呼ばれていない時点で
p_ctrポインタ変数が指し示す領域が確保されていないので、
NULLになるのは当然ですね。

でも、NULLチェックを入れて正常に動作する方法はどのようにするのでしょうか。
スレッド開始イベントが呼ばれていないわけなので、メソッド開始イベントの部分で
NULLチェックをするのでしょうか。


_________________
学生

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