全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1720
推到 Plurk!
推到 Facebook!

利用Java配合BCB 4.0製作CPU特徵偵測器

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-02-14 11:48:03 IP:61.221.xxx.xxx 未訂閱
利用Java配合BCB 4.0製作CPU特徵偵測器 http://edu.uuu.com.tw/article/010307b.htm  利用Java配合BCB 4.0製作CPU特徵偵測器    作者: 恆逸資訊 王森    筆者最近從事一個利用Java來發展密碼模組的工作,由於利用純Java語言所製作出來的密碼模組效率實在不好,最後我們把腦筋動到JNI(Java Native Interface)上. 為何會想到使用JNI呢? 大家應該都知道Java程式的執行必須透過Java Virtual Machine,透過一層仲介的結果,執行的效率必然比C/C++所編譯出來的原生碼(native code,即專屬各處理器的指令集)還要慢. 事實上,在JDK內附的java.math 這個package裡頭,許多部分也都應用了JNI來加快運算速度(例如Big Integer運算)。     硬體優勢    一旦利用的JNI,代表我們將能夠連結C/C++或是Assembly所撰寫的加密模組. 為了加快密碼模組的performance,必須運用一些硬體上的優勢,例如說當處理區塊加密運算時,如果能運用一點並行處理的觀念,就能夠適當地加快運算速度. 以目前的PC上的處理器來說,支援平行處理能力的技術就屬大家所熟知的MMX, Streaming SIMD Extension(大家也許比較熟悉的是KNI這個名詞),以及3DNOW!. 這些技術其實就是實做了SIMD(Single-Instruction, Multiple-Data)的概念,允許處理器在同一時間之內,使用單一指令,就可以同時處理好幾組資料。   另外,在Pentium等級以上的CPU具有利用Pipeline來加快執行速度的能力,只要調整Assembly code的排列順序,使其符合Intel Scheduling Rules,就可以充分利用CPU裡頭的U-pipe與V-pipe,加快執行速度. 其實,就筆者所使用的Visual C++ 6.0與Borland C++ Builder 4.0來說,雖然都有編譯器指令可以針對處理器做最佳化,但是如果您親自去看看編譯出來的結果,能然有很多地方無法盡如人意,因此如果遇到time critical的部分,仍然常常需要我們親自去調校以改善performance。    準備工作及注意事項    Ok,講到這邊,似乎離主題有點遠了,讓我們回歸正題吧! 為了讓我們可以在執行時期動態地依照CPU的能力來執行最佳化的程式碼,首要的工作就是要寫一些函式來偵測CPU的特性,於是筆者選擇了JDK 1.2以及BCB 4.0來完成整個由   Java code ---> JNI ---> Platform native code  的完整測試程式,如果以圖片來表示就如下圖:     準備工作及注意事項    Ok,講到這邊,似乎離主題有點遠了,讓我們回歸正題吧! 為了讓我們可以在執行時期動態地依照CPU的能力來執行最佳化的程式碼,首要的工作就是要寫一些函式來偵測CPU的特性,於是筆者選擇了JDK 1.2以及BCB 4.0來完成整個由   Java code ---> JNI ---> Platform native code  的完整測試程式,如果以圖片來表示就如下圖:     如果您抓取了筆者提供的原始碼,應該可以看到下面三個分別由Java與C++撰寫的程式模組:  CPUTestDll.bpr CPUTestDll.cpp  實做偵測CPU特性相關函式的模組 此為BCB 4.0之 專案檔,使用Project/make cputest的指令後,所產生的結果cputest.dll,是我們所要的。 編譯注意事項 :    由於在CPUTestDll.cpp裡頭我們用到組合語言指令CPUID,所以請打開Project/Option裡頭的Advanced Compiler次頁,裡頭有一個叫Instruction Set的地方,請勾選Pentium,否則編譯器會因為不支援此指令而產生編譯錯誤.如果您要把編譯過的結果給別人使用,建議您將Project/Option/Package次頁中的Build with Run-time Package選項 以及 Linker次頁中的Use Dynamic RTL選項通通取消掉。  請打開Project/Option/Directories Conditionals次頁,將JDK所在目錄\include 與JDK所在目錄\include\win32加到Include path裡頭 ; 另外也在Library Path中加入 JDK所在目錄\lib,否則會造成編譯錯誤。    CPUTest.java 這個Java程式是作為其他Java程式透過JNI以呼叫CPUTestDll.dll的介面. 筆者把 這個介面宣告於my.cpu這個package底下。 編譯注意事項 :  編譯Java程式時,請設定環境變數PATH與CLASSPATH 例如JDK安裝在C:\JDK1.2這個目錄,而此檔案放在c:\jdk1.2\my之下, 那麼請在提示符號下命令 PATH c:\jdk1.2\bin set CLASSPATH=C:\jdk1.2\classes;c:\JDK1.2\my     test.java  這個Java程式將利用CPUTest物件當作介面,來呼叫實做於CPUTestDll.dll內的CPU 特徵偵測函數。 編譯注意事項 :  除了2的注意事項外,請將CPUTest.java放到 < JDK安裝目錄 >\classes\my\cpu這個 目錄之中,否則編譯將無法通過。    參考文件  JDK 1.2 on-line document  Intel Architecture Optimization/Reference manual Order Number: 245127-001  AMD 3DNOW! Technology Manua         用JDK 實做JNI介面    首先,為了讓所有的Java Code都可以使用我們的CPU特徵偵測函數,我們首先必須先製作一個介面類別:   ■ 檔案列表CPUTest.java     
/*********************************************************************
CPUTest.java
JNI 介面物件
1999 April 20 by 王森 *********************************************************************/ 
//加入my.cpu這個package之中
package my.cpu ;     public class CPUTest {     /*以下定義每種處理器所代表的常數*/
static public final int i386 = 0 ; //不支援CPUID的處理器(可辨識) 
static public final int Pentium = 1 ; //最早期的Pentium處理器(可辨識)
static public final int Pentium_M = 2 ; //Pentium with MMX 處理器(可辨識)
static public final int Pentium_2 = 3 ; //Pentium II 處理器(可辨識)
static public final int Pentium_3 = 4 ; //Pentium III處理器(可辨識) 
static public final int Pentium_P = 5 ; //Pentium Pro 處理器(可辨識)
static public final int K6 = 11 ; //同Pentium with MMX 
static public final int K6_2 = 12 ; //K6-2處理器((可辨識)
static public final int K6_3 = 13 ; //同K6-2     /*以下定義所有會藉由JNI來叫用的函式*/ //    測試CPU是否支援CPUID指令,如果支援則傳回true,否則傳回false 
public native boolean CheckCPUID() ; 
^^^^^^ 注意,所有的JNI函式都必須在函式宣告裡加上native這個修飾字     //辨識處理器是否支援MMX,如果支援則傳回true,否則傳回false 
public native boolean CheckMMX() ;     //辨識處理器是否支援Stream SIMD Extension(即KNI),如果支援則傳回true,否則傳回false
public native boolean CheckSSIMD() ;     //辨識處理器是否支援AMD 3DNow,如果支援則傳回true,否則傳回false
public native boolean Check3DNOW() ;    //辨識CPU的等級,並傳回一個整數代表CPU的等級
public native int CheckCPUTYPE() ;    //印出CPU的相關資訊
public native void PrintCPUInfo() ;     note: 使用此函數之前,請先呼叫前面的所有函式, 因為前面的函式,除了傳回真偽之外,也會設定DLL檔之中的全域變數 而PrintCPUInfo會利用這些全域變數來做判定的工作 
static { 
我們把實做CPU偵測函式的模組做成DLL(動態連結函式庫)檔, 取名叫CPUDTestDll.dll,所以在這裡要載入此DLL 
} 
} 
 
