Nejdůležitější jsou tyto dva řádky:<app_config>
<app>
<project_max_concurrent>14</project_max_concurrent>
<name>minirosetta</name>
<max_concurrent>14</max_concurrent>
<cpu_versions>
<cpu_usage>1</cpu_usage>
</cpu_versions>
</app>
</app_config>
1. <project_max_concurrent>xx</project_max_concurrent>
2. <max_concurrent>yy</max_concurrent>
Položka č.1. se píše na začátek editace app_config.xml a říká BM, že pro daný projekt jako celek nemá spustit více než xx jednotek. Pokud chcete spustit 14 jednotek daného projektu xx=14.
Pokud počítáte více podprojektů naráz a chcete jim přerozdělit počet vláken na každý podprojekt, pak musíte editovat další řádky v app_config.xml a vložit ke každému podprojektu řádek s položkou č.2. Tudíž dejme tomu lze nastavit aby v projektu WCG jelo počítání podprojektu AIDS yy=10, další řádek s položkou číslo 2. TBC yy=8 a Ebola yy=14 . Tím je součet 32 vláken CPU přerozdělen mezi tři podprojekty. Pokud máte nastaveno na účtu i počítáni beta jednotek a v app_config.xml je nemáte zapsány jako podprojekt, tak BM ví, že může spustit až xx=32 jednotek celkem. Máte to tedy pojištěné právě tou prvni položkou na začátku skriptu app_config.xml.
Takže shrnuto položka č.1 je v app_configu.xml pouze jednou a to na začátku skriptu, a položka č.2 může být v takovém množství, podle toho kolik podprojektů hodláte počítat a kolik vám to dovoluje množství vláken CPU. Položka xx je vždy nadřazena, i kdyby součet yy všech podprojektů v daném projektu byl vyšší než xx.
Aby bylo nastavení ještě dokonalejší, tak můžete takovýto soubor app_config.xml vložit do adresáře každého projektu který počítáte a nastavit si jej dle vlastních potřeb. Tedy například aby na 32 jádrovém Golemu jelo vždy max 10 jednotek Asteroids, 10 jednotek WCG, 6 jednotek Rosetty a 6 jednotek PrimeGrid.
EDIT by nenym
Může se stát, resp. zákonitě se musí stát, že při záměru provozovat dva a více projektů paralelně s nastaveným parametrem <max_concurrent> či <project_max_concurrent> natáhne jeden projekt full buffer a další si o práci neřeknou. Pak je v provozu 1/2, 1/3 ... 1/4 jader, protože <project_max_concurrent>n</project_max_concurrent>, kde n= 1/2, 1/3 ... 1/4 počtu jader. Existuje na to finta, kterou provozuji dlouhá léta a začal jsem ji aplikovat nejdříve při lovení exotů. Jde o to udržet boinc core stále hladové.
Jedná se o známý vkliberův script pro ponechání určitého počtu aktivních jednotek daného projektu, ostatní jsou suspendované. Script nerozlišuje podprojekty/aplikace, pozastavuje v pořadí došlých úloh - což nemusí být nutně totéž, jako pořadí DL. Na projektech s dynamickým přidělováním DL podle FLOPSů tasku tedy velmi opatrně s velikostí zásoby - typicky CSG Wildlife a Seti. Scripty se spouští s více či méně rozumným odstupem schedulerem.
Např. pro kombinaci ODLK + ODLK1 spouštím scripty s odstupem 1,5 minuty a frekvencí 3 minuty, protože jde o krátké úlohy. Pro kombinaci Acoustics + Asteroids mám odstup 5 minut, frekvenci 10 minut. Počet uvolněných jednotek mám o 3 větší, než je max_concurrent u úloh pod 30 minut, u ostatních stačí o 2. U velmi krátkých (GoofyxGridCPU, SRBase shorty) mám nastaven dvojnásobek, odstup 1 minuta, frekvence 2 minuty. IMHO není potřeba zvláštního mozkového úsilí k extrapolaci návodu na libovolný smysluplný počet projektů.
Jest otázkou, zda je pak nutné a praktické za dávat parametry (u všech projektů), které jsou předmětem tohoto postu. Záleží na poměru RS projektů, zamýšleného hlavního a vedlejšího efektu a vkusu každého soudruha. Já typicky stanovuji u jednoho projektu a u zbytku nikoli, nějaxe to samo poskládá při správné volbě poměru RS a parametru <rec_half_life_days>0.100000</rec_half_life_days> v cc_config.xml. Jak vidíte, používám 2,5 hodiny, což nutí core k rozložení práce podle RS kontinuálně, defaultní hodnota 10 dnů vede k velkým výkyvům a zdánlivému nerespektování poměrů RS.
Pro jistotu zopakuji script, ať to máte pohromadě.
Kód: Vybrat vše
/*!
Autor : Vit Kliber, Czech National Team o.s.
Vytvoreno : 11.01.2012
Nazev : boinc_manage_wcg_tasks.js
Zdroj : boinc_framework.js
Popis : Skript vychazi z Kostry skriptu pro budouci skripy pro manipulaci s jednotkami
( url=http://forum.czechnationalteam.cz/viewtopic.php?p=53537#p53537 )
Tento provadi manipulaci s jednotkami projektu WCG ( http://www.worldcommunitygrid.org/ )
Pozadavek je nasledujici : nechat pocitat maximalne 8 <pocet_aktivnich_jednotek> jednotky
a ostatni pozastavit
*/
// adresa projektu (nejpravdepodobneji bude skript manipulovat s jednotkami jednoho projektu)
var projekt = "http://www.worldcommunitygrid.org/";
// pocet maximalne aktivnich jednotek
var pocet_aktivnich_jednotek = 8;
// verze boinc, je zjistena funkci verze(), pokud je prazdne nepodarilo se zjistit a skript se ukonci
var boinc_verze = "";
// prikaz pro zjisteni aktualnich jednotek v BOINC
var boinc_jednotky = "";
// prikaz pro manipulaci s jednotkou
var boinc_jednotka = "";
// 0 = Debug ON, 1 = Debug OFF ... jestli se maji vypisovat pri behu hlaseni
var debug_code = 1;
// corrected by nenym: co bylo puvodně uvedeno bylo logicke, ale naopak. Nyni je to patologicke, ale správne. Do kodu nepolezu.
// pro vypsani ladiciho textu pri behu skriptu
function alert(text)
{
if (debug_code != 1)
{
return (new ActiveXObject("WScript.Shell")).Popup(text, 0, WScript.ScriptName, 64);
}
}
// zjisti verzi BOINC
function verze()
{
// definice noveho objektu WScript.Shell (umozni mi spoustet externi prikazy)
var objekt_shell = new ActiveXObject("WScript.Shell");
// definice metody Exec, spusti prikaz a pointer uchova v promene <objekt_exec>
var objekt_exec = objekt_shell.Exec("boinccmd.exe --version");
// textova promena do ktere se ulozi cely obsah standardniho vystupu predchazejiciho prikazu
var verze_text = objekt_exec.StdOut.ReadAll();
alert(verze_text);
// promena <verze_text> by mela nyni obsahovat jeden radek s timto obsahem (podle verze) : "boinccmd, built from BOINC 6.12.33"
// uchovam pozici textu BOINC z promene <verze_text>
var pozice = verze_text.indexOf("BOINC");
// jestlize je ruzne od -1 tak v obsahu <verze_text> je na pozici <pozice> text BOINC (podarilo se spustit prikaz "boinccmd.exe --version")
if (pozice != -1)
{
// z <verze_text> vyriznu text od pozice <pozice> (prictu 6 ... delka textu BOINC a mezera)
boinc_verze = verze_text.substr(6+pozice);
// nyni je v <boinc_verze> hodnota 6.12.33
alert(boinc_verze);
return true;
}
else // verzi BOINC se nepodarilo zjistit, vracim FALSE
{
return false;
}
}
// funkce pro porovnani dvou verzi ve tvaru X.X.X, ocekava promene ve tvaru pole
function porovnani_verzi(verze1, verze2)
{
// promenne <verze1> a <verze2> jsou pole textovych retezcu, tak je prevedu na cisla
verze1[0] = (parseInt(verze1[0]) || 0);
verze1[1] = (parseInt(verze1[1]) || 0);
verze1[2] = (parseInt(verze1[2]) || 0);
verze2[0] = (parseInt(verze2[0]) || 0);
verze2[1] = (parseInt(verze2[1]) || 0);
verze2[2] = (parseInt(verze2[2]) || 0);
if (verze2[0] != verze1[0])
return (verze2[0] > verze1[0]);
else
{
if (verze2[1] != verze1[1])
return (verze2[1] > verze1[1]);
else
{
if (verze2[2] != verze1[2])
return (verze2[2] > verze1[2]);
else
return true;
}
}
}
// odstrani z retezce koncove mezery a znak konce radku
function trim(text)
{
return text.replace(new RegExp("[" + "\\n\\s" + "]+$", "g"), "");
}
// provede nastaveni promenych podle verze BOINC
function init()
{
// od verze BOINC 6.12 vcetne je jina syntaxe programu boinccmd
var verze_pro_porovnani = "6.12.0";
// zavolam funkci ktera zjisti verzi BOINC a pokud se to podari nastavim zakladni promenne
if (verze())
{
alert("Porovnavam verzi " + boinc_verze + " s referencni verzi " + verze_pro_porovnani);
if (porovnani_verzi(verze_pro_porovnani.split('.'),boinc_verze.split('.')))
{
// Verze BOINC >= 6.12
boinc_jednotky = "boinccmd.exe --get_tasks";
boinc_jednotka = "boinccmd.exe --task";
}
else
{
// Verze BOINC < 6.12
boinc_jednotky = "boinccmd.exe --get_results";
boinc_jednotka = "boinccmd.exe --result";
}
return true;
}
else // funkce pro zjisteni verze se nepodarila, vracim FALSE
{
return false;
}
}
/* MAIN */
// zavolam funkci ktera nastavi zakladni promenne
if (init())
{
// v tuto chvili je uspesne zjistena verze a
// uspesne nastavene zakladni promenne <boinc_jednotky> a <boinc_jednotka>
// definuji novy objekt WScript.Shell (umozni mi spoustet externi prikazy)
var objekt_shell = new ActiveXObject("WScript.Shell");
// definuji metodu Exec, spusti prikaz <boinc_jednotky> a pointer uchova v promene <objekt_exec>
var objekt_exec = objekt_shell.Exec(boinc_jednotky);
// textova promena do ktere se ulozi cely obsah standardniho vystupu predchazejiciho prikazu
var text_vystup = objekt_exec.StdOut.ReadAll();
// na konec <text_vystup> jeste pridam jednu prazdnou sekci abych pak nemusel resit konec
text_vystup = text_vystup + '\n' + "X) -----------" + '\n';
// promena <text_vystup> by mela nyni obsahovat cely standardni vystup ktery vraci prikaz "boinccmd.exe --get_tasks"
// definuji pole do ktereho prevedu obsah <text_vystup>
var pole_vystup = new Array();
// oddelovacem bude znak EOL (EndOfLine) neboli \n
// pole <pole_vystup> se naplni tak, ze kazdy dalsi radek bude v dalsim prvku
// 1. radek v pole_vystup[0], 2. radek v pole_vystup[1], ...
pole_vystup = text_vystup.split('\n');
// nyni musime v cyklu projit vsechny radky (vyzaduje znalost vystupu "boinccmd.exe --get_tasks")
// jednotlive jednotky jsou oddeleny v sekcich a o kterou jednotku se jedna zjistime az uvnitr sekce
// takze si do nejakych promenych musime ukladat co budeme dale potrebovat a az sekce skonci
// (zacne nova ... proto jsme si na konec pridali jednu prazdnou sekci pro ukonceni posledni sekce)
// tak se rozhodneme podle obsahu ulozenych promenych co dal podnikneme
// pripravim si promenne
var b_name = ""; // nazev jednotky (name)
var b_state = ""; // stav jednotky (state) 2 ... Pocita nebo Pripraven nebo Cekam na zpracovani, 4 ... Odesilam, 5 ... Odeslan. Pripraven k ohlaseni
var b_scheduler_state = ""; // stav scheduleru jednotky (scheduler state) 0 ... Pripraven, 1 ... Cekam na zpracovani, 2 ... Pocita
var b_suspended_via_GUI = ""; // pozastaveno (suspended via GUI) no, yes
var b_active_task_state = ""; // stav jednotky (active_task_state) 0 ... Pripraven, 1 ... Pocitam, 9 ... Cekam na zpracovani
var ano = 0; // 1 = ANO, 0 = NE ... jestli se jedna o projekt ktery nas zajima
var ind = 0; // index pro pole do ktereho budu ukladat hodnoty
var jednotka = new Array(); // pole do ktereho se budou ukladat radky
// kazdy radek bude zase pole ve tvaru ([0] = name, [1] = state, [2] = scheduler_state, [3] = suspended_via_GUI, [4] = active_task_state)
// a ted cyklus pres cele pole
for(var i = 0; i < pole_vystup.length; i++)
{
// jestlize radek obsahuje text ") -----------" tak se jedna o zacatek nove sekce
if (pole_vystup[i].indexOf(") -----------") != -1)
{
// jestlize je <ano> nastaveno (jedna se o projekt ktery nas zajima) je treba provest pozadovanou akci
if (ano == 1) {
alert("NACITANI JEDNOTEK (" + ind + ") :\nProjekt:" + projekt + "\nJednotka:" + b_name + "\nStav:" + b_state + "\nStav scheduleru:" + b_scheduler_state + "\nsuspended_via_GUI:" + b_suspended_via_GUI + "\nactive_task_state:" + b_active_task_state);
// dale me budou zajimat pouze jednotky ktere maji stav jednotky = 2 (state), ty ktere jsou ve stavu Odesilam nebo Odeslany uz resit nebudu, doplnen kod by nenym: stav jednotky = "downloaded"
if (b_state == 2 || b_state == "downloaded") {
// ulozim hodnoty do pole
jednotka[ind] = new Array(b_name, b_state, b_scheduler_state, b_suspended_via_GUI, b_active_task_state);
// a zvednu index o 1
ind = ind + 1;
}
}
// a po akci si opet vynulujeme promenne
b_name = "";
b_state = "";
b_scheduler_state = "";
b_suspended_via_GUI = "";
b_active_task_state = "";
ano = 0;
}
// jestlize radek obsahuje text " name: " tak se jedna o radek kde je nazev jednotky
else if (pole_vystup[i].indexOf(" name: ") != -1)
{
// a nazev jednotky si uchovam do <b_name>
b_name = trim(pole_vystup[i].substr(9));
}
// jestlize radek obsahuje text " state: " tak se jedna o radek kde je stav jednotky
else if (pole_vystup[i].indexOf(" state: ") != -1)
{
// a stav jednotky si uchovam do <b_state>
b_state = trim(pole_vystup[i].substr(10));
}
// jestlize radek obsahuje text " scheduler state: " tak se jedna o radek kde je stav scheduleru jednotky
else if (pole_vystup[i].indexOf(" scheduler state: ") != -1)
{
// a stav scheduleru jednotky si uchovam do <b_scheduler_state>
b_scheduler_state = trim(pole_vystup[i].substr(20));
}
// jestlize radek obsahuje text " suspended via GUI: " tak se jedna o radek kde je informace o pozastaveni jednotky
else if (pole_vystup[i].indexOf(" suspended via GUI: ") != -1)
{
// a informaci o pozastaveni jednotky si uchovam do <b_suspended_via_GUI>
b_suspended_via_GUI = trim(pole_vystup[i].substr(22));
}
// jestlize radek obsahuje text " active_task_state: " tak se jedna o radek kde je informace o active_task_state
else if (pole_vystup[i].indexOf(" active_task_state: ") != -1)
{
// a informaci o active_task_state si uchovam do <active_task_state>
b_active_task_state = trim(pole_vystup[i].substr(22));
}
// jestlize radek obsahuje text " project URL: " tak se jedna o radek kde je adresa projektu
else if (pole_vystup[i].indexOf(" project URL: ") != -1)
{
// a jestli radek obsahuje i adresu projektu ktery me zajima, tak si nastavim <ano>
if (pole_vystup[i].indexOf(" project URL: " + projekt) != -1)
{
ano = 1;
}
else
{
ano = 0;
}
}
}
// jestlize je pole naplnene, tak <ind> bude vetsi nez 0
if (ind > 0)
{
/*
// cele pole projdeme radek po radku a vypiseme
for(var i = 0; i < ind; i++)
{
alert("VYPIS JEDNOTEK (" + i + ") :\nProjekt:" + projekt + "\nJednotka:" + jednotka[i][0] + "\nStav:" + jednotka[i][1] + "\nStav scheduleru:" + jednotka[i][2] + "\nsuspended_via_GUI:" + jednotka[i][3] + "\nactive_task_state:" + jednotka[i][4]);
}
*/
// pro nas pozadavek je ale vhodne prochazet pole od konce, a jednotky postupne pozastavit (nebo nechat pozastavene)
// a teprve az se dostaneme na zacatek pole, tak prvnich nekolik jednotek pustit (nebo nechat pustenych)
for(var i = ind-1; i >= 0; i--)
{
alert("VYPIS JEDNOTEK OD KONCE (" + i + ") :\nProjekt:" + projekt + "\nJednotka:" + jednotka[i][0] + "\nStav:" + jednotka[i][1] + "\nStav scheduleru:" + jednotka[i][2] + "\nsuspended_via_GUI:" + jednotka[i][3] + "\nactive_task_state:" + jednotka[i][4]);
// v promenne <pocet_aktivnich_jednotek> je pocet jednotek ktere se maji pocitat
if (i < pocet_aktivnich_jednotek)
// vsechny jednotky ktere maji index <i> mensi nez <pocet_aktivnich_jednotek> pustime
{
// zjistime jestli je jednotka pozastavena
if (jednotka[i][3] == "yes")
{
// a jestli ano tak ji pustime
alert("Spoustim jednotku " + jednotka[i][0]);
var resume_exec = objekt_shell.Exec(boinc_jednotka + " " + projekt + " " + jednotka[i][0] + " resume");
}
}
else
// vsechny ostatni pozastavime
{
// zjistime jestli neni jednotka pozastavena
if (jednotka[i][3] == "no")
{
// a jestli neni tak ji pozastavime
alert("Zastavuji jednotku " + jednotka[i][0]);
var suspend_exec = objekt_shell.Exec(boinc_jednotka + " " + projekt + " " + jednotka[i][0] + " suspend");
}
}
}
}
}
alert("Konec.");
bych doplnil o nutnost údržby adres projektů, které přejdou na https protokol. Script při změně URL celkem logicky přestane fungovat.vkliber píše:Soubor uložit do stejného adresáře, kde je boinccmd.exe. Po uložení souboru WCG_manage.js na něj kliknout pravým tlačítkem myši a kliknout na "Vlastnosti". Ve vlastnostech se přepnout na kartu "Skript", zaškrtnout "Zastavit skript po:" a nastavit 10 sekund a odškrtnout "Zobrazit logo ...". Dále vytvořit zástupce ve stejném adresáři (chytnout soubor WCG_manage.js pravým tlačítkem myši, posunout a pustit a stisknout "Vytvořit zde zástupce". Vytvořeného zástupce přejmenovat na WCG_manage.js, dále na něj kliknout pravým tlačítkem a a kliknout na "Vlastnosti". Ve vlastnostech se přepnout na kartu "Zástupce", zkontrolovat jestli hodnota "Spustit v:" odpovídá adresáři ve kterém se nachází skript WCG_manage.js a nastavit "Spustit:" na hodnotu "V minimalizovaném okně".
Tím je připravený skript ke spuštění. Je možno odzkoušet tak, že spustíte BOINC Manager aktivujte "přebytečné" jednotky, a pak poklepete na WCG_manage.js. Jednotky by se měly označit jako pozastavené.
Dále je nutné zařadit skript WCG_manage.js do naplánovaných úloh ve Windows, tady se postup pro WinXP už výrazně liší od W7 a W10, proto ho nebudu podrobně popisovat. Každý ať si taky zvolí svůj časový plán.