Jak získat čas spuštění skriptu

Prostor jádra vs. uživatelský prostor
CS Architecture

Před několika týdny jsem pracoval na zábavném projektu pro dveřní monitor s Raspberry Pi 3 model B a shell skriptování. Nedávno jsem připojil kameru k Pi a aktualizoval skript tak, aby byl obrázek pořízen při otevření dveří a poslán jako připojený soubor v e-mailovém oznámení.

Jedním z problémů, na který jsem narazil, bylo to, že doba spuštění skriptu se významně zvýšila z několika sekund zpočátku na 17,58 s. Byl jsem schopen identifikovat a izolovat dobu provádění každého řádku ve skriptu. Uvědomil jsem si, že provedení příkazu raspistill trvalo 5,8 sekundy. To má za následek, že zcela chybí fotografie osoby otevírající dveře.

jak zkrátit dobu provádění raspistillu

Jednoduchý raspistill následovaný značkou „- help“ na terminálu poskytl další informace o příkazech parametrů obrazu:

pi @ raspberrypi: ~ $ raspistill --help
Spouští kameru po určitou dobu a na požádání provede zachycení JPG na konci
použití: raspistill [možnosti]
Příkazy parametrů obrázku
...
-t, --timeout: Čas (v ms) před vyfotografováním a vypnutím (pokud není uvedeno, nastaveno na 5 s)

Byl jsem schopen zkrátit dobu provádění raspistillu na několik milisekund zadáním doby, než bude snímek pořízen na skriptu následujícím způsobem:

Jak efektivně využít čas spuštění skriptu

Během tohoto procesu se dozvím o příkazu time, který se používá k získání času potřebného k provedení jiného příkazu nebo skriptu:

čas yourscript.sh // získat provedení skriptu
time ls // získat čas provedení příkazu ls

který dal následující výsledek:

Snímek obrazovky terminálu s příkazem „time ls“

Nyní si můžete všimnout, že příkaz time poskytuje skutečný, uživatelský a systémový čas. Porozumění prostoru uživatelů vs. prostoru jádra. Jedna z těchto věcí není jako druhá. Skutečný označuje skutečný uplynulý čas; Uživatel a Sys označují čas procesoru používaný pouze procesem.

Statistiky reálného, ​​uživatelského a syrského procesu
  • Reálný je čas nástěnných hodin - čas od začátku do konce hovoru. Toto je veškerý uplynulý čas včetně časových řezů používaných jinými procesy a času, který proces tráví blokovaný (například pokud čeká na dokončení I / O).
  • Uživatel je množství času CPU stráveného v kódu uživatelského režimu (mimo jádro) v procesu. Toto je pouze skutečný čas CPU použitý při provádění procesu. Ostatní procesy a čas, který proces utrácí, se do tohoto obrázku nezapočítávají.
  • Sys je množství času CPU stráveného v jádře v procesu. To znamená, že se na rozdíl od kódu knihovny, který je stále spuštěn v uživatelském prostoru, provádí čas CPU strávený v systémových voláních v jádře, na rozdíl od kódu knihovny. Stejně jako „uživatel“ i tento proces používá pouze čas CPU. Níže je uveden stručný popis režimu jádra (známý také jako režim supervisor) a mechanismu vyvolání systému.

Uživatel + Sys vám řekne, kolik skutečného času procesoru využil váš proces. Všimněte si, že se to týká všech procesorů, takže pokud má proces více vláken (a tento proces běží na počítači s více než jedním procesorem), mohl by potenciálně překročit dobu nástěnné hodiny hlášenou Real (což se obvykle vyskytuje). Vezměte na vědomí, že ve výstupech tyto údaje zahrnují čas uživatele a Sys všech podřízených procesů (a jejich potomků), kdy mohly být shromážděny, např. čekáním (2) nebo waitpid (2), ačkoli základní volání systému vrátí statistiku procesu a jeho podřízeným samostatně.

Počátky statistik vykazovaných podle času (1)

Statistiky vykazované podle času jsou shromažďovány z různých systémových volání. 'Uživatel' a 'Sys' pocházejí z čekání (2) nebo časů (2), v závislosti na konkrétním systému. „Skutečné“ se počítá od začátku a konce času získaného z volání gettimeofday (2). V závislosti na verzi systému mohou být podle času shromažďovány různé další statistiky, například počet přepínačů kontextu.