接著我們在提示符號下使用指令 javac CPUTest.java 編譯此檔案,會產生CPUTest.class這個檔案. 然後我們把這兩個檔案都移至 < JDK安裝目錄 >/classes/my/cpu/ 這個目錄底下,如果沒有做此動作,恐怕下面的步驟都會遇到一些錯誤. 最後一個步驟,就是必須產生一個引入檔(Include file),我們將會在編譯CPUTestDll.dll實用到這個引入檔. 在提示符號下使用指令 javah my.cpu.CPUTest 就會在您目前的工作目錄下看到 my_cpu_CPUTest.h 到此為止,我們已經完成了第一個階段 ■ 檔案列表my_cpu_CPUTest.h
/* DO NOT EDIT THIS FILE - it is machine generated
*/ #include 
/* 
Header for class my_cpu_CPUTest */     #ifndef _Included_my_cpu_CPUTest
#define _Included_my_cpu_CPUTest
#ifdef __cplusplus
extern "C" {
#endif 
#undef my_cpu_CPUTest_i386
#define my_cpu_CPUTest_i386 0L
#undef my_cpu_CPUTest_Pentium
#define my_cpu_CPUTest_Pentium 1L 
#undef my_cpu_CPUTest_Pentium_M
#define my_cpu_CPUTest_Pentium_M 2L
#undef my_cpu_CPUTest_Pentium_2
#define my_cpu_CPUTest_Pentium_2 3L
#undef my_cpu_CPUTest_Pentium_3 
#define my_cpu_CPUTest_Pentium_3 4L
#undef my_cpu_CPUTest_Pentium_P
#define my_cpu_CPUTest_Pentium_P 5L
#undef my_cpu_CPUTest_K6
#define my_cpu_CPUTest_K6 11L
#undef my_cpu_CPUTest_K6_2
#define my_cpu_CPUTest_K6_2 12L
#undef my_cpu_CPUTest_K6_3
#define my_cpu_CPUTest_K6_3 13L 
/*
* Class: my_cpu_CPUTest
* Method: Check3DNOW 
* Signature: ()Z 
*/ 
JNIEXPORT jboolean JNICALL Java_my_cpu_CPUTest_Check3DNOW (JNIEnv 
*, jobject); 
/*
* Class: my_cpu_CPUTest
* Method: CheckCPUID
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_my_cpu_CPUTest_CheckCPUID (JNIEnv
*, jobject); 
/*
* Class: my_cpu_CPUTest
* Method: CheckCPUTYPE
* Signature: ()I 
*/ 
JNIEXPORT jint JNICALL Java_my_cpu_CPUTest_CheckCPUTYPE (JNIEnv 
*, jobject); 
/*
* Class: my_cpu_CPUTest
* Method: CheckMMX
* Signature: ()Z 
*/
JNIEXPORT jboolean JNICALL Java_my_cpu_CPUTest_CheckMMX (JNIEnv
*, jobject); 
/* 
* Class: my_cpu_CPUTest 
* Method: CheckSSIMD 
* Signature: ()Z
*/ 
JNIEXPORT jboolean JNICALL Java_my_cpu_CPUTest_CheckSSIMD (JNIEnv 
*, jobject); 
/*
* Class: my_cpu_CPUTest
* Method: PrintCPUInfo
* Signature: ()V
*/ 
JNIEXPORT void JNICALL Java_my_cpu_CPUTest_PrintCPUInfo (JNIEnv
*, jobject);     #ifdef __cplusplus
}
#endif
#endif 
 
