Táto kapitola pojednáva o jednotlivých častiach modelu sveta, ktoré by bolo vhodné doplniť alebo vylepšiť v prvom rade.
Ako vyplýva z predchádzajúcej kapitoly, momentálne nedokážeme určiť polohu sveta na 100% presne, preto by bolo vhodné výpočet tejto polohy overiť pomocou výpočtu polohy hráča voči väčšiemu počtu statických prvkov na ihrisku. Server posiela aj informáciu a čiare, ktorú agent vidí a to začiatočný bod a koncový bod, ale začiatočný a koncový bod nie kompletnej čiary, ale časti čiary, ktorú vidí vo svojom 120 stupňovom uhle. Z toho však vyplýva aj možný problém, že určenie, na ktorú čiaru sa pozerá, nemusí byť úplne triviálne, ale malo by sa dať určiť z natočenia hráča.
Vzhľadom k tomu, že futbal je tímová hra, bolo by dobré, aby agent vedel aj o ostaných hráčoch na ihrisku. Túto informáciu mu najlepšie poskytne informácia o ich polohe na hracej ploche. Tieto informácie sa môže dozvedieť buď zo zrakového senzora, ale bolo by tiež zaujímavé ak by si hráči dokázali túto informáciu podať aj pomocou reči.
Dôvod tejto zmeny je celkom prostý a to, že na novom serveri bol premiestnený zrakový perceptor z hrude do stredu hlavy, preto tomu treba prispôsobiť aj agenta, aby nedochádzalo k neželaným odchylkám už pri získavaní informácií.
Ako bolo spomínané vyššie, tým, že server vnáša do komunikácie šum, je vhodné použiť nejakú metódu, ktorá by dokázala minimalizovať prichádzajúce chybné údaje na minimum, či už to je pomocou kombinácie viacerých objektov pri výpočte polohy, ktoré na ihrisku vidí agent, ale tiež by bolo zaujímavé použiť iné metódy ako napríklad kalmanové filtere.
Pre lepšiu schopnosť agenta zistiť čo sa na ihrisku deje by bolo vhodné vylepšiť existujúci dynamický objekt, ktorý počíta rýchlosť len na základe súčasnej a predchádzajúcej polohy a to buď pridaním väčšieho počtu predchádzajúcich polôh, alebo skvalitnením výpočtu.
Táto informácia má možné využite pri taktike, aby nedošlo k situácii, že sa všetci hráči rozbehnú za loptou, ale iba ten čo je najbližšie k nej. Táto informácia by mohla vypočítať z pozície agenta, pozície lopty a pozií ostatných agentov.
Predošlý tím identifikoval ako jeden z problémov neefektívnosť momentálneho riadiaceho kódu, ktorý sa z určitej časti podieľa na malej výkonnosti hráča. Ide hlavne o časti, ktoré sa starajú o spracovávanie komunikácie so serverom a následného ovládania hráča. Cieľom analýzy je zistiť konkrétne problémy v neefektívnosti kódu a navrhnúť vylepšenia, ktoré budú viesť k jeho optimalizácii.
Tento nástroj pomáha pri sledovaní výkonnosti a debugovaní Java aplikácií na základe monitorovania operácií na JVM úrovni. Pomocou rôznych techník sleduje čas procesora pri jednotlivých metódach a vláknach, tvorbu objektov, alokáciu pamäte apod. Yourkit ponúka hlavne prepracovaný CPU profiling, ktorý môžeme využiť na analýzu náročnosti metód a ich optimalizácie.
Profiling ponúka 3 možnosti:
Pre najpresnejšie zmeranie spotrebovaného času volanými metódami je najvhodnejšia Tracing metóda, čo vyplýva z následujúceho obrázka.
Yourkit takisto po dostatočne dlhom behu programu ponúka uloženie zozbieraných výsledkov vo forme snapshotov, ktoré budú pre analýzu vhodnejšie, než sledovanie výsledkov aktuálneho behu.
Pomocou spomínanej metódy Tracing sme zmerali celkový čas jednotlivých vykonaných metód. Výstupom sú teda zoradené metódy podľa času s ohľadom na počet ich invokácií.
Pomocou tejto štatistiky môžeme ďalej analyzovať vykonávanie programu a hlbším vnorením do metód zistiť, aké kúsky kódu sú pre CPU časovo najnáročnejšie.
Ako je z obrázku zrejmé, spracovanie komunikácie, aktualizovanie stavu hráča a príkazov prebieha iba pomocou jedného vlákna v dôsledku čoho pravdepodobne dochádza k zahadzovaniu prijatých správ, ktoré agent prijme počas spracovávania inej správy. Toto spracovanie trvá väčšinu spotrebovaného času, čomu sa však nedá vyhnúť. Veľkým zlepšením by ale mohlo byť vytvorenie nového vlákna pre spracovanie každej novej správy. V rámci ostatných metód bude optimalizácia spočívať v nahradení jednotlivých kódových konštrukcií výpočtovo menej náročnými kúskami kódu.
Táto metóda beží od začiatku pripojenia k serveru a spracováva prijaté správy o stave hráča z pohľadu servera a teda zaberá drvivú väčšinu celkového času.
private void mainLoop () throws IOException { \\ while ( true ){ \\ wait for input \\ while ( input .available() == - 1 ) {
Thread. yield(); \\ }
\\ receive message \\String incoming = receive() ; \\ parser .parse(incoming) ;
\\ process message \\ HighSkillRunner. proceed();
\\ transmit message \\transmit( outMessageBuffer .append( “(syn)” ).toString()) ; \\ outMessageBuffer = new StringBuilder () ; \\ }
}
V tejto metóde je ďalej volané spracovanie správy pomocou metódy Parser.parse(incoming). Vytvorenie nového vlákna pre každé toto volanie by mohlo priniesť zlepšenie v celkovej rýchlosti spracovávania správ a tým pádom bude mať hráč presnejšie informácie o jeho stave.
V rámci metódy dochádza k rozloženiu správy na jednotlivé informácie, ktoré server ponúka. Ďalej sa tieto informácie preložia do formy dát, ktoré sa ďalej dajú v programe spracovávať. Nakoniec sa zavolá aktualizovanie stavu objektov, ktoré ovládajú hráča.
publicParsedDataparse(String message) { \\data=newParsedData();
this.message= message; \\String[] breakDown = breakDown();
for(String perceptor : breakDown) {
String perceptorId = perceptor.substring(0,perceptor.indexOf(' ')); \\Perceptors.processPerceptor(perceptorId,perceptor,data); \\}
notifyObservers();
returndata; \\}
Priestoru na optimalizáciu veľa nie je, keďže obsiahnuté metódy až na Parser.notifyObservers() podľa Yourkitu príliš náročné nie sú.
V tejto metóde sa už volajú konkrétne objekty, ktoré sa starajú o spracovávanie preložených dát a aktualizovanie stavu hráča alebo hracieho sveta a ovládajú jeho správanie.
privatevoidnotifyObservers() { \\synchronized(Parser.class){ \\for(ParsedDataObserver observer :observers)
observer.processNewServerMessage(data); \\}
}
Priamo v metóde nie je možnosť nejakého optimalizovania, to bude možné až pri spracovávaní správ objektami observer.
Táto metóda je jedna z dvoch, ktoré sú podľa Yourkitu medzi spracovávaním objektami observer časovo najnáročnejšie.
publicvoidprocessNewServerMessage(ParsedData data) { \\if(data.ballRelativePosition!=null) {
calculateBallPosition(data); \\}
calculatePlayers(data.otherplayers,data.SIMULATION_TIME);
if(data.lines.size() >0) {
calculateLines(data); \\}
\\try{
TestFrameworkCommunication.sendMessage(newMessage().WorldModel().changed(WorldModel.getInstance())); \\}catch(Exception e) { \\LOG.log(LogType.WARNING,“Chyba v spracovani spravy vo WorldModeli”,e); \\}
}
V metóde sa potom vypočítava aktuálny stav hracích tímov, ich pozície a pozícia lopty. Tieto metódy však nie sú kritické. Ďalej sa tu ešte vykonáva informovanie testovacieho frameworku o aktuálnom stave, čo je z pohľadu času kritické. Vypnutím tohto odosielania keď nie je potrebné by sme mohli ušetriť nejaký čas.
Pomocou tejto metódy sa vytvorí správa o aktuálnom stave hracieho sveta, ktorá sa odošle do testovacieho frameworku.
publicMessagechanged(sk.fiit.jim.agent.models.WorldModel model) { \\message+=“ beginData\n”;
try{
ByteArrayOutputStream outStream =newByteArrayOutputStream(); \\ObjectOutputStream out =newObjectOutputStream(outStream); \\out.writeObject(model); \\out.close();
byte[] data = outStream.toByteArray(); \\String to_send = Base64.encodeBase64String(data); \\outStream.close(); \\MessageDigest md = MessageDigest.getInstance(“SHA-1”); \\Formatter formatter =newFormatter();
for(byteb: md.digest(data)) {
formatter.format(“%02x”,b); \\}
String checksum = formatter.toString(); \\message+= checksum +“\n”; \\message+= to_send; \\message+=“endData”; \\formatter.close();
\\}catch(Exception e) { \\LOG.log(Level.WARNING,“Couldnt process the message about the world. Cause: ”+ e.getMessage()); \\}
\\returnMessage.this; \\}
V metóde je najkritickejší zápis dátového objektu do bajtového output streamu. Potom je tu náročné ešte kódovanie Base64 stringu a transformácia na jeho hash hodnotu s SHA-1. Tieto samotné metódy sa však príliš zmeniť nedajú.
V tejto metóde sa prepočítava stav tela hráča, pozícia častí a natočenie. Po jej zbehnutí by mal hráč mať informácie o svojej pozícii a orientácii.
public void processNewServerMessage (ParsedData data) { \\ if (data. PLAYER_ID != null && data. PLAYER_ID != 0 ) {
AgentInfo.getInstance().setPlayerId(data. PLAYER_ID ) ; \\ }
\\ if (data. OUR_SIDE_IS_LEFT != null ) {
AgentInfo.getInstance().setAssignedSide( true ) ; \\ AgentInfo. side = data. OUR_SIDE_IS_LEFT ? Side. LEFT : Side. RIGHT ; \\ }
\\ /*
* According to values and server settings, if sides change at half
* time, side is changed. Roman Moravcik (Gitmen)
*/ \\ if ( HALF_TIME_CHANGE_SIDES && ! sidesChanged && data. GAME_ TIME >=<em>>=<em>HALF >=<em>>=<em>_TIME >=<em>>=<em>HALF >=<em>>=<em>_TIME ) { \\ sidesChanged = true; \\ AgentInfo. side = AgentInfo. side == Side. RIGHT ? Side. LEFT : Side. RIGHT ; \\ LOG .log(LogType. AGENT_MODEL , “Sides changed at half time” ) ; \\ }
deleteHistory(data) ;
\\ lastDataReceived = data ; \\ lastAccelerometer = data. accelerometer ;
\\ updateJointPositions(data) ; \\ adjustRotationsFor(data. gyroscope ) ; \\ updateRotations(data) ; \\ updatePureBodyAcceleration(data) ;
if (extendHistory(data))
updatePosition(data) ;
\\ Following methods are used for Zero moment point \\ updateBodyPartsPositions2() ; \\ updateCenterOfMass() ; \\ updateFeetForce(data) ; \\ updateZeroMomentPoint() ; \\ updateSpeedX(data) ;
if (data. fixedObjects != null && data. fixedObjects .size() > 0 ) \\ lastTimeFlagSeen = data. SIMULATION_TIME ; \\ End zero moment point
\\updateHistory(data) ; \\ }
Časovo náročná je tu metóda AgentModel.updateBodyPartsPositions2(), v ktorej sa nachádzajú vektorové výpočty avšak najviac času tu zaberá výpis do logu. Odstránením tohto výpisu by sme mali ušetriť nejaký čas.
Pomocou nástroja Yourkit sme mohli identifikovať metódy, ktoré sú počas behu programu časovo najnáročnejšie a bližšie pochopiť, ktoré konkrétne časti sú za to zodpovedné. Na základe týchto poznatkov dokážeme niektoré kódové konštrukcie optimalizovať a zlepšiť tým celkový výkon hráča. V prvom rade ide o zavedenie viacerých vlákien pri spracovávaní komunikácie so serverom a odstránenie niektorých funkcií, ktoré nie sú pre beh programu nevyhnutné. Všetky tieto zmeny sa budeme snažiť v kóde implementovať a tým by sa mal problém s výkonnosťou do určitej úrovne zmierniť.