\chapter{Analýza převodu}
\section{Analýza aplikace Atalanta-M}
Nejprve je potřeba vytvořit analýzu původního rozhraní a funkčnosti aplikace Atalanta-M a následně implementovat úpravy vyplývající z této analýzy.

\section{Stručný popis funkcí}
Aplikace Atalanta-M je ATPG nástroj a simulátor poruch. Dokáže generovat testovací vektory pro všechny s-a poruchy, nebo pro jednotlivě specifikované. Umožňuje třístavovou simulaci. Vstupní formát souboru BENCH.



\section{Objektový model}
Na začátek upřesnění pojmů třída, objekt, objektový model, funkce a metoda. Dle definice jazyka C++, je za třídu považován programový kód, který je definicí objektu, tj. jaké bude mít objekt proměnné, jaké funkce bude mít a co budou dělat. Za objekt je považována až instance třídy, tj. kdy dle definice je vytvořen daný objekt v paměti, který již obsahuje reálná data. Objektový model se zachoval z minulosti, kdy předchozí programovací jazyky mluvily o objektu, ať už se jednalo o definici objektu (dnes třída) nebo instaci objektu (dnes objekt). Funkce je samostatný programový kód, který  zpracovává vstupní data. Pokud funkci definujeme uvnitř třídy tak se této funkci říká metoda.

Objektový model byl již vytvořen studentem Zlatuškou. Tento objektový model jsem převzal a začal jej zkoumat. Pro lepší orientaci jsem si vytvořil UML diagram, který jsem následně aktualizoval dle mých úprav programového kódu. Výsledný UML diagram je na obrázku \ref{fig:UMLDiagram}. Hlavním vodítkem pro stanovení jmen tříd bylo rozdělení funkcí do souborů. Funkce jsou rozděleny do souborů podle toho jak k sobě logicky patří, tj. v souboru jsou obsaženy funkce, které řeší jeden specifický algoritmus. Příkladem je soubor fan.c, který obsahuje všechny funkce potřebné pro provádění algoritmu FAN, nebo soubor ppsfp.c, který obsahuje všechny funkce potřebné pro paralelní simulaci poruchových vektorů.

Existují funkce, které jsou definovány v jednom souboru, ale používané jsou i v jiném(-ých) souboru(-ech). Tyto společné funkce nám stanovily dědičnost mezi třídami. Funkce byly definovány s přístupem protected, což zaručuje, že třídy, které od této třídy dědí, mohou tuto funkci bez problémů používat.

Stejně tak jako jsou funkce definovány v jednotlivých třídách, tak je nutné definovat i datové proměnné, se kterými funkce pracují. Při definici proměnné, je třeba uvést její přístupnost, tj. oblast, kde je proměnná platná. Přístupové módy jsou public - třída/metoda je veřejně dostupná, protected - třída/metoda je dostupná v základní třídě a třídách, které dědí z této třídy a private - třída/metoda je dostupná pouze v třídě, ve které je definována.

Všechny třídy jsou umístěny do jmenného prostoru atalantadll.


\section{Rozšíření pro rozsáhlejší obvody}
Původní program Atalanta-M má některá omezení, která jej nedovolují  použít na větší obvody. Tento stav je způsoben hlavně datovými strukturami. V programu jsou definovány preprocesorové konstanty, které nastavují limity datových struktur. Po změně těchto konstant  je nutné program překompilovat. Navíc některé datové struktury užívají datové typy, které nemohou pojmout celý rozsah, pokud je nastaven příliš velký, tzn. naráží zde na omezení datových typů. Pro odstranění těchto limitujích faktorů, jsou použity dynamické datové struktury z knihovny STL (\cite{STLReference}), kde jsou již implementovány základní a nejpoužívanější dynamické datové struktury jako dynamické pole, dynamický seznam atd. Pro eliminaci tohoto problému jsou s výhodou použity tyto datové struktury, které umožňují dynamicky se měnící velikost, tj. velikost která se mění za běhu programu. Protože se velikost mění dynamicky, nejsou zde limity, které by omezovaly velikost tohoto pole kromě dostupné operační paměti a následně pak možná velikost adresace. Vzhledem k tomu, že je možné adresovat až 2GB na 32-bitových OS tak se domnívám, že bych se dostal do potíží s adresací. Tato adresace se pomocí jistého nastavení kompilátoru dá ještě zvýšit, ale předpokládám, že to nebude třeba.