附帶一提,上面這個檔案完全是使用javah這個JDK內附的程式所產生,我們不要去修改它,以免發生更多意想不到的麻煩 C Builder 4.0實做native端 好,完成了介面部分,接下來就要開始實做部分啦! 首先,請先打開您的BCB 4.0,選擇 File/New裡頭的New次頁中,選擇開啟一個DLL專案檔. 開啟成功後,請將此專案的檔名取名為 CPUTestDll. 您就會在目錄下看到CPUTestDll.bpr與CPUTestDll.cpp兩個檔案,另外,為了讓編譯工作順利,您必須再調校一些編譯器選項,請參照前面準備工作及注意事項. 首先,請在CPUTestDll.cpp裡頭將my_cpu_CPUTest.h這個檔案引入 #include "my_cpu_CPUTest.h" 否則會產生"Undefined Symbol xxxx"的錯誤 完整程式碼如下: ■ 檔案列表CPUTestDll.cpp
#include 
#pragma hdrstop    #include
#include "my_cpu_CPUTest.h"     /*底下定義一些代表CPU的變數
*/ const int i386 = 0 ; //不支援CPUID的處理器(可辨識)     const int Pentium = 1 ; //最早期的Pentium處理器(可辨識) 
const int Pentium_M = 2 ; //Pentium with MMX 處理器(可辨識) 
const int Pentium_2 = 3 ; //Pentium II 處理器(可辨識)
const int Pentium_3 = 4 ; //Pentium III處理器(可辨識)
const int Pentium_P = 5 ; //Pentium Pro 處理器(可辨識)
const int K6 = 11 ; //同Pentium with MMX 
const int K6_2 = 12 ; //K6-2處理器((可辨識) const int K6_3 = 13 ; //同K6-2 
/***************************************************************************/     /*以下定義一些辨識CPU能力的變數
*/ bool CPUID_S = false ; 
//測試是否支援CPUID指令 bool MMX = false ;
//測試是否支援MMX bool SSIMD = false ; 
//測試是否支援Streaming SIMD Extension bool _3DNOW = false ;
//測試是否支援3D!NOW int CPUTYPE = i386 ; 
//CPU的型態,初始值為i386 
/***************************************************************************/ 
 