Na strojích s více procesory může mít vícevláknový proces nebo proces rozvětvení dětí uplynulý čas menší než celkový čas CPU - protože různé vlákna nebo procesy mohou běžet paralelně. Také vykazované časové statistiky pocházejí z různých původů, takže časy zaznamenané pro velmi krátké průběžné úkoly mohou podléhat chybám zaokrouhlování, jak ukazuje příklad uvedený v původním plakátu.

Krátký primer v režimu jádra vs. uživatel

V operačním systému Unix nebo v jakémkoli operačním systému chráněné paměti se režim „jádro“ nebo „supervizor“ vztahuje na privilegovaný režim, ve kterém může CPU pracovat. Určité privilegované akce, které by mohly ovlivnit zabezpečení nebo stabilitu, lze provést pouze tehdy, pokud CPU v tomto systému pracuje režim. Tyto akce nejsou k dispozici pro kód aplikace.

Příkladem takové akce může být manipulace MMU za účelem získání přístupu do adresního prostoru jiného procesu. Normálně to kód uživatelského režimu nemůže udělat (s dobrým důvodem), i když může požadovat sdílenou paměť z jádra, které by bylo možné číst nebo zapisovat více než jedním procesem. V tomto případě je sdílená paměť výslovně vyžádána z jádra pomocí zabezpečeného mechanismu a oba procesy se k ní musí explicitně připojit, aby ji mohly používat.

Privilegovaný režim se obvykle označuje jako režim „kernel“, protože jádro je prováděno CPU běžícím v tomto režimu. Aby bylo možné přepnout do režimu jádra, musíte vydat specifickou instrukci (často nazývanou past), která přepíná CPU tak, aby běžel v režimu jádra a spouští kód z konkrétního umístění drženého ve skokové tabulce.

Z bezpečnostních důvodů se nemůžete přepnout do režimu jádra a spouštět libovolný kód - pasti jsou spravovány prostřednictvím tabulky adres, na kterou nelze zapisovat, pokud CPU není spuštěno v režimu správce. Uvíznete v pasti s explicitním číslem pasti a adresa je vyhledána ve skokové tabulce; jádro má konečný počet kontrolovaných vstupních bodů.

Volání „systému“ v knihovně C (zejména ta, která jsou popsána v části 2 manuálových stránek), mají komponentu v uživatelském režimu, což je to, co skutečně voláte z vašeho programu C. V zákulisí mohou vydat jedno nebo více systémových volání do jádra za účelem provádění specifických služeb, jako jsou I / O, ale stále mají kód spuštěný v uživatelském režimu.

Je také možné přímo vydat pasti do režimu jádra z libovolného kódu v uživatelském prostoru, i když budete možná potřebovat napsat úryvek jazyka sestavení, abyste správně nastavili registry pro volání. Zde najdete stránku popisující systémová volání poskytovaná jádrem Linux a konvence pro nastavení registrů.

Více o „sys“

Existují věci, které váš kód nemůže udělat z uživatelského režimu - věci, jako je přidělování paměti nebo přístup k hardwaru (HDD, síť atd.). Ty jsou pod dohledem jádra a to je dokáže samo. Některé operace, které provádíte (například malloc orfread / fwrite), vyvolají tyto funkce jádra a budou se počítat jako čas sys. Bohužel to není tak jednoduché, jako „každé volání na Malloc bude započítáno do času“ sys ”.

V C je funkce knihovny malloc použita k alokaci bloku paměti na haldě. Program přistupuje k tomuto bloku paměti pomocí ukazatele, který se vrací malloc. Když již paměť není potřeba, ukazatel je předán do volného stavu, který rozdává paměť, takže ji lze použít pro jiné účely.

Volání na malloc provede nějaké vlastní zpracování (stále se počítá v 'uživatelském' čase) a pak někde podél toho, jak může volat funkci v jádře (počítáno v 'sys' čase). Po návratu z volání jádra bude v 'user' ještě nějaký čas a malloc se vrátí k vašemu kódu. Pokud jde o to, kdy dojde k přepnutí, a kolik z toho se utratí v režimu jádra ... nemůžete říct. Závisí to na implementaci knihovny. Také jiné zdánlivě nevinné funkce mohou také používat malloc a podobně v pozadí, které pak bude mít opět nějaký čas v „sys“.

Některé obsahy tohoto článku jsou kombinací odpovědí původně zveřejněných na Stack Overflow
Pokud se vám tento článek líbil, může se vám také líbit „Jak vytvořit obousměrnou aplikaci pro internet věcí / chat s Pythonem“
Prosím, dejte mu několik tleskání pro podporu!
Na zdraví!!!