Jump to content
  • 0

pomoc Optimalizace kódu


Meric

Dotaz

Popis problému:

Ahojte, potřeboval bych radu od zkušených. Co všechno způsobuje zásadní zátěž na CPU a RAM v kódu? Kromě timerů. Samotný server dost laguje, má něco přes 30 000 řádků.

 

Chyby/varování kompilátoru a při běhu:

Timery jsem srovnal tak, aby se nepotkávaly. Zlepšilo se to, ale není to dostačující.

 

Kód:

 

--

 

 

 

Dodatečné poznámky:

--

Link to comment
Share on other sites

21 odpovědí na tuto otázku

Recommended Posts

  • 0

Divné, že už máš 30k riadkov a laguje ti to. Je to taky paradox. Ak máš tolko kódu, máš dosť skúseností napísať to tak aby to nelagovalo. Začiatočnícke chyby tam asi mať nebudeš, ale bez toho čo si napísal sa nedá povedať čo si kde spravil zle. icon_e_biggrin.gif

 

Tak aspoň nejaké rady ti napíšem, možno dačo z toho pomôže..

 

Menej cyklov

 V cykloch nepoužívaj MAX_PLAYERS, ale GetPlayerPoolSize(). Podobne GetVehiclePoolSize().

 Používaj nejaký moderný cmd systém (izcmd). (1 prikaz = 1 volanie strcmp, pričom izcmd použiva binary serach vsetkych prikazov, nie jednotlivo strcmp)

 Dáta ukladaj do databázy (mysql). (relational database wiki)

 Ak používaš nejaké externé includy (streamery objektov, ...) tak skús nájsť to isté, ale ako plugin, nie ako pawn kód. (pawn je bytecode jazyk, dekodovanie jednej pawn instrukcie zaberie tušim 3 CPU inštrukcie (pawn-imp, introduction a ptm od strany 88. Ine verzie toho dokumentu maju INY OBSAH)

 Nedávať veci do OnPlayerConnect(), skôr do vlastnej OnPlayerLogin(). Tam tiež možno ušetríš niečo ak maš vela botov (raksamp bot hack).

 Nepoužívaj OnPlayerUpdate(), prípadne sa snaž to obmedziť. Keď sa hráč hýbe, volá sa to aj 30x za sekundu (PRE JEDNEHO HRAČA).

 Menej cyklov

 Anticheat... Namiesto kontroly všetkých, kontroluj náhodne. Skutočného cheatera teda nechytíš na prvykrat, ale časom určite.

 Multithreading? Namiesto tých timerov multi-thread plugin. Možno by to našlo využitie. Tiež si prečítaj tie komenty k tomu, je to vcelku nebezpečné, zvažil by som mutex hooknutím funkcií, ktoré by mohli byť nebezpečné.

 

Umm nič viac mi nenapada.

 

Riešiť spotrebu RAM netreba... V podstate jediné kde RAM používaš sú tvoje premenné, takže ak tam nemáš nejaké zbytočné veci, asi moc neušetríš. icon_e_biggrin.gif

Ak ti to laguje jak prasa, možno by som pridal viac premenných aby som nevolal stále nejaké funkcie... Tj. spomedzi spotreby RAM vs CPU by som vybral menšie zlo.

 

Edit: Bulletlist ani numberlist nefunguje. Divne, na ostatnych prispevkoch mi to išlo. Musel som to tam dat tie odstavce manualne.

Edited by Tanga
  • Líbí se mi to! (+1) 4
Link to comment
Share on other sites

  • 0

Úplně šílené to není ale tak jednou za 20 sekund se server lagne cca na 3 - 5 sekund. Hlavně při odpojování. Ukládání mám přes SQLite. Je tam toho docela hodně, protože v tomto módu ukládám docela hodně informací. Snížil jsem přebytečně velká pole u stringů, přebytečná u query, opakující se timery omezit nelze, protože například vězení a aktualizace reálného času musí oboje počítat na sekundy. Kámoš má asi o 10 000 řádků víc a to má méně mappingu, než já a ani zásek a to má hostovaný na slabším PC (VPS). Já to mám na Windows serveru. Nevím co to může tak zatěžovat. Zjistil jsem, že ukládání zbraní tam mám přes dini, to možná tomu přispívá. Ale rozhodně to nebude celý problém. Každopádně díky. Jestli ještě někdo má nějakej nápad, co by to mohlo dělat, ať napíše. Je to RP server, takže se počítá s tím ,že tam bude hafo věcí.

Link to comment
Share on other sites

  • 0

Tento plugin dokaze zistit, ktore funkcie ti zaberaju najviac CPU casu. http://forum.sa-mp.com/showthread.php?t=271129

Skus ho pouzit na svojom servery a zistit, co ti najviac spomaluje, potom ries len to.

PS: Ak pouzivas nejake sialene veci ako YSI, tak ten plugin nieje uplne spolahlivy :/

Link to comment
Share on other sites

  • 0

Tento plugin dokaze zistit, ktore funkcie ti zaberaju najviac CPU casu. http://forum.sa-mp.com/showthread.php?t=271129

 

Skus ho pouzit na svojom servery a zistit, co ti najviac spomaluje, potom ries len to.

 

PS: Ak pouzivas nejake sialene veci ako YSI, tak ten plugin nieje uplne spolahlivy :/

 

Ten profiler mám, ale nepochopil jsem moc jak ho používat. Nikde pořádný vysvětlivky. Podařilo se mi ho zandat do módu, dal jsem věci do server.cfg, ale žádná z funkcí, co jsem tam viděl zkrátka nefungovala a tak nevím jak to do pawna zapsat. Dělal jsem to zrovna včera asi od 4 do 6 do rána. Vysvětlíš mi prosím, jak se to po pořádku používá?

Link to comment
Share on other sites

  • 0

Do pawna nic davat nemusis. Musis zapisat plugin do configu a pridat do configu nieco ako

 

profile_gamemode 1
profile_format html
call_graph 0

alebo

profile_gamemode 0
profile_filterscripts unit
profile_format html
call_graph 0

Samozrejme "unit" nahrad za meno tvojho FS, ktory chces zmerat.

 

Potom restartujes server, aby sa nacital plugin. Nechas server nejaku dobu bezat kym plugin ziskava data a potom ho musis vypnut normalnym sposobm (napriklad rcon exit), NIE TVRDO STLACENIM KRIZIKU!

Ked server vypnes, v zlozke filterscripts resp gamemode sa ti objavi dalsi subor, ktory sa bude volat meno_scriptu.html   

 

Tento subor otvor vo svojom internetovom prehliadaci a v nom su vsetky data, ktore plugin ziska.

Edited by xhunterx
Link to comment
Share on other sites

  • 0

Dobrý, už mi to funguje, díky moc. :-) Bylo to tím, že jsem to vypínal na tvrdo. No teď bych jen chtěl vysvětlit, co v tom znamená Total Time, Self-Time a pak ty Ovverall, Average a Worst. Average jako průměrná doba v sekundách a nejdelší doba načítání v sekundách? A hlavně ty procenta mě zajímaj co jsou.

 