下面我們將開始介紹這些原生函式的實做方式,但是有些觀念我們必須要先知道. 首先,在下面的函式裡頭,我們利用BCB內嵌組合語言來實做,雖然我們也可以利用Win32 API或其他方法來取得系統資訊和硬體資訊,可是就複雜度來說,實在不如用組合語言來的那麼簡潔.(網路上常有人在爭論組合語言跟高階語言的優劣,甚至認為組合語言已經沒有存在的必要,不過筆者還是覺得做什麼事就用最適合的語言會比較好)。 第二,在這些inline assembly code裡面,我們大量地利用了CPUID這個組合語言指令.這是一個辨識CPU相當好用的指令,除了辨識一些CPU的特殊能力,也可以提供一些廠方資訊.大家可以翻閱Intel的Instruction set reference來看看這個指令的用法.不過呢,這個指令只有在Pentium等級CPU中才提供,換句話說,486,386上這個指令應該無效,嚴格地說來,即使執行檔在486以下的電腦執行這段程式,應該是沒有問題才對. 可是大家應該還記得去年在Intel的CPU中一些don't care的指令集竟然會造成電腦當機的錯誤吧! 所以我想在使用這個指令以前,應該先看看CPU是否支援這個指令,如果不支援,就不要再做下去,以免發生不可預期的錯誤. 因此我們在使用CheckMMX, CheckSSIMD, Check3DNOW,這些函式以前,請務必先執行CheckCPUID這個函式.這個函式會去變更全域變數CPUID_S,因此不論是CheckMMX, CheckSSIMD, Check3DNOW,都會在使用CPUID指令前先檢查這個全域變數,如果是false,就不再繼續動作下去,以免發生非預期的錯誤。 最後一點,就是當C Builder在編譯內嵌組和語言的程式碼時,會在程式目錄中產生CPUTestDll.asm這個中間檔,請將Project/Option裡頭的Advanced Compiler次頁,裡頭有一個叫Instruction Set的地方,請勾選Pentium,否則不管您勾選386或是486,編譯器會因為不支援此指令而產生組譯錯誤。
/*以下開始實做所有的JNI函式*/    /*辨識處理器是否支援AMD 3DNow*/
JNIEXPORT jboolean JNICALL Java_my_cpu_CPUTest_Check3DNOW(JNIEnv *J, jobject O)
{ 
//如果不支援CPUID指令,就不必再做下去以免發生錯誤
if( CPUID_S == false ) 
return false;     unsigned long temp ;    asm mov eax,80000001h ;
asm cpuid ; 
asm mov temp,edx ;     //第31個bit為3D!NOW的特徵值
if ( temp & 0x80000000 ) 
{ 
_3DNOW = true ; 
return true ;
} 
return false; 
}     /*測試CPU是否支援CPUID指令*/
JNIEXPORT jboolean JNICALL Java_my_cpu_CPUTest_CheckCPUID(JNIEnv *J, jobject O)
{ 
//以下程式用來測試CPU是否支援CPUID指令 
unsigned int A,B ; 
 asm pushfd ; 
asm pop eax ;
asm mov ebx,eax ;
asm xor eax,00200000h ;
asm push eax ; 
asm popfd ; 
asm pushfd ; 
asm pop eax ; 
asm mov A,eax ; 
asm mov B,ebx ;
if ( A != B )
{ 
CPUID_S = true ;
return true ; 
} 
return false ; 
}     /*辨識CPU的等級*/
JNIEXPORT jint JNICALL Java_my_cpu_CPUTest_CheckCPUTYPE(JNIEnv *J, jobject O)
{ 
//如果不支援CPUID指令,就不必再做下去以免發生錯誤
if( CPUID_S == false )
return i386 ;     unsigned int temp ; 
asm mov eax,0 ; 
asm cpuid ; 
asm mov temp,eax ;
if (temp == 2)//這是P6家族的情形 
{     CPUTYPE = Pentium_P ; 
//P6家族的第一顆processor為Pentium Pro if (SSIMD)
//P6然後又支援SSIMD ..一定是Pentium III
{ 
CPUTYPE = Pentium_3 ; 
return Pentium_3 ;
} 
if (MMX) //否則P6然後又支援MMX ..一定是Pentium II
{ 
CPUTYPE = Pentium_2 ; if( _3DNOW )
/支援MMX又支援3D!NOW,一定是K6-2
{ 
CPUTYPE = K6_2 ; return K6_2 ;
} 
return Pentium_2 ; 
} 
 //如果都沒有支援以上這些多媒體指令集,那麼應該是
 Pentium Pro了 return Pentium_P ; 
}
if (temp == 1)//這是P5家族的情形
{ 
CPUTYPE = Pentium ; //P5家族的第一顆processor為Pentium
 if (MMX) //P5然後又支援MMX ..一定是Pentium with MMX
{ 
CPUTYPE = Pentium_M ; 
return Pentium_M ; 
}
return Pentium ; 
} 
return i386 ; 
}    /*辨識處理器是否支援MMX*/
JNIEXPORT jboolean JNICALL Java_my_cpu_CPUTest_CheckMMX(JNIEnv *J, jobject O) 
{ 
//如果不支援CPUID指令,就不必再做下去以免發生錯誤
if( CPUID_S == false ) 
return false ;     unsigned long temp ;    asm mov eax,1 ;
asm cpuid ;
asm mov temp,edx ;     //第23個bit為MMX的特徵值
//p.s bit的編號由0 ~ 31
 if ( temp & 0x00800000 ) 
{     MMX = true ;
return true ;
}
return false ; 
}
/*辨識處理器是否支援Stream SIMD Extension(即KNI)
*/ JNIEXPORT jboolean JNICALL Java_my_cpu_CPUTest_CheckSSIMD(JNIEnv *J, jobject O) 
{ 
//如果不支援CPUID指令,就不必再做下去以免發生錯誤
if( CPUID_S == false )
return false ;     unsigned long temp ;    asm mov eax,1 ; 
asm cpuid ; 
asm mov temp,edx ;     //第25個bit為Streaming SIMD Extension的特徵位元
//p.s bit的編號由0 ~ 31
if ( temp & 0x02000000 )
{     SSIMD = true ; 
return true ; 
} 
 return false ; 
}     /*印出CPU的相關資訊*/
JNIEXPORT void JNICALL Java_my_cpu_CPUTest_PrintCPUInfo(JNIEnv *J, jobject O)
{ 
cout << "... Verify Some Processor Information ..." << endl ; 
cout << "The Capacity of your Processor : " << endl ;
if ( MMX )
{ 
cout << "Support Intel MMX Technology" << endl ;
}else
{ 
cout << "No Intel MMX Technology Support" << endl ; } 
if ( SSIMD )
{ 
cout << "Support Intel Streaming SIMD Extensions" << endl ; 
}else 
{ 
cout << "No Intel Streaming SIMD Extensions Support" << endl ; 
} 
 if ( _3DNOW )
{ 
cout << "Support AMD 3D!NOW Technology" << endl ; 
}else 
{ 
cout << "No AMD 3D!NOW Technology Support" << endl ; 
} 
cout << "CPU Type :" ;
switch( CPUTYPE ) 
{ 
case i386 : 
 cout << "General i386 Processor" << endl ; 
 break ; 
case Pentium : 
 cout << "Intel Pentium Processor" << endl ; 
 break ; 
case Pentium_M : 
 cout << "Intel Pentium with MMX Processor" << endl ;
 break ; 
case Pentium_2 :
 cout << "Intel Pentium II Processor" << endl ;
 break ; 
case Pentium_3 : 
 cout << "Intel Pentium III Processor" << endl ;
 break ; 
case Pentium_P : 
cout << "Intel Pentium Pro Processor" << endl ; 
 break ; 
 case K6 :
cout << "AMD K6 Processor" << endl ; 
 break ; 
 case K6_2 : 
cout << "AMD K6 II Processor" << endl ; 
 break ; 
case K6_3 : 
cout << "AMD K6 III Processor" << endl ; 
 break ; 
}
cout << "... Verify End ..." << endl ; 
}    int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) 
{ 
return 1; 
}
//--------------------------------------------------------------------------- 
 
