Dnes a zítra probíhá vývojářská konference Google I/O 2025. Sledovat lze na YouTube a na síti 𝕏 (#GoogleIO).
V Bostonu probíhá konference Red Hat Summit 2025. Vybrané přednášky lze sledovat na YouTube. Dění lze sledovat na síti 𝕏 (#RHSummit).
Společnost Red Hat oficiálně oznámila vydání Red Hat Enterprise Linuxu 10. Vedle nových vlastností přináší také aktualizaci ovladačů a předběžné ukázky budoucích technologií. Podrobnosti v poznámkách k vydání.
Tuto sobotu 24. května se koná historicky první komunitní den projektu Home Assistant. Zváni jsou všichni příznivci, nadšenci a uživatelé tohoto projektu. Pro účast je potřebná registrace. Odkazy na akce v Praze a v Bratislavě.
Troy Hunt představil Have I Been Pwned 2.0, tj. nový vylepšený web služby, kde si uživatelé mohou zkontrolovat, zda se jejich hesla a osobní údaje neobjevily v únicích dat a případně se nechat na další úniky upozorňovat.
Microsoft představil open source textový editor Edit bežící v terminálu. Zdrojové kódy jsou k dispozici na GitHubu pod licencí MIT.
V Seattlu a také online probíhá konference Microsoft Build 2025. Microsoft představuje své novinky. Windows Subsystem for Linux je nově open source. Zdrojové kódy jsou k dispozici na GitHubu pod licencí MIT.
Z příspěvku Turris Sentinel – co přinesl rok 2024 na blogu CZ.NIC: "Za poslední rok (únor 2024 – únor 2025) jsme zachytili 8,3 miliardy incidentů a to z 232 zemí a z jejich závislých území. Tyto útoky přišly od 6,2 milionu útočníků (respektive unikátních adres). SMTP minipot je stále nejlákavější pastí, zhruba 79 % útoků bylo směřováno na tento minipot, 16 % útoků směřovalo na minipot Telnet, 3 % útoků směřovaly na minipot HTTP a 2 % na minipot FTP. Dále jsme zaznamenali 3,2 milionu unikátních hesel a 318 tisíc unikátních loginů, které útočníci zkoušeli."
Byla vydána (Mastodon, 𝕏) nová verze 3.0.4 svobodné aplikace pro úpravu a vytváření rastrové grafiky GIMP (GNU Image Manipulation Program). Přehled novinek v oznámení o vydání a v souboru NEWS na GitLabu. Nový GIMP je již k dispozici také na Flathubu.
Byla vydána nová stabilní verze 7.4 webového prohlížeče Vivaldi (Wikipedie). Postavena je na Chromiu 136. Přehled novinek i s náhledy v příspěvku na blogu.
Dostal jsem se k práci, kde je jedním z úkolů upravování DalvikVM. To se neobejde bez neustálého kompilování celého Androidu. Jeho strom používá staré dobré(?) make
, ovšem s neuvěřitelnou hromadou Makefile
souborů, které se při každé kompilaci musí znova a znova parsovat, i když se vůbec nezměnily.
Jen pro představu, kolik toho se toho parsuje: bez toho, aby bylo vše už v diskové cache (nemám SSD), trvá minimálně 5 minut pouze naparsování všech Makefilů
(tj. bez samotné kompilace). I poté, co je vše v cache trvá parsování 30 až 60 sekund, což je naprosto neúnosné, protože je to často několikanásobně déle, než kolik zabere samotná kompilace. Pořízení SSD by to pravděpodobně moc nezrychlilo, cache v kernelu by měla být rychlejší než SSD. Výstup z make -d
má po naparsování všeho potřebného okolo 200 MB.
Pravděpodobně by bylo možné optimalizovat Makefile
soubory v Androidu, nebo dokonce make
samotný aby prováděl parsování paralerně, nicméně moje řešení je o něco jednodušší, rychlejší a více humpolácké :)
Parsováním Makefilů
a samotná kompilace vypadaly jako dvě jasně oddělené fáze celého procesu. Co kdybych tedy po naparsování všeho možného make zastavil, počkal na nějaký signál a po jeho přijetí zavolal fork()
a dále pokračoval v kompilaci v naklonovaném procesu?
Po zběžném projetí kódu make
se toto řešení ukázalo jako možné, a dokonce i velmi rychlé a jednoduché. Nebudu už zdržovat, tady je výsledný patch (proti make 4.0 z apt-get source make
v Debian Testing, mělo by to být ale stejné snad pro všechno. Je možné, že to budu ještě nějak upravovat - případné aktuálnější verze můžete najít na gistu):
--- main.c.orig 2013-10-09 06:22:40.000000000 +0200 +++ main.c 2014-10-26 01:42:21.022330558 +0200 @@ -302,6 +302,17 @@ char cmd_prefix = '\t'; +/* For the -F/--fork-hack option */ +#define FORK_HACK_PID_FILE ".make-fork-hack.pid" +static int is_forked = 0; +static int use_fork_hack = 0; +static void fork_hack_signal_handler(int sig) +{ + if(use_fork_hack && !is_forked) + remove(FORK_HACK_PID_FILE); + exit(130); +} + /* The usage output. We write it this way to make life easier for the translators, especially those trying to translate to right-to-left @@ -330,6 +341,12 @@ -f FILE, --file=FILE, --makefile=FILE\n\ Read FILE as a makefile.\n"), N_("\ + -F, --fork-hack Parses all makefiles, then waits for SIGUSR1, forks\n\ + when it arrives and continues in the forked child.\n\ + This eliminates parsing the same makefiles on every\n\ + 'make' over and over again.\n\ + WARNING: THIS IS A HACK AND MIGHT BREAK EVERYTHING!\n"), + N_("\ -h, --help Print this message and exit.\n"), N_("\ -i, --ignore-errors Ignore errors from recipes.\n"), @@ -398,6 +415,7 @@ { 'D', flag, &suspend_flag, 1, 1, 0, 0, 0, "suspend-for-debug" }, #endif { 'e', flag, &env_overrides, 1, 1, 0, 0, 0, "environment-overrides", }, + { 'F', flag, &use_fork_hack, 1, 0, 0, 0, 0, "fork-hack", }, { 'h', flag, &print_usage_flag, 0, 0, 0, 0, 0, "help" }, { 'i', flag, &ignore_errors_flag, 1, 1, 0, 0, 0, "ignore-errors" }, { 'k', flag, &keep_going_flag, 1, 1, 0, 0, &default_keep_going_flag, @@ -1460,6 +1478,27 @@ die (0); } + /* Trigger build on fork-hack daemon */ + if(use_fork_hack) + { + FILE *f = fopen(FORK_HACK_PID_FILE, "r"); + if(f) + { + char buf[64] = { 0 }; + char *res UNUSED = fgets(buf, sizeof(buf), f); + fclose(f); + + pid_t daemon_pid = atoi(buf); + if(daemon_pid > 0 && kill(daemon_pid, SIGUSR1) == 0) + { + printf("Sent SIGUSR to %d, exiting.\n", daemon_pid); + die(0); + } + } + + signal(SIGINT, fork_hack_signal_handler); + } + if (ISDB (DB_BASIC)) print_version (); @@ -2132,6 +2171,43 @@ OUTPUT_UNSET (); output_close (&make_sync); + /* FORK HACK: wait for SIGUSR1 here, then fork and continue + with build in the child.*/ + if(use_fork_hack) + { + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_BLOCK, &mask, NULL); + + FILE *f = fopen(FORK_HACK_PID_FILE, "w"); + if(f) + { + fprintf(f, "%d\n", getpid()); + fclose(f); + } + + while(1) + { + int recv; + printf("\n\aWaiting for SIGUSR1, command to spawn child and continue: kill -USR1 %d or %s -F in the same folder\n\n", getpid(), argv[0]); + if(sigwait(&mask, &recv) == 0) + { + pid_t p = fork(); + if(p == 0) // child + { + is_forked = 1; + break; + } + else + { + printf("Started child with pid %d, waiting for it to finish\n", p); + waitpid(p, &recv, 0); + } + } + } + } + if (read_files != 0) { /* Update any makefiles if necessary. */ @@ -3411,7 +3487,9 @@ if (verify_flag) verify_file_data_base (); - clean_jobserver (status); + // Hangs for some reason if executed in forked one, I don't think I need it + if(!is_forked) + clean_jobserver (status); if (output_context) {
Jak je vidět, je to velmi jednoduché, malé a rychlé, ale ušetří mi to spoustu času. Na konci je vidět, že nějaká část make
se s tím nemohla vyrovnat, nicméně je to až ve fázi, kdy se celý make ukončuje a nemyslím si, že zrovna jobservery k něčemu potřebuji, tak jsem neztrácel čas debugováním čím by to mohlo být.
tassadar@nymeria:~/android/android-repo-aosp$ make -j4 -F & *parsování makefilů* Waiting for SIGUSR1, command to spawn child and continue: kill -USR1 404 or make -F in the same folder tassadar@nymeria:~/android/android-repo-aosp$ make -F Sent SIGUSR to 404, exiting. Started child with pid 8982, waiting for it to finish *kompilace*
Poté, co je kompilace hotová, můžu znovu zavolat make -F
a nic se už parsovat nebude. Make
je navíc postaven tak, že detekuje změny v souborech až po naparsování Makefile
souborů, takže to udělá vždy až nový child.
Všechny argumenty se berou z toho prvního volání make
, tj. targety a switche u druhého make -F
už jsou zbytečné (proto mám -j4 v tom prvním make
a ne v tom druhém). Myslím si, že by bylo možné přeposlat nové targety a switche z toho druhého volání make
, ale momentálně to nepotřebuji.
Když čas od času změním nějaký Makefile
, jednoduše zabiju původní make
proces a zase ho spustím znovu aby to všechno naparsoval.
Na to, jak nesmyslně jednoduchý nápad to je, tak výsledek funguje až překvapivě dobře a ušetří mi spoustu času. Nevím sice o žádném projektu kromě Androidu, který by měl takové problémy se složitostí Makefile
souborů, že by potřeboval takovýto hack, ale třeba to bude pro někoho z vás užitečné.
PS: make má nejšílenejší způsob odsazování kódu, který jsem kdy viděl. Kromě toho má jeho int main()
přes 1500 řádků a dost špatně se v něm orientuje.
Tiskni
Sdílej:
return 4;
return 4;
nemyslím si, že zrovna jobservery k něčemu potřebujiJobserver je v make potřeba kdykoliv, když se pouští paralelní kompilace, tedy soudě podle příkladů i ve vašem případě. Bez toho aniž bych koukal do kódu si dovolím tipnout, že to při ukončování čeká až všechny childy doběhnou - a viset by to tedy mohlo proto, že díky forkování mu pak "nesedí účetnictví". Pokud tedy tu metodu nevoláte, mohlo by v určitých případech stát, že tam zůstane něco zbytečně viset.
/* Close the write side, so the read() won't hang. */ close (job_fds[1]); while (read (job_fds[0], &token, 1) == 1)Ta
jobs_fd
pajpa je otevřená ještě před forkem, tj. po forknutí ji má otevřenou jak "daemon", tak i ten make co bude kompilovat. Ten kód ji pak zavře jednou, ale daemon ji má pořád otevřenou -> read nikdy nevrátí EOF. Řešením je otevírat tu pajpu až v childu, opraveno v patchi na gistu: https://gist.github.com/Tasssadar/f9f38d27253e88aa740b.
return 4;
A nedala by se rozparsovaná data kešovat v jednom binárním souboru, který by odpovídal obsahu paměti po načtení makefilů?To byla druhá možnost kdyby
fork()
pokus nevyšel, ale ukládání a načítání všech datových stuktur make by bylo pravděpodobně mnohem složitější.
A nedalo by se předřadit velkému makefile malý, který by kouknul, zda se něco nezměnilo a pokud ano, spustil ten velký makefile?Ano, pravděpodobně by šlo něco takového vygenerovat. Ale opět mnohem časově náročnejší na výrobu, nicméně patches welcome :)
return 4;
$ mv Makefile Makefile.orig $ cat Makefile .orig: * make -f Makefile.orig && touch .orig $ make
Makefile
, ale hromada *.mk souborů, která se do sebe různě includuje:
$ find -name *.mk | wc -l 4771 $
return 4;
return 4;
make -pqB | sed '1,/^. Implicit Rules/d;/^[\x23]/d;/^$/d;' > preparsed.mk make -f preparsed.mk -j4Ten sed je tam jen proto, aby odstranil některé zbytečné části z výstupu, čtení a parsování komentářů přeci jen taky něco stojí. Teoreticky by to mohlo pomoct pokud ty makefily obsahují hodně logiky nebo velké kusy podmíněného kódu který se nakonec vůbec nepoužije. Docela by mě zajímalo vidět jak moc nebo málo na tomhle konkrétním projektu tenhle jednoduchý trik ovlivní dobu kompilace.
gcc -MM
) a na tom už nezáviset.
Makefile
, jen s hromadou include
volání, kdežto ta práce mluví o samostatných Makefile
a spouštění make
pro každou složku.
return 4;