btw mám tam docela dost takových položek: unknown@0004fbf4 a asi nejvíc ze všeho zatěžují server. Znamená to, že se to nestihlo detekovat, nebo to je nějaký cajk, kterej tam jen tak nenajd a tolik žere?


Akorát je zvláštní, že se mi tam ukazuje například aj Itter_OnPlayerDisconnect a ty unknowny. Jak to můžu srazit?

 

https://pastebin.com/34b7cqLM

Edited by Meric
Link to comment
Share on other sites

  • 0
  • Globální moderátor

K tomu unknown, tak je potreba zkompilovat mod s prepinacem -d3 aby kompiler vlozil vic debug informaci do finalniho .amx

 

http://forum.sa-mp.com/showpost.php?p=1253632&postcount=7 (ukazka jak kompilovat -d3 prepinacem)

Link to comment
Share on other sites

  • 0

Zjistil jsem, že ukládání zbraní tam mám přes dini, to možná tomu přispívá. Ale rozhodně to nebude celý problém. Je to RP server, takže se počítá s tím ,že tam bude hafo věcí.

 

Btw, dini funguje tak ze pri kazdom jednotlivom čitani otvori subor, cely ho preskenuje kym nenajde to čo hladaš a potom tu hodnotu vrati.

Ukladanie je ešte lepšie.