Tato úzká místa již byla identifikována a nahrazena zmíněnými dynamickými datovými strukturami studentem Zlatuškou. Vzhledem k náhradě těchto datových struktur, došlo i ke změně kódu, který však není všude správně implementován, a proto je nutno jej opravit. Tím je míněno, že změněný kód má na některých místech jinou funkci než původní program a to vede k pádům aplikace. Tento programový kód je nutno opravit.

\section{Vytvoření rozhraní dynamické knihovny}
Vzhledem k tomu, že program bude převeden do dynamické knihovny je potřeba vytvořit rozhraní pro volání jednotlivých funkcí. Protože pracujeme s objekty, tak je nutné definovat pouze dostupnost funkcí vně jmenného prostoru tj. správné nastavení vlastností public, metod jednotlivých tříd. 

Rozhraní musí umožňovat nastavení stejné funkčnosti jako předchozí aplikace, tj. nastavení příslušných parametrů algoritmů a zároveň předání vstupních a výstupních dat aplikaci, která knihnovnu bude využívat.\\

Prvním rozdílem rozhraní je předávání vstupních parametrů. Vstupní parametry programu Atalanta-M jsou předávány pomocí příkazové řádky. Příkazová řádka se rozloží na jednotlivé ``přepínače'' a jejich případné parametry. Popis jednotlivých přepínačů je v \cite{Atalanta-MMan}. Příkazová řádka slouží pouze k nastavení parametrů užitých algoritmů, ale vlastní zpracovávaná data jsou předávána pomocí souborů. Odkazy na soubory, ve kterých jsou data uložena, jsou ve formě jména souboru včetně jeho plné nebo relativní cesty. 

Z výše uvedeného vyplývá, že pro vygenerování testovacích vzorků  bylo nutné všechna potřebná data uložit na disk do souboru(-ů)
a tyto soubory pak zpětně načítat pomocí programu Atalanta-M. Diskové operace jsou nejpomaleší operace v počítači. Tyto operace lze eliminovat a to tak, že potřebná data předáme pouze v operační paměti bez zápisu na disk, respektive si je můžeme uložit i na disk jako případnou zálohu nebo uložení výsledku operací, ale dynamické knihovně je předáme pouze v operační paměti. Abych toho docílil, bylo nutné upravit stávavající rozhraní programu. Možné způsoby předání jsou:\\

\begin{enumerate}
\item Předání pomocí řetězce, který bude mít stejný formát jako na příkazové řádce. Řetězec se rozloží na jednotlivé přepínače a jejich parametry. Takto připravený řetězec pak postupně nastaví parametry v pořadí v jakém byly zadány v řetězci.
\item Pro jednotlivé parametry algoritmů budou vytvořeny nové metody, které budou dané parametry nastavovat a číst. Pro každý parametr bude dodána jedna metoda, která daný parametr nastaví. Metody budou dodány do tříd, kde je možné nastavit příslušnou proměnnou programu. Každá metoda bude mít vlastní ověření platnosti zadané hodnoty, aby bylo možné nastavit pouze validní hodnotu.  
\item Pro jednodušší práci s parametry, zavést novou třídu Params, která bude sloužit pro hromadné nastavení parametrů pomocí jedné metody. Třída bude implementovat operátor přiřazení, který bude využit při testování správnosti metod nastavujících parametry. Výhoda třídy spočívá v tom, že je možné implementovat serializaci této třídy, která nám umožní uložení a zpětné načtení konfigurace ze souboru nebo jiného proudu a tímto způsobem je možné uchovat několik nastavení - konfigurací.
\item Použití nějaké statické třídy, která bude obsahovat statické proměnné, které se nastaví dle vstupních parametrů.  
\end{enumerate}

První způsob bych zde zachoval z důvodu zpětné kompatibility. Není potřeba měnit žádný kód, protože aplikaci, která bude užívat tento způsob, stačí pouze vytvořit pole typu char*, kam uloží jednotlivé přepínače a jejich hodnoty v pořadí, jako na příkazové řádce a toto pole, spolu s počtem prvků v tomto poli, předat  metodě pro spustění programu. Druhý možný způsob je nechat předat pole přímo z příkazové řádky, tj. aplikace, která využívá tuto knihovnu, vezme pole, které jí bylo předáno při spuštění a to pouze předá metodě pro spuštění programu. Zde však nastává riziko, že spolu s těmito parametry budou předány i jiné parametry, které nejsou určeny pro program Atalanta. Pokud k tomu dojde, tak Atalanta vypíše nápovědu k jednotlivým parametrům a skončí. Existuje možnost toto chování změnit a prostě neplatný přepínač ignorovat, ale zde hrozí riziko, že by mohlo dojít k chybné interpretaci následujících parametrů a to by bylo nežádoucí. Nehledě na to, že aplikace, která by užívala knihovnu, by nemohla používat přepínače definované v Atalantě.

