Programiranje

Profiliranje uporabe CPU znotraj aplikacije Java

8. november 2002

V: Kako določite uporabo procesorja v Javi?

A: Tu so torej dobre in slabe novice. Slaba novica je, da programsko poizvedovanje za uporabo procesorja s čisto Javo ni mogoče. Za to preprosto ni API-ja. Predlagana alternativa bi lahko uporabila Runtime.exec () če želite določiti ID procesa JVM (PID), pokličite zunanji ukaz za platformo, kot je psin razčlenite svoj izhod za PID, ki vas zanima. Toda ta pristop je v najboljšem primeru krhek.

Dobra novica pa je, da lahko zanesljivo rešitev dosežemo tako, da stopimo izven Jave in napišemo nekaj vrstic kode C, ki se integrirajo z aplikacijo Java prek Java Native Interface (JNI). Spodaj sem pokazal, kako enostavno je to z ustvarjanjem preproste knjižnice JNI za platformo Win32. Oddelek Viri vsebuje povezavo do knjižnice, ki jo lahko prilagodite svojim potrebam, in vrata na druge platforme.

Na splošno je JNI nekoliko zapleten za uporabo. Ko pa kličete samo v eno smer - iz Jave v izvorno kodo - in komunicirate s primitivnimi podatkovnimi vrstami, stvari ostanejo preproste. Obstaja veliko dobrih referenc (glej Vire) o JNI, zato tukaj ne zagotavljam vadnice JNI; Jaz zgolj orisam svoje korake izvajanja.

Začnem z ustvarjanjem predavanja com.vladium.utils.SystemInformation ki razglasi izvorno metodo, ki vrne število milisekund procesorskega časa, ki ga je do zdaj uporabil trenutni postopek:

 javni statični izvorni long getProcessCPUTime (); 

Orodje javah iz JDK uporabljam za izdelavo naslednjega naslova C za prihodnjo domačo implementacijo:

JNIEXPORT jlong ​​JNICALL Java_com_vladium_utils_SystemInformation_getProcessCPUTime (JNIEnv * env, jclass cls) 

Na večini platform Win32 je to metodo mogoče uporabiti z uporabo GetProcessTimes () sistemski klic in je dobesedno tri vrstice kode C:

JNIEXPORT jlong ​​JNICALL Java_com_vladium_utils_SystemInformation_getProcessCPUTime (JNIEnv * env, jclass cls) {FILETIME createTime, exitTime, kernelTime, userTime; GetProcessTimes (s_currentProcess, & createTime, & exitTime, & kernelTime, & userTime); vrnitev (jlong) ((fileTimeToInt64 (& kernelTime) + fileTimeToInt64 (& userTime)) / (s_numberOfProcessors * 10000)); } 

Ta metoda dodaja procesorski čas, porabljen za izvajanje jedra in uporabniške kode v imenu trenutnega procesa, ga normalizira glede na število procesorjev in rezultat pretvori v milisekunde. The fileTimeToInt64 () je pomožna funkcija, ki pretvori FILETIME struktura na 64-bitno celo število in s_currentProcess in s_numberOfProcessors so globalne spremenljivke, ki jih je mogoče priročno inicializirati v metodi JNI, ki se pokliče enkrat, ko JVM naloži izvorno knjižnico:

statični HANDLE s_currentProcess; statični int s_numberOfProcessors; JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * rezervirano) {SYSTEM_INFO systemInfo; s_currentProcess = GetCurrentProcess (); GetSystemInfo (& systemInfo); s_numberOfProcessors = systemInfo.dwNumberOfProcessors; vrni JNI_VERSION_1_2; } 

Upoštevajte, da če izvajate getProcessCPUTime () na Unixovi platformi bi verjetno uporabili getrusage sistemski klic kot izhodišče.