Pri ukladani jednotlivych udajov zasa vytvori prazdnu kopiu suboru do ktoreho zapisuješ (s nazvom "nazov.part"), čita cely povodny subor, po jednom tie riadky prepisuje do novej kopie, pri každom kontroluje či prave dany riadok nechceš zmeniť (so strcmp()). Ked subor dokopiruje, odstrani povodny a znovu to prekopiruje (z nazov.part) do noveho suboru s povodnym nazvom kedze file_rename() v samp neexistuje.

Link to comment
Share on other sites

  • 0

Jo, díky. Funguje to. Jen se chci zeptat, ten CallLocalFunction patří k iZCMD? Znamená to tedy, že mám příliš náročné nebo příliš pomalé kódy na příkazy?


Btw, dini funguje tak ze pri kazdom jednotlivom čitani otvori subor, cely ho preskenuje kym nenajde to čo hladaš a potom tu hodnotu vrati.

Ukladanie je ešte lepšie.
Pri ukladani jednotlivych udajov zasa vytvori prazdnu kopiu suboru do ktoreho zapisuješ (s nazvom "nazov.part"), čita cely povodny subor, po jednom tie riadky prepisuje do novej kopie, pri každom kontroluje či prave dany riadok nechceš zmeniť (so strcmp()). Ked subor dokopiruje, odstrani povodny a znovu to prekopiruje (z nazov.part) do noveho suboru s povodnym nazvom kedze file_rename() v samp neexistuje.

 

Jestli to správně chápu, tak je dini pomalejší, než SQLite, nebo ne? A navíc křížení dini a SQLite mi už tak říká, že to nebude dělat dobrotu, tak jsem to smazal a předělávám to do SQLite verze. Každopádně samotný db_query jak je vidno tam, tak mi vyhazuje taktéž docela velké čísla. A předělávat celý mód z db na něco jiného .. nevím. Problém musí být někde jinde ohledně těch malých lagů serveru.

Link to comment
Share on other sites

  • 0
  • Globální moderátor

SQLite urcite prebiji dini. Do souboru bych ukladal jen nastaveni (server nastaveni?) ale jinak vse rozhodne do db. Ty lagy nastanou randomly po 20s nebo je to presne kazdych 20s (a s kolika hraci pritomni na serveru). Pokud se jedna o tu pozdejsi variantu, tak nejlepe si vse oprintfovat, sledovat real-time log a najit pricinu. Vygeneroval bys graf a hodil ho sem jak to momentalne mas? Jestli to teda ten plugin umoznuje

 

CallLocalFunction je volani jakekoliv public funkce z daneho scriptu (jestli to dela iZCMD tak je to iZCMD).

 

Moje dalsi otazky, jak casto si ukladal zbrane? Jak casto spoustis automaticke ukladani uctu?

Link to comment
Share on other sites

  • 0

j, ten calllocalfunction je izcmd, cez to parsuje prikazy.
Mozu to pouzivat aj ostatni ale izcmd z kazdeho prikazu spravi public funkciu a vola ju cez calllocal.

Dini je shit v reale, je to dobre pre niekoho čo sa uči programovat, ale inak je to nepouzitelne.

Link to comment
Share on other sites

  • 0

SQLite urcite prebiji dini. Do souboru bych ukladal jen nastaveni (server nastaveni?) ale jinak vse rozhodne do db. Ty lagy nastanou randomly po 20s nebo je to presne kazdych 20s (a s kolika hraci pritomni na serveru). Pokud se jedna o tu pozdejsi variantu, tak nejlepe si vse oprintfovat, sledovat real-time log a najit pricinu. Vygeneroval bys graf a hodil ho sem jak to momentalne mas? Jestli to teda ten plugin umoznuje

 

