Fabijan Lukin, Fran Pregernik,
Tomislav Sukser Tehnička dokumentacija za obojivo računarstvo |
|
3 Interna realizacija simulatora3.1 Obojivo računaloObojivo računalo je realizirano kao apstraktni razred PaintableComputerBase te ona sadrži sve funkcije koje je potrebno implementirati, kako za sučelje prema simulatoru tako i za API sučelje prema programima. Diagram razreda PaintableComputerBase Razred PaintableComputerBase ima dvije grupe metoda, prva služi za komunikaciju prema simulatoru a druga za komunikaciju prema programima. Slijedi opis svake od njih. 3.1.1 Definicija razreda3.1.1.1 Svojstva razreda PaintableComputerBasepublic uint ComputerId – svojstvo(property) služi simulatoru za identifikaciju kompjutera u listi. Vrijednost ovog svojstva postavlja sam kompjuter i nije garantirano u potpunosti da će biti jedinstveno zbog prirode generiranja slučajnih brojeva. Bez obzira na to može se uzeti da je jedinstveno. public Homepage LocalHomepage – svojstvo koje služi više grafičkim sučeljima nego simulatoru u svrhu traženja pogrešaka programa. Vraća lokalnu podatkovnu stranicu. public List<Homepage> MirroredHomepages – svojstvo koje također služi više grafičkim sučeljima nego simulatoru u svrhu traženja pogrešaka programa. Vraća listu kopija podatkovnih stranica koje trenutno računalo ima u UI prostoru. public NetworkPacket TransmissionAntenna – svojstvo preko kojeg simulator rasprostire pakete bežične veze. Kada simulator postavlja vrijednost ovog svojstva on zapravo stavlja paket „na“ antenu i taj paket se onda postavlja u ulazni red. Kada simulator čita vrijednost ovog svojstva, to zapravo simulira kao da je računalo uspješno poslalo paket iz svog odlaznog spremnika. 3.1.1.2 Metode razreda PaintableComputerBasepublic abstract void Cycle() – metoda koja predstavlja operacijski sustav obojivog računala. Poziva ju simulator. U njoj se izvršavaju onih pet koraka obrade nabrojenih u poglavlju 2.3. Ostale metode spadaju u API funkcije s kojima direktno komuniciraju programi. Slijedi popis istih ali detaljna upotreba API funkcija se nalazi u dokumentaciji za pisanje programa. public abstract int PostEntry(...); – piše proizvoljnu vrijednost u podprostor lokalnog podatkovnog prostora za trenutni program. public abstract bool RemoveEntry(...) – briše određenu vrijednost iz podprostora lokalnog podatkovne stranice za trenutni program. public abstract int RemoveAllEntries(...) – briše sve zapisane vrijednosti iz podprostora lokalnog podatkovne stranice za trenutni program. public abstract int GetPostCount() – vraća broj zauzetih mjesta u podprostoru lokalnog podatkovne stranice za trenutni program. public abstract object GetPost(...) – vraća vrijednost zapisanu u podprostoru lokalnog podatkovne stranice za trenutni program. public abstract int GetIOSpaceCount() – vraća broj kopija podatkovne stranice u UI prostoru. Odgovara broju trenutno vidljivih susjeda. public abstract int GetIOPostCount(...) – vraća broj zauzetih zapisa u jednoj od kopija podatkovne stranice u UI prostoru za određeni program. public abstract object GetIOPost(...) – vraća vrijednost iz podprostora programa u specifičnoj kopiji podatkovne stranice u UI prostoru. public abstract bool QueueTransfer(...) – zapiše zahtjev za prijenos programa na susjedno računalo i stavlja ga u red za obradu. public abstract bool IsQueuedForTransfer(..) – vraća istinu ili laž o tome je li je trenutni program još uvijek u listi za čekanje na prijenos. public abstract bool ClearQueueTransfer(...); - poništava zahtjev za prijenos na određenog susjeda. public abstract bool QueueUninstall() – zapiše zahtjev za deinstalaciju trenutnog programa. public abstract uint GetComputerId() – vraća slučajno generirani identifikacijski broj trenutnog računala koji se ne garantira da je jedinstven. 3.1.2 Podatkovna stranica – razred HomepagePodatkovna stranica je implementirana kao rječnik čiji je ključ jedinstveni broj programa, a vrijednost indeksirana lista objekata – razred HomepagePostCollection. Diagrami razreda Homepage i HomepagePostCollection Ako bi željeli dobiti listu svih vrijednosti koje je jedan program zapisao, napravili bi to na slijedeći način: homepage[programID]. Ako bi željeli pristupiti točno nekoj vrijednosti, onda bi to napravili ovako: homepage[programID][indeksVrijednosti]. 3.1.3 Mrežni podsustavDiagram razreda mrežnog podsustava Mrežni sustav obojivog računala je realiziran, kao što je prije rečeno, kao dva FIFO međuspremnika (reda) – ulazni i izlazni. Svi mrežni paketi su realizirani preko apstraktnog razreda NetworkPacket. Trenutačno postoje samo dvije specijalizacije za mrežne pakete: ProcessFragmentPacket i HomepagePacket koji pored osnovnih podataka o polazištu i odredištu sadržavaju redom, novi program koji će se instalirati na odredištu i kopiju podatkovne stranice. Prilikom primanja paketa računalo ima podatke koji je susjed poslao paket i komu. Bežična veza kao takva pošalje paket svim susjedima te je na njima da obrade paket koji je namijenjen njima. Naravno, moguće je napraviti takvo računalo koje ima promiscuous mrežni podsustav, no svrha takvog računala je upitna. 3.2 Senzori i objekti tokova fizičkih podataka (DataFeeders)Diagram razreda tokova podataka i senzora Prije je napomenuto da svaki senzor radi sa jednim ili više tokova podatak i samo s njima. Prilikom izrade senzora se fiksno postave u kodu tipovi tokova podataka s kojima senzor radi (svojstvo Type[] ISensor.DataFeeders). To daje simulatoru uvid o tome koji će tok podataka zatražiti kako bi tom senzoru vratio neku vrijednost. Simulator prilikom stvaranja računala ili prilikom naknadnog dodavanja novih računala provjerava imaju li ta računala senzore i koje. Te ako ima neki registrirani tok podataka koji odgovara tom senzoru smješta ga u njegovu listu senzora. Ako nema onda se prilikom registracije tokova podataka nanovo rade iste provjere. Prilikom obrade ciklusa senzora, simulator zatraži od toka podataka da svakom senzoru u njegovoj listi izračuna i preda vrijednost. 3.2.1 SenzoriKoncept senzora je implementiran kao sučelje ISensor kojeg razredi, koje nasljeđuju od PaintableComputerBase (može biti bilo koji stupanj nasljeđivanja sve dok je vrh nasljeđivanja PaintableComputerBase), trebaju implementirati. Sučelje ISensor ne daje nikakvu funkcionalnost sa strane računala ali zato simulatoru daje mogućnost da tom računalu daje vrijednosti, koje bi realan senzor pretvarao iz fizičkih vrijednosti u vrijednosti čitljive programima. Rad senzora je jednostavan, nakon što primi neke vrijednosti od toka podataka, on te vrijednosti zapisuje kao virtualni program u podprostor podatkovne stranice sa nekim fiksnim identifikacijskim brojem. Taj identifikacijski broj može poslužiti onda programima da nađu i pročitaju vrijednosti senzora te da promjene svoje ponašanje na temelju toga. 3.2.1.1 Opis sučelja ISensorSučelje ISensor ima samo jedno svojstvo DataFeeders i jednu metodu SetEnvironmentValue! Type[] DataFeeders – svojstvo vraća listu koja treba biti nepromjenjiva i fiksno postavljena u izvorni kôd. U toj listi se nalaze svi tipovi tokova podataka s kojima senzor zna razgovarati. Void SetEnvironmentValue(Type, double) – metoda koja postavlja vrijednosti na senzor. Njeni parametri su tip toka podataka koji daje trenutnu vrijednost i sama vrijednost. 3.2.1.2 Primjer senzora – Temperaturni senzorSlijedi primjer koda senzora koji prati temperaturu okoline. Radi samo sa tokom podataka temperature opisanog kasnije. /// <summary> /// This is a PaintableComputer with a temperature sensor on board /// </summary> [DefaultHomepageColorizer(typeof(TemperatureSensorHomepageColorizer))] public class TemperatureSensorPaintableComputer : GenericPaintableComputer, ISensor { /// <summary> /// This sensor only works with the simpleTemperatureDataFeeder /// </summary> private readonly Type[] usesDataFeeders = new Type[] {typeof(SimpleTemperatureDataFeeder)}; /// <summary> /// Initializes a new instance of the <see cref="T:TemperatureSensorPaintableComputer"/> class. /// </summary> public TemperatureSensorPaintableComputer() : base(DEFAULT_MAXIMUMNEIGHBOURCOUNT) { ... }
/// <summary> /// Initializes a new instance of the <see cref="T:TemperatureSensorPaintableComputer"/> class. /// </summary> /// <param name="maximumNeighbourCount">The maximum neighbour count.</param> public TemperatureSensorPaintableComputer(uint maximumNeighbourCount) : base(maximumNeighbourCount) { ... }
/// <summary> /// Sets the environment value. /// </summary> /// <param name="dataFeederType">Type of the data feeder.</param> /// <param name="sensorValue">The sensor value.</param> public void SetEnvironmentValue(Type dataFeederType, double sensorValue) { ... }
/// <summary> /// Gets the data feeders this sensor works with. /// </summary> /// <value>The data feeders.</value> public Type[] DataFeeders { get { return usesDataFeeders; } }
/// <summary> /// Cycles this instance. /// </summary> public override void Cycle() { ... }
/// <summary> /// Updates the sensor homepage. /// </summary> private void UpdateSensorHomepage() { ... }
} 3.2.1.3 Primjer senzora –Senzor pritiskaSlijedi primjer koda za senzor koji registrira pritisak (npr. hod mrava). Taj senzor radi samo sa tokom podataka hodajućeg mrava opisanog kasnije. /// <summary> /// /// </summary> [DefaultHomepageColorizer(typeof(PressureSensorColorizer))] public class PressureSensorComputer : GenericPaintableComputer, ISensor { public const uint ProcessFragmentId = 0x12121212;
/// <summary> /// This sensor only works with the simpleTemperatureDataFeeder /// </summary> private readonly Type[] usesDataFeeders = new Type[] { typeof(AntWalkerDataFeeder) };
private double pressure;
/// <summary> /// Initializes a new instance of the <see cref="T:PressureSensorComputer"/> class. /// </summary> public PressureSensorComputer() : this(DEFAULT_MAXIMUMNEIGHBOURCOUNT) {}
/// <summary> /// Initializes a new instance of the <see cref="T:PressureSensorComputer"/> class. /// </summary> /// <param name="maximumNeighbourCount">The maximum neighbour count.</param> public PressureSensorComputer(uint maximumNeighbourCount) : base(maximumNeighbourCount) { ... }
/// <summary> /// Sets the environment value. /// </summary> /// <param name="dataFeederType">Type of the data feeder.</param> /// <param name="sensorValue">The sensor value.</param> public void SetEnvironmentValue(Type dataFeederType, double sensorValue) { ... }
/// <summary> /// Gets the data feeders this sensor works with. /// </summary> /// <value>The data feeders.</value> public Type[] DataFeeders { get { return usesDataFeeders; }}
/// <summary> /// Cycles this instance. /// </summary> public override void Cycle() { ... }
/// <summary> /// Updates the sensor homepage. /// </summary> private void UpdateSensorHomepage() { ... }
} 3.2.2 Tokovi podatakaObjekti toka podataka (engl. Datafeeders) su objekti koji nasljeđuju od razreda EnvironmentDataFeeder. Važno je napomenuti da kod stvaranja objekta toka podataka njegov konstruktor zahtjeva parametar veličine zida kako bi se mogla dodatno prilagoditi fizička pojava koju tok podataka modelira. Razred EnvironmentDataFeeder ima samo jednu jedinu metodu koju simulator koristi, a ta je GetValue koja zahtjeva dva parametra, lokaciju senzora i vrijeme simulatora. 3.2.2.1 Opis razreda EnvironmentDataFeederRazred EnvironmentDataFeeder je jako jednostavna, ima samo jednu metodu GetValue koja je zadužena da na temelju lokacije senzora i vremena izračuna vrijednost koju senzor registrira, double GetValue(Point location, uint time) – metoda koja na temelju lokacije i vremena vraća vrijednost koju simulator daje senzoru. 3.2.2.2 Primjer toka podataka – tok podataka o temperaturipublic class SimpleTemperatureDataFeeder : EnvironmentDataFeeder {
private Point heatSource; private double itensity;
/// <summary> /// Initializes a new instance of the <see cref="T:SimpleTemperatureDataFeeder"/> class. /// </summary> /// <param name="wallSize">Size of the wall.</param> public SimpleTemperatureDataFeeder(Size wallSize) : base(wallSize) { ... }
/// <summary> /// Gets the environmental value. /// </summary> /// <param name="location">The location.</param> /// <param name="ticks">The ticks.</param> /// <returns></returns> public override double GetValue(System.Drawing.Point location, uint ticks) { ... } } 3.2.2.3 Primjer toka podataka – „hodajući mrav“/// <summary> /// /// </summary> public class AntWalkerDataFeeder : EnvironmentDataFeeder { private Point centerPoint; private int minimalRadius; public const double MAXIMUMPRESSURE = 100.0;
/// <summary> /// Initializes a new instance of the <see cref="T:AntWalkerDataFeeder"/> class. /// </summary> /// <param name="wallSize">Size of the wall.</param> public AntWalkerDataFeeder(Size wallSize) : base(wallSize) { ... }
/// <summary> /// Gets the environmental value. /// </summary> /// <param name="location">The location.</param> /// <param name="ticks">The ticks.</param> /// <returns></returns> public override double GetValue(System.Drawing.Point location, uint ticks) { ... }
} 3.3 Jezgra simulatoraDiagram jezgre simulatora i dvije izvedbe simulatora Svaki simulator prilikom inicijalizacije traži da mu se postave neke postavke (SimulationSettings) koje kontroliraju njegovo ponašanje. Te postavke su predstavljene razredom EngineSettings. 3.3.1 Postavke simulacijeDiagram razreda postvaka simulatora EngineSettings Razred EngineSettings ima slijedeće postavke: bool LoadEquilization – Postavka koja uključuje mjerenje snage procesora računala na kojem se vrši simulacija u svrhu da se izbjegne početan ubrzan rad simulatora. Naime, ako simulirana računala nemaju u sebi programe onda je simulacija brža. Čim više računala instaliraju programe, simulacija se usporava. Prilikom dodavanja prvog programa u prvo računalo, simulacija je još uvijek podosta brza i grafičko sučelje ne stigne pratiti rad tog programa, nego promjene znaju biti skokovite. Sa LoadEquilization se može simulacija usporiti na početku u svrhu lakšeg praćenja simulacije na početku. ThreadPriority SimulatorThreadPriority – prioritet dretve simulatora. Najveća postavka je ThreadPriority.Normal. Ima utjecaj na praćenje simulacije u smislu da ako je prioritet simulatorske dretve manji od prioriteta grafičkog sučelja (ThreadPriority.Normal), grafičko sučelje stigne sve iscrtati prije nego se nešto znatno promijeni. uint MaximumNeighbourCount – postavka koja ograničava broj susjeda koje računalo „vidi“. Direktno je povezano sa veličinom UI prostora obojivog računala. uint MaximumComputerCount – postavka koja ograniči broj računala na zidu. int SimulatorCycleDeviation – Odstupanje od prosječnog trajanja jednog ciklusa simulatora, isto u taktovima obojivog računala. Razlog uvođenja jest nejednakost brzine takta svih obojivih računala. uint PaintableComputerFailureTime – odgovara srednjem vremenu do greške računala (Mean time before failure – MTBF). Broj koji simulator koristi kako bi povremeno mogao simulirati ispadane obojivog računala. uint RadioLinkDelay – vrijeme koje je potrebno da signal propagira od antene do antene računala. double RadioLinkFailurePercent – postotak gubljenja bežičnog paketa podataka. uint SimulatorCycle – broj simulatorskih ciklusa izvršenih jedan za drugim, prije nego se provjeravaju uvjeti zaustavlajnja. uint SpaceBetweenPaintableComputers – srednja udaljenost od računala do računala. uint WirelessRadius – radijus bežične veze, odgovara jačini odašiljača na računalu. Size WallSizeRatio – odnos širine i visine zida. 3.3.2 Tok simulacijeNakon postavljanja vrijednosti postavki simulatora i odabira vrste računala koje želimo nanijeti na zid, poziva se metoda simulatora InitializeSimulator. Ona stvara računala, raspoređuje ih po zidu i pronalazi susjede svakog računala unutar radijusa bežične veze. Sada kada je simulator inicijaliziran moguće ga je pokrenuti sa Run(), zaustaviti sa Stop() i izvršavati ciklus po ciklu sa Step(). Svaki simulator mora podržavati uklanjanje (isključivanje) računala na zidu. Ta funkcionalnost se implementira u metodi DisableComputers. Ona uklanja računala koja želimo izbrisati te nanovo izvršava pretragu susjeda. Simulacija se obavlja u četiri koraka. Prvi korak je provjera je li prošlo više vremena od vremena navedenog pod PaintableComputerFailureTime te se nasumično ugasi jedno računalo. Drugi korak je dostava svih bežičnih paketa na antene susjeda računala koje je odaslalo pakete. Tu se također uzima u obzir vrijeme propagacije signala i postotak gubljenja paketa. Time je simuliran realni komunikacijski medij. Drugi korak je izvršavanje jedinice rada svakog računala, ako je na njemu red. Točnije svako računalo se zabilježi u nekom trenutku vremena za obradu te ako je taj trenutak došao računalo se pokrene (PaintableComputerBase.Cycle() metoda) 3.3.3 Vizualizacija obojivog računalaGlavni dio grafičkog sučelja je prikaz obojivih računala i promjena koje su se događale na njima. Javila se potreba da se na temelju stanja računala, točnije na temelju sadržaja podatkovne stranice računala, računalima pridruži neka značajka – boja. Za to smo predvidjeli objekte za bojanje, koji pogledaju cijeli sadržaj podatkovne stranice (ili samo njen mali dio) i na temelju zapisanih vrijednosti vrate boju koja će predstavljati računalo na zidu u grafičkom sučelju. Trenutačno samo dvije vrste razreda mogu imati za sebe vezane objekte za bojanje, to su programi i senzori. To je zbog toga jer si želimo predočiti kako program radi i npr. koje vrijednosti senzor registrira od okoline. Također je moguće napraviti i objekt za bojanje koji nije isključivo vezan uz jedan program ili senzor. Objekti za bojanje koji su vezani za programe i senzore se automatski izabiru prilikom učitavanja istih. Oni koji nisu vezani se obično izrađuju kako bi se lakše moglo pratiti neke složene interakcije između raznih programa i senzora. Vezani objekti za bojanje bi trebali služiti kako bi se prikazalo napredovanje programa. Svi oni vide što se događa na podatkovnoj stranici, tako da sintaktički nema razlike među njima. To su samo smjernice kako bi se trebalo programirati. Diagram razreda objekta za bojanje i jedne njegove implementacije Objekti za bojanje su instance razreda koji nasljeđuju od razreda HomepageColorizer. Taj razred zahtjeva da se implementira metoda Colorize kojoj je jedini parametar podatkovna stranica a rezultat boja (struktura System.Drawing.Color) Grafičko sučelje je zaduženo za dohvat liste boja i njezin prikaz na temelju izabranog objekta za bojanje. 3.3.3.1 Primjer objekta za bojanjeObjekti za bojanje se vežu uz programe i senzore pomoću DefaultHomepageColorizerAttribute razreda (pogledati razred Attribute u .NET Frameworku). Slijedi primjer gdje se veže PressureSensorColorizer na PressureSensorComputer: [DefaultHomepageColorizer(typeof(PressureSensorColorizer))] public class PressureSensorComputer : GenericPaintableComputer, ISensor { ... } Sustav za učitavanje dodataka i grafičko sučelje mogu pročitati te atribute pomoću .NET metarazreda (Reflection). Grafička sučelja su napravljena tako da prilikom učitavanja programa se automatski izabrati vezani objekt za bojanje. Pogledajmo primjer jednog objekta za bojanje temperaturnog senzora: /// <summary> /// Colorizes the specified homepage. /// </summary> /// <param name="homepage">The homepage.</param> /// <returns></returns> public override Color Colorize(Homepage homepage) { Color retval = Color.WhiteSmoke;
for (int i = 0; i < homepage.Count; i++) if (homepage.KeyList[i] == TemperatureSensorPaintableComputer.TemperatureSensorProcessFragmentId) { if (homepage.DataList[i].Count == 0) break;
// post at index 0 is the temperature double temperatureValue = (double)homepage.DataList[i][0];
if (maximumTemperature < temperatureValue) maximumTemperature = temperatureValue;
int color = (int)(255 * temperatureValue / maximumTemperature);
retval = Color.FromArgb(color, 0, 0);
// stop processing the rest of the homepage break; }
return retval; } Kao što je vidljivo, on zapravo pretražuje podatkovnu stranicu i kad naiđe na ono što ga zanima on čita vrijednost i na neki način izračunava boju koju će prikazati. Na ovaj način programer programa i senzora, odmah piše i vizualizaciju istih u simulatoru, što se pokazalo vrlo fleksibilnim i daje jako velike mogućnosti za prikaz akcija i interakcija programa i senzora. 3.3.4 Opis razreda GenericSimulatorRad na lokalnom računalu nije ograničen brzinom veze između simulatora i korisničkog sičelja i zahtjeva simulator koji je višenitni (kako bi iskoristio potencijal dvojezgrenih i HT procesora) i ima brzi odziv na naredbe. Za takve potrebe napisan je GenericSimulator. Sastoji se od jednog razreda koji obrađuje naredbe i vraća informacije korisniku, dok je sama simulacija rada obojivih računala, komunikacije među njima i simulacije okoliša odvojena u posebnu nit, kako bi se mogla izvoditi paralelno sa ostalim korisnikovim akcijama te vizualizacijom stanja simulatora. 3.3.5 Opis razreda RemoteSimulatorRemote simulator je simulator optimiran za rad na udaljenost u SmartClient grafičkom sučelju. Pogotovo su optimirane metode dohvata podataka o računalima. Tu se radi o velikom broju računala koja treba prikazivati i pobojat što rezultira velikom količinom podataka koju treba poslati preko mreže. RemoteSimulator to uspješno smanjuje na minimum te omogućava praćenje simulacije bez velikih zaostataka. RemoteSimulator se ne razlikuje od GenericSimulator-a u strukturi već samo u optimiranju količine podataka preko mreže. Nema nikakvih ograničenja na korištenje RemoteSimulatora lokalno, štoviše to radi bez ikakvih dodatnih postavaka. Ono što omogućuje rad na daljinu sa RemoteSimulator-om je .NET Remoting sustav koji nam omogućuje da koristimo objekt na isti način kao i da ne koristimo rad na daljinu. To omogućava da napravimo grafičko sučelje za rad lokalno i uz par dodatnih naredbi omogućimo rad na daljinu. Više o Remoting sustavu treba pogledati .NET dokumentaciju. Dodatna razlika je što RemoteSimulator pokreće pozadinskog radnika prilikom pozivanja Run() koji je jako efikasan način za obavljanje nekog posla, u ovom slučaju simulacije, i kontrolu iste.
|