Vrnitev na Javo, nalaganje izvorne knjižnice (silib.dll na Win32) je najbolje doseči s statičnim inicializatorjem v Sistemska informacija razred:

 zasebni statični končni niz SILIB = "silib"; statična {poskusite {System.loadLibrary (SILIB); } catch (UnsatisfiedLinkError e) {System.out.println ("native lib '" + SILIB + "' ni mogoče najti v 'java.library.path':" + System.getProperty ("java.library.path")); vrzi e; // ponovni met}} 

Upoštevajte to getProcessCPUTime () vrne čas procesorja, porabljen od ustvarjanja procesa JVM. Ti podatki sami po sebi niso posebej uporabni za profiliranje. Potrebujem več uporabnih metod Java za snemanje posnetkov podatkov ob različnih časih in poročanje o uporabi CPU med katerima koli dvema časovnima točkama:

 javni statični končni razred CPUUsageSnapshot {private CPUUsageSnapshot (long time, long CPUTime) {m_time = time; m_CPUTime = CPUTime; } javni končni dolgi m_time, m_CPUTime; } // konec ugnezdenega razreda javni statični CPUUsageSnapshot makeCPUUsageSnapshot () {vrni nov CPUUsageSnapshot (System.currentTimeMillis (), getProcessCPUTime ()); } javni statični dvojni getProcessCPUUsage (CPUUsageSnapshot start, CPUUsageSnapshot end) {return ((double) (end.m_CPUTime - start.m_CPUTime)) / (end.m_time - start.m_time); } 

"API za nadzor CPU" je skoraj pripravljen za uporabo! Kot zadnjo potezo ustvarim razred enojne niti, CPUUsageThread, ki samodejno posname posnetke podatkov v rednih intervalih (privzeto 0,5 sekunde) in jih sporoči naboru poslušalcev dogodkov uporabe procesorja (znani vzorec Observer). The CPUmon class je predstavitveni poslušalec, ki preprosto natisne uporabo procesorja System.out:

 javna statična void main (String [] args) vrže izjemo {if (args.length == 0) vrže novo IllegalArgumentException ("uporaba: CPUmon"); CPUUsageThread monitor = CPUUsageThread.getCPUThreadUsageThread (); CPUmon _this = nov CPUmon (); Razred app = Class.forName (args [0]); Metoda appmain = app.getMethod ("main", nov razred [] {String []. Class}); String [] appargs = nov niz [args.length - 1]; System.arraycopy (args, 1, appargs, 0, appargs.length); monitor.addUsageEventListener (_this); monitor.start (); appmain.invoke (null, nov objekt [] {appargs}); } 

Poleg tega CPUmon.main () "zavije" še en glavni razred Java z edinim namenom za zagon CPUUsageThread pred zagonom prvotne aplikacije.

Kot demonstracija sem tekel CPUmon s predstavitvijo SwingSet2 Swing iz JDK 1.3.1 (ne pozabite namestiti silib.dll na mesto, ki ga pokriva POT Spremenljivka okolja OS ali java.library.path Lastnost Java):

> java -Djava.library.path =. -cp silib.jar; (moj namestitveni direktorij JDK) \ demo \ jfc \ SwingSet2 \ SwingSet2.jar CPUmon SwingSet2 [PID: 339] Uporaba CPU: 46,8% [PID: 339] CPU poraba: 51,4% [PID: 339] CPU uporaba: 54,8% (med nalaganjem demo uporablja skoraj 100% enega od dveh CPU-jev na mojem računalniku) ... [PID: 339] Uporaba CPU: 46,8% [PID: 339] Uporaba CPU: 0% [PID: 339] Poraba CPU: 0% (predstavitev je končala z nalaganjem vseh svojih plošč in je večinoma v prostem teku) ... [PID: 339] Poraba CPU: 100% [PID: 339] Poraba CPU: 98,4% [PID: 339] CPU uporaba: 97% (preusmeril sem se na ploščo ColorChooserDemo, ki je izvajala CPU intenzivno animacijo, ki je uporabljala oba moja CPU) ... [PID: 339] Poraba CPU: 81,4% [PID: 339] Uporaba CPU: 50% [PID : 339] Uporaba procesorja: 50% (z upraviteljem opravil Windows NT sem prilagodil afiniteto procesorja za "java" postopek za uporabo enega CPU) ... 

Seveda lahko iste številke uporabe spremljam prek upravitelja opravil, vendar gre tukaj za to, da imam zdaj programski način za snemanje istih podatkov. Prišel bo prav za dolgotrajne teste in diagnostiko strežniških aplikacij. Popolna knjižnica (na voljo v virih) doda nekaj drugih uporabnih izvornih metod, vključno s tisto za pridobivanje PID procesa (za integracijo z zunanjimi orodji).

Vladimir Roubtsov že več kot 12 let programira v različnih jezikih, vključno z Javo od leta 1995. Trenutno razvija programsko opremo za podjetja kot višji razvijalec za Trilogy v Austinu v Teksasu. Ko kodira za zabavo, Vladimir razvija programska orodja, ki temeljijo na bajtni kodi Java ali instrumentaciji izvorne kode.

Preberite več o tej temi

  • Prenesite celotno knjižnico, ki spremlja ta članek

    //images.techhive.com/downloads/idge/imported/article/jvw/2002/11/01-qa-1108-cpu.zip

  • Specifikacija JNI in vaje

    //java.sun.com/j2se/1.4/docs/guide/jni/index.html

  • Za dober pregled JNI glejte Stuart Dabbs Halloway's Razvoj komponent za platformo Java (Addison-Wesley, december 2001; ISBN0201753065)

    //www.amazon.com/exec/obidos/ASIN/0201753065/javaworld

  • V "Java Tip 92Use JVM Profiler Interface za natančno določanje časa" Jesper Gortz raziskuje alternativno smer profiliranja uporabe CPU. (Vendar uporaba JVMPI zahteva več dela za izračun porabe procesorja za celoten postopek v primerjavi z rešitvijo tega članka)

    //www.javaworld.com/javaworld/javatips/jw-javatip92.html

  • Glej Vprašanja in odgovori o Javi indeksna stran za celoten katalog Vprašanj

    //www.javaworld.com/columns/jw-qna-index.shtml

  • Obiščite več kot 100 pronicljivih nasvetov za Java JavaWorld 's Java Nasveti indeksna stran

    //www.javaworld.com/columns/jw-tips-index.shtml

  • Prebrskajte Jedro Java odsek JavaWorld 's Aktualni indeks

    //www.javaworld.com/channel_content/jw-core-index.shtml

  • Pridobite več odgovorov na naša vprašanja v naši Začetnik Java diskusija

    //forums.devworld.com/webx?50@@.ee6b804

  • Prijavite se za JavaWorldbrezplačna tedenska glasila po e-pošti

    //www.javaworld.com/subscribe

  • Na naslovu .net boste našli ogromno člankov, povezanih z IT, iz naših sestrskih publikacij

To zgodbo z naslovom "Profiliranje uporabe CPU znotraj aplikacije Java" je prvotno objavil JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found