CallLocalFunction je volani jakekoliv public funkce z daneho scriptu (jestli to dela iZCMD tak je to iZCMD).

 

Moje dalsi otazky, jak casto si ukladal zbrane? Jak casto spoustis automaticke ukladani uctu?

 

Hodně věcí ukládám do databáze, informace o hráčích (a hodně, včetně zbraní a timer na drogy a zbraně, nějaké pokuty, timer na vězení etc.), vozidlech, cmdlog, nábytek, pak do jinýho souboru db doplňky (attachnuté objekty na postavu). Ukládám staty tak každých zhruba 10 minut, to je i se zbraněma, včera jsem to propojil kvůli změně z dini na SQLite. Zkusím vyvolat z profileru i graf tedy. Není to asi úplně přesně 20 sekund, to jen přibližně a stačí už když jsem tam sám nebo s jedním člověkem. Ale když jsme tam byli dva, tak to bylo stejný jako bych tam byl sám. Ale nedokážu si představit, že bych tam měl hráčů 20+.

 

Chtěl bych se zeptat, bylo by lepší to předělat na SQLite Web Browser? Chci se těch lagů zbavit a když jsem četl tvůj topic o SQLite, tak jsi psal, že SQLite je nedokonalý a způsobuje lagy serveru, takže tuším, že je to to, o čem jsi psal. A psát tak velký mód jako je RP, to je jak vidím dost o hubu dávat tam základní SQLite.

Už mám i ten graf, ale mám ho v textový verzi, v nějaké šabloně. Zkouším to přes Graphviz, ale tomu vůbec nerozumím. Je tam XY .exe souborů a v tom by se nevyznám.

Edited by Meric
Link to comment
Share on other sites

  • 0
  • Globální moderátor

Ten topic je léta starý, ještě když jsem se teprv dostal do styku s SQLite... až někdy najdu motivaci tak to musím přepsat. Nemluvě o tom, že nedávno se předělával sqlite v sa-mpu icon_e_smile.gif trochu se zdokonalil. 

 

Textový graf klidně někam upni a v tom případě pokud to laguje u jednoho hráče tak nezbývá než to oprintfovat a koukat kdy to výrazně lagne v logu (průběh posílání printfu není souvislý, ale je tam nějakej lag).

 

Jak ale tady píšou kluci (víceméně hlavně od Tango) těch příčin lagu může bejt spoustu věcí, takže je potřeba to hodně pomalu debugovat a zjistit jaká část ty lagy způsobují

Link to comment
Share on other sites

  • 0

Aha, dobře. No, nejvíce podle profileru u Self Time procent bere db_query, tudíž databáze jako taková. 54 a něco %.

 

Bude stačit takhle v pastebinu? Ten graf se mi za boha nedaří zobrazit. A mohu se prosím zeptat na postup při printfování u toho SQLite? Vím, že se tím asi bude myslet printf(query) například, Musí to být u každé akce, kde se ta databáze nebo ten špatný script vyskytuje, nebo je i jednodušší cesta?

 

Mimochodem ty lagy u 1 a 2 hráčů jsou minimální, jedna za cca 20 sekund to vidím na ukazateli času, že přeskočí o 2 vteřiny. Je to nepatrný, ale i tak vím, že je to problém a čím víc by tam bylo hráčů, tím horší by to bylo.

 

https://pastebin.com/Q1Jcnqjg


Nevím jak s tím printf pracovat co nejjednodušeji, abych to nemusel rozepsat po celým módu. Pokud je to cíl, tak asi dobrá. Ale tady vám ukážu, co mi nejvíc žere nějaký % a celkově.

 

https://pastebin.com/xzr215d6

Edited by Meric
Link to comment
Share on other sites

  • 0

Graf nieje prilis podstatny. Dolezitejsie je asi optimalizovat SQL. Ale este pred tym nez zacnes by si mohol pozriet nie len na % ale aj na average a worst time. To je cas, kolko trva vykonat tu funkciu. Ak sa ti server lagne raz za cas, moze to byt tym, ze sa nejaka funkcia vola malokedy (cize ma male %) ale trva dlho.