Druhý způsob bych implementoval. Důvodem pro implementaci je, že jednotlivé metody jsou umístěny v třídách podle toho kde je proměnná deklarována. V těchto metodách se udělají základní validace nastavovaných proměnných, aby byly zajištěny korektní hodnoty v programových proměnných.
 
Třetí způsob bych implementoval. Důvodem pro implementaci je možnost nastavení všech parametrů najednou. V metodě, která bude nastavovat parametry lze následně provést validaci parametrů. Validace je možná i vlastním porovnáním parametrů, které by se mohli ovlivňovat. Jednou z dalších výhod definice této třídy je možnost vytvoření několika instancí této třídy, které si samostaně nastavíme a tyto instance budeme používat podle potřeby. Nejlépe to vysvětlím na příkladě.

\label{StreamPriklad}Uvažujme příklad, kdy budeme chtít pro každý obvod provést vygenerování testovacích vektorů a jejich následné odsimulování. V této situaci si vytvoříme dvě instance třídy Params, kde v první instanci této třídy si nastavíme parametry Atalanty tak, jak požadujeme vygenerovat testovací vektory a v druhé instanci si nastavíme parametry Atalanty tak, abychom tyto vektory odsimulovaly. Zavoláme metodu setParams, kde parametr bude první instance třídy Params, která obsahuje nastavení Atalanty na generování testovacích vektorů. Spustíme Atalantu. Po doběhnutí zavoláme znovu metodu SetParams, ale tentokrát bude parametrem druhá instance třídy Params, která obsahuje nastavení parametrů na simulaci testovacích vektorů. Znovu spustíme Atalantu. Po doběhnutí si můžeme prohlédnout výsledky našich testů.

Čtvrtý způsob bych neimplementoval. Důvodem je to, že v jeden okamžik může být aktivní pouze jedna konfigurace. Je to dáno tím, že změnou statického parametru se tento parametr nezmění pouze pro jednu danou instanci Atalanty, ale pro všechny instance, i ty, co již běží. Toto chování programu je nežádoucí.

Po analýze vstupních parametrů z manuálu \cite{Atalanta-MMan} byly stanoveny metody, které jsou vypsány v tabulce \ref{tab:NoveMetody}.

Vstupní a výstupní soubory jsou nahrazeny proudy (streams). Třídy, kam bude definována příslušnost těchto proudů, budou deklarovat typy proudů, které budou odpovídat typu souboru jako u aplikace Atalanta. Je tím míněno, že pokud je soubor Bench vstupní, tak jím i nadále zůstane. To bude zajištěno tak, že v dané třídě bude deklarován proud jako vstupní (istream) a pro  výstupní soubor bude deklarován proud výstupní (ostream). Jednotlivé proudy mají za úkol předávání dat mezi knihovnou a aplikací, která knihovnu využívá. Daty jsou v tomto případě myšleny informace, které knihovna čte či generuje. Výstupní data,  například testovací vektory, mohou být dále využity pouhým přečtením proudu. Aby bylo možné tento proud zpětně přečíst, je nutné soubor v aplikaci, využívající tuto knihovnu, definovat jako proud vstupně/výstupní (iostream). Tento proud se předá knihovně jako výstupní proud, například proud pro uložení testovacíh vektorů. Proudy mají ještě navíc i tu výhodu, že je možné předat jako vstupní nebo výstupní soubor i fstream. Fstream je proud, který umožňuje uložení či načtení dat ze souboru. Výhoda spočívá v tom, že zůstává možnost realizovat načítání a ukládání do souborů tak, jak tomu bylo v původní aplikaci Atalanta. Jednotlivé způsoby se dají i kombinovat.