大家可能會發現每個函式在回傳布林值以前,都會先去設定一個DLL內部的全域變數,這是因為效率的考量,假如讀者有興趣擴充筆者的程式,讓Java程式可以因為CPU的特徵去呼叫適當的函式,一旦你遇到兩次這種情形,您就必須呼叫CheckXXXX函式兩次,十次這種情形,您就要呼叫十次,相當地沒有效率,如果照筆者的實做法,只要呼叫一次,就會去設定紀錄CPU特徵的全域變數,接下來就不必再次呼叫CheckXXXX,直接存取全域變數就可以了. 大家可以參考一下PrintCPUInfo函式,大致上可以知道為何筆者這樣做的理由. 還有就是CheckCPUTYPE這個函式的方法並非是最正規的方法,筆者只是假設市面上只有AMD與Intel兩家廠商而已,如果要正確的辨認出廠商跟型號,我們還必須利用CPUID取得更多資訊才行,這就當作給諸位讀者一個練習的機會,相信只要讀者有心,去找找各種CPU的System Programming Manual,一定可以找到正確的偵測方法. 測試 終於到了要測試咱們程式正確性的時候了,所以我們撰寫了test.java ■ 檔案列表test.java
import my.cpu. * ;    class test
{ 
/*以下定義每種處理器所代表的常數*/ 
static public final int i386 = 0 ; //不支援CPUID的處理器(可辨識)
static public final int Pentium = 1 ; //最早期的Pentium處理器(可辨識)
static public final int Pentium_M = 2 ; //Pentium with MMX 處理器(可辨識)
static public final int Pentium_2 = 3 ; //Pentium II 處理器(可辨識) 
static public final int Pentium_3 = 4 ; //Pentium III處理器(可辨識)
static public final int Pentium_P = 5 ; //Pentium Pro 處理器(可辨識) 
static public final int K6 = 11 ; //同Pentium with MMX 
static public final int K6_2 = 12 ; //K6-2處理器((可辨識) 
static public final int K6_3 = 13 ; //同K6-2     //主程式開始
public static void main(String args[]) 
{ 
boolean temp ; 
//取得JNI介面物件 
CPUTest my = new CPUTest() ;    //開始CPU相關資訊的初始化工作
temp = my.CheckCPUID() ;
if( temp )
{ 
System.out.println("CPUID support") ; }
else 
{ 
System.out.println("CPUID not support") ; 
}
temp = my.CheckMMX() ; 
 if( temp )
{ 
System.out.println("MMX support") ;
}else 
{ 
System.out.println("MMX not support") ; 
} 
temp = my.CheckSSIMD() ;
if( temp )
{ 
System.out.println("SSIMD support") ; 
}else
{ 
System.out.println("SSIMD not support") ; 
} 
 temp = my.Check3DNOW() ; 
 if( temp ) 
 { 
System.out.println("3DNOW support") ;
 }else
{ 
System.out.println("3DNOW not support") ; 
}      System.out.println("") ;
 System.out.println("---------Starting Java code Print--------") ; 
 switch(my.CheckCPUTYPE())
{ 
case i386: 
System.out.println("i386") ; 
 break ; 
case Pentium:
 System.out.println("Pentium") ; 
 break ;
 case Pentium_M: 
 System.out.println("Pentium with MMX") ;
 break ;
 case Pentium_2: 
 System.out.println("Pentium II") ;
 break ; 
 case Pentium_3: 
System.out.println("Pentium III") ; 
break ; 
 case Pentium_P:
System.out.println("Pentium Pro") ; 
break ;
 case K6:
System.out.println("K6") ;
break ; 
 case K6_2: 
System.out.println("k6-2") ;
break ;
 case K6_3: 
System.out.println("K6-3") ;
break ; 
}     System.out.println("") ; 
System.out.println("---------Starting native code Print--------") ; 
my.PrintCPUInfo() ;     }//end of main 
}//end of class 
 