Ak potrebujes optimalizovat SQL, tak skus vytvorit indexy, ak ich este nemas. Taktiez ak robis velke mnozstvo INSERT/UPDATE, tak pouzi transakciu. Ak vyhladavas, snaz sa vyhladavat podla veci, ktore su indexovane. To iste zoradovanie. (index v SQL je akysi zoradeny zoznam. Cize ak napriklad vytvoris index na tabulke hracov podla mena, tak sa ulozia abecedne zoradeny podla mena. Vdaka tomu sa v nich rychlejsie vyhladava hrac s urcitim menom a nieje nutne rucne zoradovat. To vyrazne zrychli vykonavanie db_query).

PS: ale neprezen to s prilis vela indexmi, indexy zaberaju miesto a trochu spomaluju insert a update.

Edited by xhunterx
Link to comment
Share on other sites

  • 0

Graf nieje prilis podstatny. Dolezitejsie je asi optimalizovat SQL. Ale este pred tym nez zacnes by si mohol pozriet nie len na % ale aj na average a worst time. To je cas, kolko trva vykonat tu funkciu. Ak sa ti server lagne raz za cas, moze to byt tym, ze sa nejaka funkcia vola malokedy (cize ma male %) ale trva dlho.

 

Ak potrebujes optimalizovat SQL, tak skus vytvorit indexy, ak ich este nemas. Taktiez ak robis velke mnozstvo INSERT/UPDATE, tak pouzi transakciu. Ak vyhladavas, snaz sa vyhladavat podla veci, ktore su indexovane. To iste zoradovanie. (index v SQL je akysi zoradeny zoznam. Cize ak napriklad vytvoris index na tabulke hracov podla mena, tak sa ulozia abecedne zoradeny podla mena. Vdaka tomu sa v nich rychlejsie vyhladava hrac s urcitim menom a nieje nutne rucne zoradovat. To vyrazne zrychli vykonavanie db_query).

 

PS: ale neprezen to s prilis vela indexmi, indexy zaberaju miesto a trochu spomaluju insert a update.

 

Jak takový index vypadá? Já už se v těch pojmech dost ztrácím. Bylo mi zde navrhnuto printfování, abych zjistil, který script mi vyhazuje takové hodnoty nebo které scripty. Ale jestli mám printovat formáty typu UPDATE users SET a INSERT INTO, rozhodně by to trvalo dlouho + bych se v konzoli (cmd řádku) pořádně nedozvěděl asi, co s tím bude. Je i nějaká jednodušší cesta? Klidně můžu poslat celou server.db, jestli byste našli chybu tam, nebo tak. Každopádně ty indexy to je pro mě neznámá, prakticky jsem jen vytvářel table a do něj vložil a pojmenoval pole a tím jsem končil.

Link to comment
Share on other sites

  • 0

Cely dokumentacia je tu: https://sqlite.org/lang_createindex.html

Nicmenej, tebe asi staci nieco ako:
 

CREATE INDEX IF NOT EXISTS MenoIndexu ON MenoTabulky (MenoStlpca)

Potom vyhladavanie v tej tabulke podla stlpcu bude rychlejsie.

Meno indexu daj ake chces, ale ja osobne tam davam MenoTabulky_MenoStlcpu aby bolo jasne, co to je za index hned na prvy pohlad.

 

Najtipickejsi index je na tabulku hracov na stlpci s menami. Napriklad

CREATE INDEX IF NOT EXISTS Players_Name ON Players (Name)

Potom vyhldanie typu

SELECT * FROM Player WHERE Name = ?

Bude ovela rychlejsie, lebo Name (meno hraca) je ulozene abecedne.

EDIT: Mozes mat viac indexov na jednej tabulke, ak potrebujes vyhldavat/zoradovat podla viac stlpcov a mozes mat viac stlpcov v jednom indexe.
Ak das do indexu viac stlpcov, tak ak su 2 riadky rovnake podla prveho, tak sa zoradia podla druheho. Uzitocne napriklad na zoradovanie, ked chces najprv podla levelu a potom napr podla killov alebo abecedy.