Příklad kombinace iostream a fstream. Aplikace, která generuje bench soubor se upraví tak, že bude používat tuto knihovnu. Textovou informaci, kterou by ukládala do souboru, uloží do vstupně/výstupního proudu (iostream) a tento stream se následně předá knihovně jako vstupní stream. Jako výstupní stream se nastaví soubor na disku (fstream). Poté se nastaví parametry jednotlivých algoritmů pro generování správných testovacích vektorů a spustí se generování. Výsledkem tohoto příkladu bude vygenerování testovacích vektorů, které budou uloženy na disku v souboru, který byl definován, ale data původně ukládaná do bench souboru se do tohoto souboru vůbec neuloží, ty pouze ``projdou'' pamětí počítače, ale na disku se vůbec neuloží. To by mělo mít za následek zrychlení zpracování vstupních dat, protože diskové operace spojené s načítáním souboru budou vyměněny za operace s pamětí, které jsou o mnoho rychlejší.

Implementace příkladu (uvedeného zde \ref{StreamPriklad}) může být provedena právě pouze v paměti číslicového počítače a to tak, že si nadefinuji vstupně/výstupní proud (iostream), který předám jako výstupní proud pro generování testovacích vektorů a po vygenerování těchto vektorů, spustím atalantu znovu s nastavením parametrů pro simulaci a nadefinovaný vstupně/výstupní proud, který byl naplněn v předchozím kroku, předám jako vstupní parametr pro simulaci. Výsledek tohoto běhu si uložím na disk. Zde je vidět, že mezivýsledky v podobě testovacích vektorů a seznamu poruch není třeba ukládat na disk, ale pouze předat.

Program používá dva vstupní soubory a pět výstupních. Soubory pro program Atalanta jsou na \ref{fig:SchemaIO}, kde jsou označeny žlutou barvou. Jednotlivé formáty jsou popsány na \cite{Atalanta-MMan}:
\begin{itemize}
  \item Vstupní sobory
  \begin{itemize}
    \item Circuit description - soubor, který obsahuje definici a strukturu testovaneho obvodu
    \item Fault list - soubor, který obsahuje seznam poruch k otestování
  \end{itemize} 
  \item Výstupní soubory
  \begin{itemize}
    \item Test patterns - soubor, kam se ukládájí výsledné testovací vektory
    \item Processed faults - soubor, kam se ukládají zpracované poruchy
    \item AbortedFaults - soubor, kam se ukládají přerušené nebo nedetekované poruchy
    \item FaultMask - soubor, kam se ukládají masky poruch
    \item Report - soubor, kam se ukládá výsledná zpráva programu
  \end{itemize}
  
\end{itemize}

\begin{figure}[h]
\begin{center}
\includegraphics[width=100mm]{SchemaIO}
\caption{Schéma vstupů a výstupů programu Atalanta-M}
\label{fig:SchemaIO}
\end{center}
\end{figure}

Druhým zásadním rozdílem je změna z aplikace na knihovnu. Aplikace je samostatně spustitelný kód, zatímco knihovna je samostatně existující kód, který není přímo spustitelný, ale umožnujě tento kód znovu použít v jiných programech, které využívají funkčnosti této knihovny a komunikují s ní pomocí předem stanoveného rozhraní, které je v knihovně implementováno. Toto rozhraní by mělo poskytovat možnost plně nastavit všechny potřebné parametry nutné pro správnou funkčnost knihovních funkcí a k co největšímu uspokojení požadavků třetích stran, které budou tuto knihovnu používat. Programový kód knihovny není dostupný. Dostupný je pouze seznam funkcí/metod rozhraní této knihovny a jejich popis.

Třetím zásadním rozdílem bude i chybový systém. Chybový systém je v tomto případě myšleno zpětné hlášení chyb aplikaci, která využívá knihovnu. V původním programu byl tento systém zajištěn pomocí funkce error, která prováděla vypsání poruchové hlášky na standardní výstup a následně ukončila program. Tento způsob není možné použít u knihovny, protože zde standardní výstup nemusí vůbec být používán a ukončení celého programu je nežádoucí. V tomto případě využijeme rozšíření jazyka C++ a sice vyjímky (exceptions). Veškerá chybová hlášení musí být převedena na vyjímky. Text pro chybové hlášení bude uložen do stringu, který bude obsahovat popis chyby. Volání programového kódu atalanty by pak mělo být uzavřeno v sekci try a catch, aby bylo možné vyjímku zpracovat. 