在命令列下打入javac test.java,就可以產生test.class這個檔案.接者請打java test來執行程式,不過首先您會先遇到下面的錯誤訊息:
 C:\jdk1.2\my>java test 
Exception in thread "main" java.lang.UnsatisfiedLinkError: no CPUTestDll in java
.library.path 
at java.lang.ClassLoader.loadLibrary(Compiled Code)
at java.lang.Runtime.loadLibrary0(Runtime.java:470)
at java.lang.System.loadLibrary(System.java:745) 
at my.cpu.CPUTest.(CPUTest.java:48) 
這是什麼原因呢? 原來是因為Java Virtual Machine找不到CPUTestDll.dll,所以產生了執行時期例外.解決這個問題的方法有兩種: 第一種就是把CPUTestDll.dll拷貝到跟test.class同一個目錄下. 第二種方法就是下指令java -Djava.library.path=< DLL所在位置 > test,例如: java -Djava.library.path=c:\jdk1.2\my\dll test代表CPUTestDll.dll是放置在c:\jdk1.2\my\dll底下. 不論您用哪種方法,都可以看到下面的輸出結果:
C:\jdk1.2\my>java test 
CPUID support 
MMX support 
SSIMD not support 
3DNOW not support     ---------Starting Java code Print--------
Pentium II     ---------Starting native code Print--------
... Verify Some Processor Information ... 
The Capacity of your Processor : 
Support Intel MMX Technology
No Intel Streaming SIMD Extensions Support 
No AMD 3D!NOW Technology Support
CPU Type :Intel Pentium II Processor 
... Verify End ...  
以上是在筆者電腦上的執行情形.您的電腦上也成功地輸出結果了嗎? 結語 其實在本文章中,只應用了JNI幫我們傳遞一些參數給動態連結函式庫,再由動態連結函式庫傳回一些值給我們而已. 其實,利用JNI也可以做到直接更改動態連結函式庫裡頭的變數,動態連結函式庫裡頭的函式也可以直接更改java程式中的變數,只不過本文章重點並非在JNI功能的介紹,所以並沒有提及. 另外關於CPU特徵的偵測,我們只是簡單地偵測幾個CPU的特性,較複雜的還有偵測CPU的時脈等特徵,在Intel的網站上我們也可以找到名為cpuinfo.zip的樣本. 期望這篇文章可以讓目前正在使用java,又想充分利用處理器特性來做最佳化的朋友提供一個踏板. 發表人 - conundrum 於 2004/02/14 11:57:16
系統時間:2024-05-09 11:29:15
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!