Edited by xhunterx
Link to comment
Share on other sites

  • 0

A kam přesně bych ty indexy měl psát? Nejvíc zapisuji do table users, kde mám asi 120 polí pro hodnoty. A opravdu hodně používám INSERT/UPDATE, o indexování ani transakci jsem v životě neslyšel. Co se týče polí v users, nepočítám ještě asi patnáct tablů, kde se ukládají také různé hodnoty.

 

EDIT: Právě jsem zjistil, že místo každých 9 - 13 sekund se ten server lagne na několik ms už každých 8, v podstatě přesně. Tak jsem si řekl, že to musí být nějaký timer, ale za boha nevím který timer nebo které timery to mohou dělat. Protože kromě těch, které zkrátka musí být na 1000 ms přesně, tak se žádné nepotkávají.

Edited by Meric
Link to comment
Share on other sites

  • 0
A kam přesně bych ty indexy měl psát?

Pod vytvorenie tabulky. Ako mas CREATE TABLE, tak pod to rovnako vytvor index.

 

 

Nejvíc zapisuji do table users, kde mám asi 120 polí pro hodnoty.

Ako som povedal, urcite by som dal do users index na meno, kedze predpokladam, ze vyhladavas podla mena.

 

 

 

Tak jsem si řekl, že to musí být nějaký timer, ale za boha nevím který timer nebo které timery to mohou dělat.

Pozri sa na ten profiler. Timery by tam mali byt normalne, menom toho publicu a pozri sa na Worst Time. Tieto cisla ti hovoria, ako dlho sa ten public vykonava. V takomto pripade tieto cisla su dolezitejsie, nez tie %.

Pozeraj taktiez na Total Time, nie na self time. 

Edited by xhunterx
Link to comment
Share on other sites

  • 0

No já se díval na všechno. Jedno usje nechal server zapnutý asi 4 hodiny a podíval se na výsledek. Někdy u někteých funkcí jako OnPlayerConnect/Disconnect bylo worst time u total time aj 4 nebo 8 sekund. Potom jsem upravil includy tak, aby se nesetkal zcmd s izcmd (nevím proč jsem to tam měl ani) a ještě jsem zapnul case sensitive mod pro izcmd, vše za účelem zrychlení kódu a už to není takové s těmi rozdíly. Teďka mívám worst time u čehokoliv v self time i total time tak něco přes 2 sekundy, někdy 3.

 

Ale jelikož se mi to zasekává během každých 8 sekund, tak mě napadlo, že se během těch osmi sekund sešlo několik náročnějších timerů a laglo server na několik milisekund. Tak jsem experimentálně zakomentoval všechny opakující se timery a žádný efekt. Po tom, co jsem přidal systém zón, tak to na těch 8 sekund padlo z těch cca 9 - 10 sekund. Je tedy možné, že je to spíš čtením nekvalitního kódu? Je pravda, že na tomto módu jsem i s pawnem začínal, takže začátečnické chyby tam být mohou, jen jsem si jich nevšiml a doteď je nevidím.

 

Do users používám INSERT jenom jednou v celým ódu, ale UPDATE je tam faaakt hodněkrát a je fakt, že podle jména ukládám hodně, to jo. Zkusím ty indexy. Každopádn tyhle lagy mě docela vytáčej, když nemůžu za boha zjistit, co je příčinou. Timery to očividně nejsou i když to je to jediný, co mi dává smysl.

Link to comment
Share on other sites

  • 0

Díky všem, co mi zde pomáhali, zvláštní díky také uživateli xhunterx s nimž jsem problém řešil. Zjistil, že problém je jen v samotné nepřesnosti timerů a "lagy" byly jen zdánlivé. Všem ostatním samozřejmě také díky, stejně byl pravý čas mód i tak optimalizovat, na škodu to vůbec není. :-) Můžete taktéž lock, díky. 

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...