分享
 
 
 

利用Java配合BCB 4.0制作CPU特征侦测器

王朝java/jsp·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

注:本文亦适用Borland C++ Builder 5.0

?前言

笔者最近从事一个利用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

的完整测试程序.

假如以图片来表示就如下图

假如您抓取了笔者提供的原始码,应该可以看到下面三个分别由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所在目录includewin32加到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.2my之下,

那幺请在提示符号下命令

PATH c:jdk1.2in

set CLASSPATH=C:jdk1.2classes;c:JDK1.2my

test.java

这个Java程序将利用CPUTest对象当作接口,来呼叫实做于CPUTestDll.dll内的CPU特征侦测函数

编译注重事项 :

除了2的注重事项外,请将CPUTest.java放到 <JDK安装目录>classesmycpu这个目录之中,否则编译将无法通过.

?参考文件

1. JDK 1.2 on-line document

2. Intel Architecture Optimization/Reference manual Order Number: 245127-001

3. AMD 3DNOW! Technology Manual

?用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

System.loadLibrary("CPUTestDll") ;

}

}

接着我们在提示符号下使用指令

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 <jni.h>

/* 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 <vcl.h>

#pragma hdrstop

#include <iostream.h>

#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.2my>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.<clinit>(CPUTest.java:48)

这是什幺原因呢? 原来是因为Java Virtual Machine找不到CPUTestDll.dll,所以产生了执行时期例外.解决这个问题的方法有两种: 第一种就是把CPUTestDll.dll拷贝到跟test.class同一个目录下. 第二种方法就是下指令java -Djava.library.path=<DLL所在位置> test,例如:

java -Djava.library.path=c:jdk1.2mydll test代表CPUTestDll.dll是放置在c:jdk1.2mydll底下. 不论您用哪种方法,都可以看到下面的输出结果:

C:jdk1.2my>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,又想充分利用处理器特性来做最佳化的朋友提供一个踏板.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有