31.08.2010, autor: Robert Krejčí, kategorie: Signály

Využití preprocesoru PHP pro generování zdrojových kódů v jazyce C

Příspěvek na 8. mezinárodní konferenci IEEE Králíky 2010

Tento příspěvek se zabývá efektivní metodou, která usnadňuje a zpřehledňuje programování a vývoj algoritmů, se zaměřením na rozpoznávání řeči na hardwarových platformách s omezenými systémovými prostředky. Článek pojednává o využití skriptovacího jazyka PHP jako preprocesoru pro vytváření zdrojových kódů v programovacím jazyce C, které jsou následně zkompilovány do výsledného programu. Pomocí této metody lze pohodlně generovat zdrojové kódy datových struktur, ale i samotné bloky programů v závislosti na konfiguračním nastavení. Výhoda této metody spočívá v jednoduchosti propojení napsaných a generovaných kódů.

Robert Krejčí

České vysoké učení technické v Praze
Fakulta elektrotechnická
Katedra teorie obvodů
Laboratoř zpracování řečových a biologických signálů
Czech Republic

1 Úvod

Standard programovacího jazyka C umožňuje využívat tzv. direktivy preprocesoru, kterými je možné definovat základní konstanty programu (např. #define PLATFORM C674x), vytvářet často se opakující kód pomocí tzv. maker (např. #define mUARTSetMIDI UART_set(31250)), nebo např. řídit podmíněný překlad části kódu v závislosti na konfiguraci programu. Např.:

#ifdef PLATFORM && PLATFORM==C674x
  #include "fft/fft-C674x-optimised.h"
#else
  #include "fft/fft-general.h"
#endif

Programovací jazyk C: direktivy preprocesoru

  • Definice konstant programu:
    #define PLATFORM C674x

  • Makra: často se opakující kód:
    #define mUARTSetMIDI UART_set(31250)

  • Řízení podmíněného překladu:

    #ifdef PLATFORM && PLATFORM==C674x
      #include "fft/fft-C674x-optimised.h"
    #else
      #include "fft/fft-general.h"
    #endif

Jsou však případy, kdy možnosti standardního preprocesoru nejsou postačující. Standardní preprocesor neumožňuje např. vytváření cyklů nebo počítání s geometrickými funkcemi. Typickým příkladem začlenění složitěji počítaných dat do programu může být datová struktura, která obsahuje tabulku koeficientů Hammingova okna, které se používá v číslicovém zpracování signálů.

Preprocesor neumožňuje:

  • Cykly

  • Goniometrické funkce

  • Vygenerovat Hammingovo okno

  • ...

1.1 Generování při startu programu

Jedním z řešení je jednorázově vygenerovat takovéto datové struktury na začátku programu. Nevýhoda tohoto řešení spočívá jednak v delší prodlevě při startu systému a také ve větší paměťové náročnosti. Kompilátor by totiž v tomto případě do programu zařadil také matematickou knihovnu, která zabírá v programové paměti nezanedbatelné místo, což by se negativně projevilo zejména v hardwarových systémech s relativně malou pamětí.

  • Nevýhody:

  • Prodleva po spoštění programu

  • Paměťová náročnost: připojení matematické knihovny

1.2 Matlab

Další možností je vygenerování zdrojového kódu datové struktury pomocí Matlabu. Vygenerovaný kód v jazyce C se uloží do samostatného souboru, který je začleněn do výsledného programu při kompilaci a linkování. Generující skript by mohl vypadat např. takto:

% export_hamming.m
N_SEGMENT=512;
ham=hamming(N_SEGMENT);
fp=fopen('hamming.c','w');
fwrite(fp,sprintf('const float hamming_ar[%d]={\n', N_SEGMENT));
for i=1:N_SEGMENT
    fwrite(fp,sprintf('%d,',ham(i)));
    if(((i/8) == floor(i/8))) % if i is divisable by 8
        fwrite(fp,sprintf('\n'));
    end;
end;
fwrite(fp,sprintf('};\n'));
fclose(fp);

Přes všechny známé výhody Matlabu jako výkonného systému pro provádění vědeckých výpočtů jsou vidět některé nevýhody tohoto řešení: generovaný zdrojový kód datové struktury se v kódu skriptu poněkud ztrácí. A každý výstup je potřeba výslovně uložit do cílového souboru.

Ukážeme si ještě jiný způsob generování zdrojových kódů, a to pomocí skriptovacího jazyka PHP.

  • Nevýhody:

  • Generovaný zdrojový kód datové struktury se v kódu skriptu ztrácí.

  • Každý výstup je potřeba výslovně uložit do cílového souboru.

2 Generování zdrojových kódů pomocí PHP

Skriptovací jazyk PHP [1] se používá především pro generování webových stránek a výstupem skriptů PHP nejčastěji bývá prostý text. Na rozdíl např. od JavaScriptu, který pracuje na straně klienta (v prohlížeči), PHP běží na webovém serveru a ve vygenerovaném kódu HTML stránky vůbec nemusí být poznat, že byla vygenerována skriptem PHP. Syntaxe PHP vychází ze syntaxe jazyka C a mnoho se od ní neliší.

Následující příklady předpokládají běh PHP v prostředí operačního systému Windows. V případě použití PHP na jiných operačních systémech jsou rozdíly pouze minimální. V textu bude kód PHP psán tučným neproporcionálním písmem s barevným pozadím. Zdrojové kódy jsou psány s využitím funkcí PHP5.

  • PHP: generování HTML stránek

  • PHP běží na serveru × JavaScript běží v klientu

  • Syntaxe vychází z C

  • Příklady: PHP5 na Windows

  • Označení: tučným neproporcionálním písmem s barevným pozadím

2.1 Instalace PHP

K tomu, abychom mohli PHP používat na lokálním počítači, je potřeba ho nejdříve nainstalovat. Můžeme k tomu použít známý program XAMPP [2], který se postará o instalaci a konfiguraci počítače, aby byl schopen zpracovávat PHP skripty. Součástí instalace XAMPPu je mimo jiné také databáze MySQL, FTP server a další programy. V tomto článku předpokládáme instalaci balíku XAMPP do adresáře C:\Server\xampp.

  • Instalace PHP: XAMPP

  • PHP, MySQL, FTP server, ...

  • Instalace do
    C:\Server\xampp

2.2 Generování a zachycení výstupu

Generovaný kód budeme ukládat do souboru s názvem, který se skládá z výsledného názvu souboru a přípony .php. Např. pro vygenerování souboru hello.c vytvoříme soubor hello.c.php.

Preprocesor PHP vrací vygenerovaný text do standardního výstupu. K tomu, abychom mohli výstup zachytit, je potřeba vložit do kódu dva řádky skriptu PHP – jeden na začátek a druhý na konec. Následující příklad vygeneruje zdrojový kód v závislosti na tom, zda a jak je definována konstanta PLATFORM.

  • Pro vygenerování souboru hello.c vytvoříme soubor hello.c.php

  • Zachycení výstupu: jeden řádek PHP na začátku a jeden na konci kódu

  • Příklad: generování kódu v závislosti na konstantě PLATFORM

<?php ob_start(); ?>
void hello(void){
  printf("Hello, <?php
  if(defined(PLATFORM) && PLATFORM=='C674x'){
    echo 'TMS320C674x';
  }
  else{
    echo 'world';
  }
  ?>
!\n");
}
<?php $code=ob_get_contents();
ob_end_flush();
file_put_contents( './'.basename(__FILE__,'.php'), $code );?>

Funkce ob_start() zapne zachycování do výstupního bufferu. Funkce ob_get_contents() převezme obsah bufferu do proměnné $code. Funkce ob_end_flush() odešle obsah bufferu na výstup. Funkce file_put_contents() uloží vygenerovaný text (kód) do příslušného souboru. Jak je vidět, do výstupu se odesílá vše, tj. prostý text i výstup skriptu.

  • ob_start(): zapnutí zachycování do výstupního bufferu

  • ob_get_contents(): převzetí obsahu bufferu

  • ob_end_flush(): odeslání obsahu bufferu na výstup

  • file_put_contents(): uložení vygenerovaného textu do souboru

Výsledek:

void hello(void){
  printf("Hello, world!\n");
}

Spuštění skriptu

K tomu, abychom mohli PHP skript spustit, potřebujeme napsat dva řádky shell skriptu v syntaxi odpovídající použitému operačnímu systému. V případě, že používáme operační systém Windows, můžeme vytvořit soubor hello.bat s tímto kódem:

  • Dva řádky shell skriptu

  • hello.bat:

SET PHP=C:\Server\xampp\php\php.exe
%PHP% -f hello.c.php

Po spuštění souboru hello.bat se spustí PHP skript s názvem hello.c.php a jeho výstup se uloží do souboru s názvem hello.c. Tento soubor je možné zkompilovat a používat ho pro krokování programu a další vývoj. Veškeré změny však je potřeba provádět ve skriptovém souboru hello.c.php.

  • hello.bat -> hello.c.php -> hello.c

  • Kompilace hello.c

  • Ladění, změny: pouze v hello.c.php!

2.3 Vytváření look-up tabulek

Jedna z metod optimalizace algoritmů číslicového zpracování signálů spočívá ve spočítání mezivýsledků výpočtů předem, a jejich umístění do paměti cílového systému při kompilaci do tzv. look-up tabulek. Ve vlastním algoritmu pak nedochází k opakovaným výpočtům pomocí časově náročných funkcí, ale algoritmus se redukuje na výpočet indexu předem spočítané hodnoty, která je uložena v datové struktuře (tabulce) v paměti.

Pomocí PHP lze generovat look-up tabulky pro některé algoritmy velmi snadno. Výhoda generování datových struktur pomocí PHP spočívá ve snadné překonfigurovatelnosti výstupu. Ukážeme si další příklad, jehož výsledkem je datová struktura obsahující koeficienty Hammingova okna ve formátu plovoucí řádové čárky. Změnou proměnné $N se ovlivňuje počet vygenerovaných koeficientů. Následující kód je uložen v souboru hamming.c.php.

  • Optimalizační metoda: spočítání mezivýsledků výpočtů předem

  • Výpočet -> nalezení indexu - ukazatele do tabulky

  • Koeficienty Hammingova okna - Floating Point:

<?php ob_start();
$PI=3.14159; // defaults
$N=512;
?>

const float hamming_ar[<?php echo $N;?>]={
<?php // generating output
for($n=0; $n<$N; $n++){
  $w=0.54 - 0.46 * cos(2*$PI*$n/$N);
  echo "$w,";
  if(($n % 8) == 7){echo "\n";}
}
?>

};
<?php $code=ob_get_contents(); ob_end_flush();  file_put_contents( './'.basename(__FILE__,'.php'), $code );?>

Výstup tohoto skriptu obsahuje datovou strukturu 512 koeficientů Hammingova okna:

  • Výstup: 512 koeficientů Hammingova okna

const float hamming_ar[512]={
0.08,0.0800346370955,0.0801385431657,0.0803117025629, ...
};

Parametry vygenerovaného kódu (v tomto případě počet koeficientů) je možné měnit buď změnou hodnot konfiguračních konstant v PHP skriptu, nebo předáváním parametrů při volání z příkazového řádku shell skriptu a následným využitím standardních proměnných $argc$argv v PHP skriptu.

Změna parametrů (počet koeficientů):

  • Změna hodnot ve skriptu ($N=512;)

  • Standardní vstupní proměnné: $argc$argv

2.4 Generování zdrojových kódů

Pomocí PHP lze generovat nejen datové struktury, ale lze také pohodlně sestavovat výsledné zdrojové kódy programů z jednotlivých dílčích bloků vybraných např. podle hardwarové platformy cílového systému. Následující příklad vybere zdrojový kód knihovny pro výpočet FFT podle zvolené konfigurace.

  • Sestavování zdrojových kódů z dílčích bloků

  • Výběr např. podle HW platformy

  • Výběr knihovny pro FFT:

<?php
if(defined(PLATFORM) && PLATFORM=='C674x'){
    include './fft/fft-C674x-optimised.c';
}
else{
    include './fft/fft-general.c';
}
?>

Vkládáním kódů z dílčích souborů podle nastavených parametrů představuje alternativu k direktivám standardního preprocesoru. Touto metodou se docílí jednak rychlejší kompilace, ale hlavně přehledného kódu, který nemusí obsahovat nevyužité podmíněné bloky kódu, a je tak lépe čitelný při ladění programu.

  • Rychlejší kompilace

  • Přehlednější kód pro ladění

3 Výsledky

Metodu generování zdrojových kódů pomocí preprocesoru PHP používáme pro provádění experimentů rozpoznávání řeči na systémech s omezenými hardwarovými prostředky, přičemž se zaměřujeme na signálové procesory od firmy Texas Instruments řady TMS320C674x. Aby rozpoznávač řeči mohl fungovat v reálném čase, je potřeba provést mnoho optimalizací. Pro některé optimalizační metody využíváme generování kódu v rámci kompilačního procesu.

Jako příklad výsledku jedné optimalizace uvedeme následující graf.

  • Rozpoznávání řeči na systémech s omezenými HW prostředky

  • Texas Instruments TMS320C674x

  • Generování kódu při kompilaci

Graf 1: Porovnání doby výpočtu standardního a optimalizovaného algoritmu DCT

Součástí parametrizace signálu, kdy jsou ze signálu extrahovány příslušné řečové příznaky, je výpočet diskrétní kosinové transformace (DCT) [3]:

S použitím standardní metody výpočtu DCT jsme na testovacím signálovém procesoru dosáhli doby výpočtu parametrizace přibližně 55 milisekund na segment. Při známém počtu vstupních a výstupních koeficientů DCT, což jsou konstanty známé v době kompilace a během rozpoznávání se nemění, si výsledky konkrétních kosinů spočítáme předem a uložíme do datové struktury. Při běhu algoritmu DCT v reálném čase se pak (paradoxně) už nepočítá s kosinem, ale použije se již předem spočítaná hodnota kosinu podle příslušných argumentů. Tím jsme dosáhli doby výpočtu necelých 6 milisekund, tedy přibližně 9-násobného zrychlení.

Algoritmus Doba výpočtu
Standardní metoda cos(x) 55 ms
Optimalizovaná metoda - Lookup table 6 ms

4 Závěr

V tomto článku jsme si popsali jednoduchý způsob využití preprocesoru PHP pro generování zdrojových kódů v jazyce C bez potřeby dalších složitých nastavení, přestože PHP umožňuje mnoho specifických nastavení a větší integraci s operačním systémem. Výsledky této metody mohou být analogicky aplikovány také na generování zdrojových kódů i v jiných programovacích jazycích.

  • Jednoduchý způsob generování zdrojových kódů v C

  • Funguje i pro jiné programovací jazyky

  • Další možnosti integrace s operačním systémem

  • Propojení s databázemi

  • Využití: kustomizace produktů

Poděkování

Tento výzkum byl podporován z grantu GAČR 102/08/H008 „Analýza a modelování biomedicínských a řečových signálu“, GAČR 102/08/0707 „Rozpoznávání mluvené řeči v reálných podmínkách“.

Literatura

[1] PHP [online]. 2010 [cit. 2010-07-20]. URL: <http://www.php.net/>.

[2] XAMPP [online]. 2010 [cit. 2010-07-20]. URL: <http://www.apachefriends.org/en/xampp.html>.

[3] PSUTKA, Josef, et al. Mluvíme s počítačem česky, pages 162–165. Praha: Academia, 2006. ISBN 80-200-1309-1.

 
{e_like}
 
 
Nahoru