\clearpage
Vytvoření konzolové aplikace stejně jako je předchozí Atalanta-M je vytvoření a spustění tohoto programového kódu:
\begin{verbatim}
int main(int argc,char** argv)
{
  Atalanta *simulation = NULL;
  int res = 0;
  try {
    simulation=new atalantadll::Atalanta();
    res=simulation->run(argc, argv);
    delete simulation;
  }
  catch(string s) {
    cerr << s;
  }
	return res;
};
\end{verbatim}
Tento programový kód je vytvořen i na dodaném CD k této bakalářské práce, protože byl použit pro testování funkčnosti programového kódu.



\section{Dynamická knihovna} \label{sec:DynamickaKnihovna}
Pro dynamickou knihovnu je ještě nutné dodělat jisté úpravy pro operační systém windows, který umožňuje definovat, které třídy a metody budou dostupné z dynamicky linkované knihovny a které ne. Pro operační systém Linux se nic takového nedefinuje, proto je zde nutné zavést preprocesorové makro. Toto makro má tvar: 
\begin{verbatim}
#ifdef _WIN32
  // Export symbols to .dll while using MS C++ compiler
  # define SHARE_EXPORT __declspec(dllexport)
#else
  // There is no need to declare export on Linux
  # define SHARE_EXPORT
#endif
\end{verbatim}
Makro se umisťuje před třídy, které chceme vyexportovat z knihovny. Jednotlivé metody vyexportované třídy si stále zachovávají svoji přístupnost, která je definována pomocí klíčových slov public, protected nebo private.

\section{Kompilovatelnost na více OS} 
Z názvu již vyplývá, že pro každý operační systém je nutno knihovnu zkompilovat, protože programový kód je překládán do nativního kódu procesoru dle daného OS a neběží v žádném frameworku, který by tento kód interpretoval. Programový kód musí být uzpůsoben tomu, aby ho bylo možné kompilovat na jednotlivých operačních systémech beze změny, proto jsou zaváděna preprocesorová makra, pomocí kterých se řeší tyto rozdíly. Jeden rozdíl je popsán v kapitole \ref{sec:DynamickaKnihovna}. K tomu, aby tyto preprocesorová makra fungovala správně, je nutné zkontrolovat, zda při kompilaci na jednotlivých OS jsou během kompilace definovány určité preprocesorové konstanty, které určují, jaká část kódu se zkompiluje. Pro operační systém Windows je třeba definovat konstantu \_WIN32 a pro operační systém Linux je to \_LINUX. Tyto preprocesorové konstanty bývají běžně definovány pokud kompilujeme programový kód z nějakého vývojového prostředí. Pokud je programový kód kompilovaný pouze pomocí programu make, potom je třeba tuto konstantu nadefinovat. Příkladem souboru, který make používá, je na přiloženém CD v adresáři linux a jménem "`makefile"'.

\section{Ověření funkčnosti}
Aby bylo možné konstatovat, že je program funkční, tak je třeba ověřit jeho funkčnost. V mé situaci mám tu výhodu, že mám již existující funkční a odladěný program, který mi poskytne výsledky pro porovnání. Ověření proto bude nejlepší jako porovnání výsledků jednoho a druhého programu. Výsledky se v tomto případě myslí výstupní soubory z obou programů. U každého testu jsou vypsány výstupní soubory, které se budou porovnávat a výsledek porovnání. Pro tento účel by bylo vhodné vypracovat nějaký testovací skript, který otestuje funkce programu na různých testovacích vzorcích. Testované vzorky budou reálné obvody, které mají uloženou strukturu v bench souborech. Výsledky obou programů se pak následně porovnají. Pokud budou výsledky stejné, pak můžeme s určitostí říci, že je nově naprogramovaný program funkční.

\section{Srovnání rychlosti}
Nakonec je ještě potřeba provést srovnání rychlosti, které nám ukáže, jak se zlepšila nebo zhoršila výkonnost programu při převodu do C++. K porovnání využijeme měření procesorového času v jednotlivých programech. V původním programu je měření procesorového času již implementováno. Toto měření je třeba implementovat také v nově vytvořeném programu. Výsledky měření se zaznamenají do grafu, kde budou všechny křivky vedle sebe a snáze tak vyhodnotíme, zda došlo ke zrychlení nebo zpomalení. Jako zajímavost zde uvádím i výsledky programů, které jsou zkompilovány bez optimalizace.