Study about Models of Computatoin for describing Digital Systems

170 visualizações

Publicada em

Master dissertation on different semantics that describe concurrent component-based architectures for embedded systems.

Publicada em: Engenharia
0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
170
No SlideShare
0
A partir de incorporações
0
Número de incorporações
3
Ações
Compartilhamentos
0
Downloads
0
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Study about Models of Computatoin for describing Digital Systems

  1. 1. Ivan Jeukens Um Estudo sobre a Utilização de Modelos Computacionais para a Representação de Sistemas Digitais Dissertação apresentada à Escola Politécnica da Universidade de São Paulo para obtenção do título de Mestre em Engenharia Elétrica. São Paulo 2000
  2. 2. Ivan Jeukens Um Estudo sobre a Utilização de Modelos Computacionais para a Representação de Sistemas Digitais Dissertação apresentada à Escola Politécnica da Universidade de São Paulo para obtenção do título de Mestre em Engenharia Elétrica. Área de Concentração: Microeletrônica Orientador: Prof. Dr. Marius Strum São Paulo 2000
  3. 3. Jeukens, Ivan Um Estudo sobre a Utilização de Modelos Computacionais para a representação de Sistemas Digitais São Paulo, S. P., Brasil, 2000. p. 108 Dissertação de Mestrado. Escola Politécnica da Universidade de São Paulo. Departamento de Engenharia Elétrica. 1. Sistemas Digitais 2. Modelos computacionais 3. Especificações Executáveis 4. Metodologias. I. Universidade de São Paulo. Escola Politécnica. Departamento de Engenharia Elétrica II. t.
  4. 4. Aos meus pais.
  5. 5. Agradecimentos Ao meu orientador Prof. Marius Strum pelas inúmeras discussões que acabaram por moldar e assegurar a qualidade desse trabalho. Aos membros da banca de defesa pela paciência de ler esse texto. Aos colegas da sala C2−53 Alexandre Giulietti, Oscar Guilarte, Alfredo Coelho e João Paulo. Ao grupo de desenvolvimento do ambiente Ptolemy por disponibilisar um software de alta qualidade. A CAPES pelo financiamento desse trabalho através de uma bolsa de mestrado.
  6. 6. SUMÁRIO Lista de tabelas Lista de figuras Resumo ¨Abstract¨ 1 Introdução ............................................................................................................1 1.1 Considerações Iniciais ..............................................................................1 1.2 Trabalhos Relacionados ...........................................................................2 1.3 Estrutura do Texto ...................................................................................3 2 Fundamentos ........................................................................................................4 2.1 Introdução ................................................................................................4 2.2 O Ambiente Ptolemy ................................................................................4 2.2.1 A implementação do Ambiente Ptolemy .............................................4 2.2.1.1 O Pacote Kernel: Sintaxe da Especificação ...................................5 2.2.1.2 O Pacote Actor: Suporte à Semântica ............................................6 2.2.1.3 Outras Classes Importantes ...........................................................8 2.2.2 Utilizando o Ambiente Ptolemy ..........................................................9 2.3 Os Modelos Computacionais ..................................................................11 2.3.1 Discrete Event ...................................................................................11 2.3.2 Synchronous Reactive .......................................................................13 2.3.3 Communicating Sequential Processes ...............................................17 2.3.4 Synchronous Data Flow ....................................................................19 2.3.5 Dynamic Data Flow ..........................................................................21 2.3.6 Kahn Process Networks ....................................................................24 2.4 Outros Modelos Computacionais ............................................................24 2.5 A Ferramenta de Depuração/Profile .......................................................26 2.5.1 Dados Coletados ...............................................................................26 2.5.2 A Interface Gráfica ............................................................................27 3 Primitivas Comportamentais .............................................................................32 3.1 Introdução ..............................................................................................32 3.2 Seqüência de Expressões ........................................................................32
  7. 7. 3.2.1 Exemplo de Sistema ..........................................................................32 3.2.2 Especificação Executável ..................................................................33 3.2.3 Análise da Execução .........................................................................34 3.2.3.1 SDF .............................................................................................34 3.2.3.2 DDF ............................................................................................34 3.2.3.3 PN ...............................................................................................34 3.2.3.4 DE ..............................................................................................35 3.2.3.5 CSP .............................................................................................35 3.2.3.6 SR ...............................................................................................35 3.3 Desvio Condicional ..........................................................................................35 3.3.1 Exemplo de Sistema ..........................................................................35 3.3.2 Especificação Executável ..................................................................36 3.3.2.1 SDF .............................................................................................36 3.3.2.2 DDF ............................................................................................38 3.3.2.3 PN ...............................................................................................39 3.3.2.4 CSP .............................................................................................39 3.3.2.5 DE ..............................................................................................40 3.3.2.6 SR ...............................................................................................41 3.3.3 Análise da Execução .........................................................................42 3.3.3.1 SDF .............................................................................................42 3.3.3.2 DDF ............................................................................................42 3.3.3.3 PN ...............................................................................................43 3.3.3.4 CSP .............................................................................................43 3.3.3.5 DE ..............................................................................................43 3.3.3.6 SR ...............................................................................................43 3.4 Iteração com Duração Fixa .....................................................................44 3.4.1 Exemplo de Sistema ..........................................................................44 3.4.2 Especificação Executável ..................................................................44 3.4.2.1 SDF .............................................................................................45 3.4.2.2 DDF ............................................................................................46 3.4.2.3 PN ...............................................................................................46 3.4.2.5 CSP .............................................................................................47 3.4.2.4 DE ..............................................................................................47 3.4.2.6 SR ...............................................................................................48 3.4.3 Análise da Execução .........................................................................48 3.4.3.1 SDF .............................................................................................48 3.4.3.2 DDF ............................................................................................48 3.4.3.3 PN ...............................................................................................49 3.4.3.4 CSP .............................................................................................50 3.4.3.5 DE ..............................................................................................50
  8. 8. 3.4.3.6 SR ...............................................................................................50 3.5 Outras Primitivas Comportamentais .......................................................51 3.5.1 Sincronismo ......................................................................................51 3.5.2 Compartilhamento de Recursos .........................................................51 3.5.3 Concorrência .....................................................................................52 3.5.4 Preempção ........................................................................................52 3.5.5 Recursão ...........................................................................................53 3.6 Discussão ...............................................................................................53 4 Estudo de Caso ...................................................................................................56 4.1 Introdução ..............................................................................................56 4.2 O Modem ADSL ....................................................................................56 4.2.1 Introdução .........................................................................................56 4.2.2 Framming .........................................................................................57 4.2.3 Código de Redundância Cíclica .........................................................59 4.2.4 Embaralhamento ...............................................................................60 4.2.5 Correção de Erros .............................................................................60 4.2.6 Interleaver ........................................................................................60 4.2.7 Ordenamento de Tons .......................................................................60 4.2.8 Codificação de Constelações .............................................................61 4.2.9 Modulação ........................................................................................61 4.2.10 A inicialização ................................................................................61 4.3 As Especificações Executáveis ...............................................................63 4.3.1 O sistema ..........................................................................................63 4.3.2 Framming .........................................................................................65 4.3.3 A especificação dos modems ATU−C e ATU−R ...............................66 4.3.3.1 MuxSyncTx ..................................................................................67 4.3.3.2 MuxSyncRx .................................................................................69 4.3.3.3 CRCTx ........................................................................................69 4.3.3.4 CRCRx ........................................................................................70 4.3.3.5 ScramblerTx ................................................................................71 4.3.3.6 ScramblerRx ...............................................................................72 4.3.3.7 FECTx ........................................................................................72 4.3.3.8 FECRx ........................................................................................73 4.3.3.9 InterleaverTx ...............................................................................75 4.3.3.10 InterleaverRx ............................................................................75 4.3.3.11 Map ...........................................................................................76 4.3.3.12 Demap .......................................................................................79
  9. 9. 4.3.3.13 IDFT .........................................................................................80 4.3.3.14 DFT ..........................................................................................81 4.3.3.15 Initializer ..................................................................................82 4.4 Discussão ...............................................................................................87 5 Conclusões e Trabalhos Futuros ........................................................................89 5.1 Considerações Finais ..............................................................................89 5.2 Trabalhos Futuros ..................................................................................89 Referências Bibliográficas .....................................................................................91
  10. 10. LISTA DE TABELAS Tabela 3.1 Comparação dos escalonadores do MoC DE ..........................................50
  11. 11. LISTA DE FIGURAS Figura 2.1 Diagrama estático de classes simplificado dos pacotes Actor e Kernel.......5 Figura 2.2 Uma topologia não hierárquica .................................................................5 Figura 2.3 Exemplo de topologia hierárquica ............................................................6 Figura 2.4 Exemplo de troca de dados .......................................................................6 Figura 2.5 Exemplo de topologia para ilustrar o uso da classe Director .....................7 Figura 2.6 Type lattice do ambiente Ptolemy .............................................................8 Figura 2.7 Um exemplo genérico de ator atômico ......................................................9 Figura 2.8 Exemplo de arquivo principal de uma especificação executável ..............10 Figura 2.9 Situação de eventos simultâneos no MoC DE .........................................11 Figura 2.10 O ator Delay no MoC DE ....................................................................12 Figura 2.11 Ilustrações das definições do MoC SR ..................................................16 Figura 2.12 Ator de atraso no MoC SR ....................................................................17 Figura 2.13 O comando CDO no ambiente Ptolemy ................................................18 Figura 2.14 Dois grafos SDF ...................................................................................19 Figura 2.15 Dois grafos SDF inválidos mas com matrizes consistentes ....................20 Figura 2.16 O ator Delay no MoC SDF ...................................................................21 Figura 2.17 Os atores Switch e Select no modelo DDF ............................................22 Figura 2.18 Código do ator Select no MoC DDF .....................................................23 Figura 2.19 A janela inicial da ferramenta PTII Analyzer ........................................27 Figura 2.20 A janela da topologia ............................................................................28 Figura 2.21 Janela inicial para o profiling ................................................................29 Figura 2.22 Tabela de dados estatísticos de atores ...................................................29 Figura 2.23 A tabela de dados dos portos .................................................................30 Figura 2.24 Gráfico da evolução do estado de um ator .............................................31 Figura 2.25 Gráfico alternativo da evolução dos estados de um ator ........................31 Figura 2.26 Exemplo de gráfico da evolução da quantidade de tokens em uma conexão .......................................................................................................31 Figura 3.1 Descrição em linguagem C do cálculo dos pontos da curva borboleta .....33 Figura 3.2 A topologia da especificação executável para o exemplo curva borboleta.............................................................................................33 Figura 3.3 Situação da execução em um momento inicial utilizando o escalonador com classificação de ator deferrable .............................................................34 Figura 3.4 Situação da execução em um momento inicial utilizando o escalonador
  12. 12. sem classificação de ator deferrable .............................................................34 Figura 3.5 Descrição em linguagem C do cálculo do coeficiente angular em uma reta .................................................................................................36 Figura 3.6 Topologia da primeira especificação em SDF .........................................36 Figura 3.7 Trecho do código do ator Mux ................................................................37 Figura 3.8 Topologia da segunda especificação utilizando o MoC SDF ...................37 Figura 3.9 Interface para uma função do exemplo do coeficiente angular ................37 Figura 3.10 Topologia da primeira especificação utilizando o modelo DDF ............38 Figura 3.11 Topologia da segunda especificação utilizando o MoC DDF ................39 Figura 3.12 Trecho de código do ator MuxND no MoC CSP ...................................40 Figura 3.13 Topologia da especificação no MoC DE ...............................................40 Figura 3.14 Trecho de código do ator Coef no MoC DE ..........................................41 Figura 3.15 Método fire() do ator MuxND no MoC SR ............................................41 Figura 3.16 Exemplo da evolução do estado do ator Comp2 para a especificação da figura 3.10 no MoC DDF .............................................................................42 Figura 3.17 Exemplo da evolução do estado do ator Comp2 para a especificação da figura 3.11 no MoC DDF .............................................................................42 Figura 3.18 Exemplo da evolução do estado do ator Comp2 para a especificação da figura 3.11 no MoC PN ................................................................................43 Figura 3.19 Multiplicação de duas matrizes de ordem N ..........................................44 Figura 3.20 A primeira especificação para a primitiva de iteração fixa ....................44 Figura 3.21 Implementação alternativa para a geração dos índices da iteração .........45 Figura 3.22 A iteração com duração fixa no MoC SDF ...........................................45 Figura 3.23 Trecho de código dos atores CT e Data ................................................46 Figura 3.24 Código dos atores Data e CT no MoC PN ............................................47 Figura 3.25 Trecho do ator Sequencer no MoC PN ..................................................47 Figura 3.26 Trecho do ator Sequencer no MoC DE .................................................47 Figura 3.27 Evolução do estado dos atores Data (em azul) e Accum (em verde) ......48 Figura 3.28 Evolução do estado dos atores Data e Accum com a alteração do parâmetro do método waitFor() ...................................................................49 Figura 3.29 Evolução do estado do ator Data quando o tamanho inicial das filas é 1 ..................................................................................................49 Figura 3.30 Evolução do estado do ator Data quando o tamanho inicial das filas é 8 ..................................................................................................49 Figura 3.31 Discrete Cosine Transform : exemplo para a primitiva de sincronismo .51
  13. 13. Figura 3.32 Um exemplo para a primitiva de preempção .........................................52 Figura 3.33 Máquina de Mealy para o código da figura 3.32 ...................................53 Figura 4.1 Modelo de referência de sistemas ADSL ................................................56 Figura 4.2 Diagrama funcional do transmissor do modem ATU−C ..........................57 Figura 4.3 A estrutura de frame e superframe do modem ADSL ..............................58 Figura 4.4 A estrutura de um frame de dados do buffer fast .....................................58 Figura 4.5 A estrutura de um frame de dados do buffer interleaved .........................59 Figura 4.6 Constelação quando o comprimento de b for igual à 3 ............................61 Figura 4.7 Ativação e Acknowledgment ...................................................................62 Figura 4.8 Topologia da especificação do sistema ...................................................63 Figura 4.9 Trecho de código do ator BroadBandNet no MoC DE ............................64 Figura 4.10 Trecho de código da classe MuxDataFrame .........................................65 Figura 4.11 Trecho de código da classe FastFECDataFrame ..................................66 Figura 4.12 A topologia da especificação para o modem ATU−C ............................66 Figura 4.13 Trecho de código do ator MuxSyncTx no MoC DE ...............................68 Figura 4.14 Trecho de código do ator CRCTx ..........................................................70 Figura 4.15 Trecho de código do ator CRCRx ..........................................................71 Figura 4.16 Trecho de código do ator ScramblerTx .................................................72 Figura 4.17 Trecho de código do ator FECTx ..........................................................73 Figura 4.18 Trecho de código do ator FECRx ..........................................................74 Figura 4.19 Trecho de código do ator InterleaverTx ................................................75 Figura 4.20 Trecho de código do ator InterleaverRx ................................................76 Figura 4.21 Trecho de código do ator Map ..............................................................78 Figura 4.22 Trecho de código do ator Demap ..........................................................80 Figura 4.23 Trecho de código do ator IDFT no MoC DE .........................................81 Figura 4.24 Trecho de código do ator DFT no MoC DE ..........................................82 Figura 4.25 Classe auxiliar com os símbolos de inicialização ..................................82 Figura 4.26 Método fire() do ator Timer ..................................................................83 Figura 4.27 Método _getSymbol() do ator Initializer ...............................................84 Figura 4.28 Método _sendSymbol() do ator Initializer .............................................84 Figura 4.29 Método _detectSignal() do ator Initializer ............................................85 Figura 4.30 Método _transmitSignal() do ator Initializer .........................................86 Figura 4.31 Método _fire() do ator Initializer ..........................................................87
  14. 14. RESUMO Neste trabalho abordamos o problema da captura e validação da especificação funcional de um sistema digital através de especificações executáveis. Nos concentramos na comparação de modelos computacionais, isto é, o suporte semântico de uma linguagem de descrição de sistemas. O ambiente Ptolemy II foi escolhido para o desenvolvimento deste trabalho, uma vez que ele possui uma infra−estrutura para a implementação de modelos computacionais e criação de especificações executáveis. Comparamos seis modelos computacionais. Fundamentamos nossa metodologia na analise de comportamentos primitivos presentes em sistemas reais. Três comportamentos foram estudados: seqüência de expressões, desvio condicional e iteração com duração fixa. Uma ferramenta de software foi desenvolvida para auxiliar na comparação dos diferentes modelos computacionais através da reprodução da execução de uma especificação. Foi possível observar que o comportamento de seqüência de expressões foi capturado eficientemente pelos seis modelos computacionais. Os comportamentos de desvio condicional e iteração com duração fixa apresentaram dificuldades para a captura com alguns modelos. Finalmente, desenvolvemos a especificação de um modem ADSL. Utilizamos o modelo computacional que se mostrou mais eficiente para a captura dos três comportamentos. Identificamos um novo comportamento primitivo a partir desse estudo.
  15. 15. ABSTRACT In this dissertation we studied the problem of capture and validation of a functional specification of a digital system using executable specifications. We focused on comparing different models of computation, i.e., the semantic support of a system description language. We have chosen the Ptolemy II framework for the development of this work, since it has several models implemented and efficiently supports the addition of others. We compared six different models. We based our methodology on the analysis of primitive behaviors present in real systems. Three different behaviors we studied: sequence of expressions, conditional execution and fixed length iteration. We developed a software tool for helping the comparison of different models of computation by reproducing an execution. It was possible to efficiently capture the sequence of expressions with all six models. The other two primitive behaviors presented some difficulties under certain models. Finally, we developed the specification of an ADSL modem. An executable specification using the most efficient model for capturing the three behaviors was employed. We were able to identify a new primitive behavior from this case study.
  16. 16. 1 Capítulo 1 Introdução 1.1 Considerações Iniciais O desenvolvimento das tecnologias de microeletrônica vem possibilitando a criação de circuitos integrados cada vez mais complexos. Conforme foi previsto pela lei de Moore [BRE98], a capacidade de integração dobra a cada um ou dois anos. Os microprocessadores de alto desempenho são um bom exemplo dessa evolução: já existem processadores com mais de 20 milhões de transistores operando a freqüências acima de 1 GHz. Também já é uma realidade o projeto de circuitos de aplicação específica (ASIC) com milhões de transistores. Essa abundância de recursos possibilita a implementação de sistemas cada vez mais complexos, que podem ser realizados utilizando vários componentes discretos ou em apenas uma única pastilha. Este último caso é denominado de System−on−Chip (SOC). Embora o desenvolvimento da tecnologia de circuitos integrados seja fundamental para a implementação de sistemas cada vez mais versáteis e completos, ele também traz problemas. A principal dificuldade é lidar com a complexidade do projeto. Por exemplo, foi avaliado que durante o período de 20 anos, o número de transistores de um CI aumentou à uma taxa de 58% ao ano, enquanto que no mesmo período, a produtividade de um projetista, medida em número de transistores projetados por dia, aumentou à uma taxa de 21% [GAJ00]. Isso significa que não mais a capacidade de manufatura é o gargalo, mas sim o desenvolvimento do CI, ou seja, as ferramentas e metodologias CAD. A solução que a comunidade científica e industrial considera como sendo a mais promissora é elevar o nível de abstração na qual o projetista trabalha, pois assim a quantidade de detalhes é reduzida. Entretanto, um nível de abstração mais alto significa que linguagens de especificação, ferramentas de projeto, metodologias, etc, devem ser adequadas. Essa tarefa é bastante complexa pois envolve a mudança para um novo paradigma de projeto. Em [GAJ00], Gajski et al. identificam três metodologias sendo empregadas atualmente para o desenvolvimento de sistemas em alto nível: projeto baseado em plataformas (platform based design), integração de propriedade intelectual (IP Assembly), e síntese a partir de especificações (Synthesis from Specifications). Essas três soluções diferem em custo, esforço de projeto, flexibilidade e qualidade. O projeto baseado em plataforma [CHA99] fundamenta−se no uso de uma arquitetura pré− definida, otimizada para um tipo de aplicação. A metodologia empregada deve permitir a criação de uma especificação do sistema, para então mapeá−la na arquitetura. O projeto utilizando propriedade intelectual (IP) é baseado na reutilização de blocos pré− projetados e pré−caracterizados. A metodologia incorpora as tarefas de seleção de componentes e criação da arquitetura (envolve a interface entre blocos), além das tarefas presentes no projeto baseado em plataforma. O desafio para a solução utilizando blocos IPs é a criação de uma base de dados de componentes, além de formatos de troca de dados. Já existem esforços da comunidade de ferramentas CAD para atacar esses problemas [SYSC]. A síntese a partir de especificações significa implementar as diferentes funções da especificação diretamente em hardware e software. Essa solução é a mais flexível das três. A metodologia para projeto é bastante similar às outras duas soluções, com o problema adicional de particionar a especificação e criar métodos eficientes para explorar as inúmeras soluções arquiteturais. Embora existam três diferentes soluções sendo estudadas, todas elas requerem a criação de uma especificação executável para capturar o sistema nos diferentes níveis de abstração, desde sua funcionalidade até a implementação em uma arquitetura específica [GAJ00]. Conjuntamente com uma especificação para o ambiente no qual o sistema será implantado, é possível analisar o comportamento do sistema sendo desenvolvido através dos resultados da execução, tal qual em uma simulação tradicional. Esse tipo de técnica já vem sendo empregada na industria para o projeto de ASICs [SYSC], onde a linguagem de programação C é utilizada para capturar o algoritmo a ser implementado. Só após extensas análises e otimizações é que tal descrição em linguagem C é refinada para uma descrição em linguagem VHDL (comportamental/RTL).
  17. 17. 2 Toda linguagem de programação ou de descrição de hardware possui uma definição sintática e semântica. A semântica da linguagem define o significado de cada comando, ou seja, como aquele comando produz alguma alteração no estado do sistema ou ambiente e como ele está relacionado à outros comandos. A semântica de uma linguagem é definida com base em um modelo computacional (MoC), ou seja , um conjunto de definições e regras que possibilitam a representação formal e não ambígua de um algoritmo. Um exemplo clássico de modelo computacional é a máquina RAM [AHO74] associada à programas seqüenciais. O item 3.2 deste texto apresenta uma lista de alguns modelos computacionais. A escolha de um, ou um conjunto, de MoCs para o desenvolvimento de uma especificação executável depende de fatores como o domínio de aplicação, características semânticas do modelo e interação com outros modelos computacionais. Essa escolha irá afetar as tarefas de captura/validação do comportamento do sistema bem como posterior tarefa de sintetizar sua arquitetura. Nesse trabalho, iremos estudar a eficiência de alguns MoCs para capturar e validar a funcionalidade de um sistema. A motivação para nosso trabalho é: 1. o fato do projeto de sistemas eletrônicos através de metodologias top−down partirem da captura de sua especificação através de uma linguagem SLDL; 2. linguagens SLDL são sempre baseadas em um ou um conjunto de modelos computacionais o que pode limitar a possibilidade de capturar as especificações; 3. na existência de uma grande variedade de modelos computacionais. Portanto, é necessário que exista algum auxílio para o projetista, na forma de ferramentas, critérios, metodologias, tal que este possa identificar os modelos computacionais mais adequados para capturar as especificações de sua aplicação. 1.2 Trabalhos Relacionados O problema da escolha de um método de descrição para sistemas surgiu com o desenvolvimento das técnicas de co−projeto hardware/software (hardware/software codesign), pois uma única linguagem não era adequada para a captura do comportamento dos módulos em hardware e software. Isto ocorre devido as diferenças intrínsecas entre hardware e software. No nível sistêmico esse problema torna−se mais evidente, uma vez que é necessário capturar comportamentos heterogêneos como hardware analógico, hardware digital dominado pelo fluxo de dados, hardware digital dominado pelo fluxo de controle, dispositivos mecânicos, software com restrições temporais, etc. Três soluções foram estudadas: desenvolver uma nova linguagem, estender uma linguagem existente ou utilizar várias linguagens conjuntamente. Dentre inúmeros trabalhos que exemplificam tais soluções, podemos enumerar os seguintes:   [BEC92]: a linguagem de programação C e a linguagem de descrição de hardware Verilog são utilizadas conjuntamente para cosimular um sistema hardware/software;   [COS99]: inicialmente a linguagem SDL é utilizara para capturar a parte eletrônica de uma sistema mecatrônico e a linguagem Matlab para capturar o comportamento dos componentes mecânicos. Em seguida, o código em linguagem SDL é refinado para uma descrição utilizando linguagem C e VHDL;   [LAV99]: a semântica da linguagem C é estendida com comandos da linguagem Esterel. Esse trabalho concentra−se em sistemas dominados pelo fluxo de controle, mas que necessitam de uma linguagem eficiente para descrever as partes dominadas pelo fluxo de dados;   [MAR98]: a linguagem de programação Java foi estendida com algumas classes, tornando−a adequada para capturar sistemas reativos;   [REE95]: a linguagem Haskell é utilizada conjuntamente com um ambiente gráfico para capturar sistemas dominados pelo fluxo de controle;
  18. 18. 3   [SYSC]: a linguagem C++ é estendida através de um conjunto de classes para permitir a descrição de circuitos síncronos;   [GAJ00]: uma nova linguagem foi desenvolvida visando a captura e refinamento de sistemas digitais;   [DAV99]: a linguagem Java é utilizada conjuntamente com um grupo de classes que permitem a implementação de diversos modelos computacionais. Nenhum dos trabalhos mencionados procura analisar quando cada linguagem ou característica semântica deve ser empregada. Em geral, uma classe específica de sistema é escolhida e a linguagem mais apropriada é empregada. O único trabalho que encontramos que aborda a comparação de modelos computacionais é [LEE98]. Entretanto, a comparação é feita de maneira descritiva e teórica. 1.3 Estrutura do Texto Esta dissertação apresenta os seguintes capítulos:   Capítulo 2: descreveremos os fundamentos teóricos e práticos necessários para o desenvolvimento desse trabalho. Descreveremos uma ferramenta de software que desenvolvemos;   Capítulo 3: apresentaremos nossa metodologia para o estudo do problema da escolha de modelos computacionais;   Capítulo 4: apresentaremos o estudo de caso de um sistema real que desenvolvemos para aplicar alguns dos resultados obtidos no capítulo 3;   Capítulo 5: contém o resumo final do trabalho e propostas para trabalhos futuros.
  19. 19. 4 Capítulo 2 Fundamentos 2.1 Introdução Nesse capítulo faremos uma breve descrição dos fundamentos utilizados nesse trabalho e introduziremos termos utilizados ao longo dessa dissertação. Inicialmente, o ambiente Ptolemy será descrito. Seus componentes internos serão apresentados juntamente com um exemplo de como uma especificação executável é criada. Em seguida, descreveremos os modelos computacionais que estudamos e enumeraremos outros importantes modelos encontrados na literatura. Ao final do capítulo apresentaremos uma ferramenta que desenvolvemos para a análise da execução de especificações. 2.2 O Ambiente Ptolemy O ambiente Ptolemy II [DAV99] é a segunda geração de um projeto sendo desenvolvido na Universidade da Califórnia em Berkeley desde 1990. Inicialmente voltado para o desenvolvimento de sistemas (hardware e software) para processamento digital de sinais, atualmente seu principal objetivo é dar suporte ao desenvolvimento de sistemas embutidos (embedded systems), principalmente os componentes de software do sistema. O fundamento central do ambiente Ptolemy1 é a utilização conjunta de diferentes modelos computacionais para a captura das especificações do sistema. A heterogeneidade observada em sistemas embutidos é a justificativa para essa abordagem, isto é, um sistema embutido pode utilizar várias tecnologias distintas como hardware analógico, hardware digital, componentes ópticos, componentes mecânicos, software de tempo real, etc. Dessa forma, um único MoC não é eficiente para a captura do sistema. 2.2.1 A Implementação do Ambiente Ptolemy A linguagem de programação Java foi escolhida pelo grupo de desenvolvimento do ambiente Ptolemy. Essa também é a linguagem de programação utilizada para criar uma especificação executável, ou seja, um especificação no ambiente Ptolemy é um conjunto de classes criadas pelo usuário mais um conjunto de classes disponíveis no ambiente. A figura 2.12 apresenta resumidamente um diagrama estático de classes pertencentes aos dois pacotes centrais do ambiente: Kernel e Actor. Outros pacotes auxiliares também estão disponíveis, além de pacotes que implementam modelos computacionais. 1 Quando utilizamos o termo Ptolemy, estamos nos referindo à versão II do ambiente, e não a versão Classic (anterior). Caso seja necessário, faremos explicitamente a distinção entre as versões. 2 Por conveniência, as figuras mostradas no item 2.2 foram extraídas da documentação do ambiente Ptolemy[DAV99]. Para uma descrição completa do ambiente, utilize tal referência.
  20. 20. 5 Figura 2.1 − Diagrama estático de classes simplificado dos pacotes Actor e Kernel. 2.2.1.1 O Pacote Kernel: Sintaxe da Especificação O pacote Kernel é composto por um conjunto de classes para implementar e manipular grafos com nós hierárquicos, também chamados de topologias. Uma topologia não hierárquica é constituída por entidades (Entity) e relações (Relation). A figura 2.2 apresenta um exemplo de topologia3 . Figura 2.2 − Uma topologia não hierárquica. Cada entidade pode possuir vários portos (Port) e uma relação pode conectar vários portos entre si. O uso de portos e relações torna uma topologia diferente de um grafo matemático. Uma relação é uma conexão entre múltiplos elementos. Já em grafos matemáticos, arcos são conexões entre dois elementos. Um grafo matemático poderia ser representado através de entidades designando os nós do grafos e cada uma possuindo exatamente um porto. No caso de um grafo direcionado, cada entidade possuiria dois portos, uma para arcos de entrada e outro para arcos de saída. 3 Ao contrário da figura 2.2, nas representações gráficas de topologias apresentadas nos capítulos seguintes, utilizaremos retângulos como representação gráfica para atores e setas direcionadas para representar conexões entre dois ou mais atores. O terminal com a seta indica o ator de destino e o outro terminal o ator de origem. Dessa forma, não iremos mostrar de forma explícita as relações. Nameable <<Interface>> <<Interface>> Executable <<Interface>> Actor NamedObj Entity ComponentEntity AtomicActor Manager Port Relation Workspace CompositeEntity CompositeActor Director ComponentPort ComponentRelation 0..n 0..1 0..n 1 0..n Container 0..n 0..nLink Link Container 0..1 0..n 0..1 0..1 1 0..2 Container 0..n 0..1 1 0..1 0..n Implementa Deriva Pertence ao pacote Kernel Pertence ao pacote Actor Attribute Entidade Porto Entidade Porto Entidade Porto Relação Link Link Link
  21. 21. 6 Como mostrado na figura 2.1, cada uma das três principais classes do pacote Kernel possui uma classe derivada com o prefixo Component. A finalidade dessas classes é permitir a criação de topologias hierárquicas. Além dessas três classes, a classe CompositeEntity é utilizada para conter objetos do tipo ComponentEntity e ComponentRelation. Dessa forma, uma CompositeEntity contém uma sub−topologia. Entidades que não contenham sub−grafos são denominadas de atômicas. A figura 2.3 apresenta um exemplo de topologia hierárquica, onde E0 e E1 são entidades do tipo CompositeEntity. Figura 2.3 − Exemplo de topologia hierárquica. Os portos P3 e P4 da figura 2.3 são denominados de transparentes (transparent), enquanto que os demais são denominados de opacos (opaque). Esse conceito também se aplica a entidades, como será mostrado mais adiante. Um porto é opaco quando a entidade que o contém é opaca, e é transparente quando a entidade que o contém é transparente. Quando um porto for opaco, conexões com uma possível sub−topologia são invisíveis. Já um porto transparente permite que algoritmos percorram todas as conexões associadas a ele. Por exemplo, existe um método na classe ComponentPort denominado deepConnectedPortList(). Esse método retorna uma lista de todos os portos conectados, independentemente do nível de hierarquia. No caso do porto P1 da figura 2.3, esse procedimento retornaria os portos P2, P5 e P6. Portos transparentes não são retornados. Quando o procedimento atinge o porto P4, através da relação R2, o procedimento continua pesquisando, através das relações R3 e R4. 2.2.1.2 O Pacote Actor: Suporte à Semântica As classes do pacote Kernel definem uma topologia onde as entidades não possuem semântica. O pacote Actor é composto por um conjunto de classes para adicionar semântica à topologia e permitir a implementação de um modelo computacional específico, derivando−se das principais classes do pacote actor. Além das classes mostradas na figura 2.1, a classe IOPort e a interface Receiver também possuem papel importante. Duas características são necessárias para a implementação de uma semântica: troca de dados entre os atores da topologia e o controle da execução. Troca de Dados A figura 2.4 ilustra o processo básico de troca de dados. Figura 2.4 − Exemplo de troca de dados Dois portos são utilizados na figura 2.4: um de saída (P1) e um de entrada (P2). Eles são E0 E1 E2 E3 E4 E5 P1 P2 P3 P4 P5 P6 R1 R2 R3 R4 send(0, t0) send(1, t1) 2 2 2 get(0), get(1) token t0, t1 receiver.put(0) receiver.put(1) P1 P2
  22. 22. 7 instâncias da classe IOPort. Essa classe disponibiliza vários métodos, entre eles o método send(), utilizado por um porto de saída para enviar dados aos portos conectados, e o método get(), utilizado por um porto de entrada para receber dados. No ambiente Ptolemy, os dados são transmitidos encapsulados em tokens. Uma vez criado, o valor de um token é imutável4 . A função do método send() é transferir os dados para um elemento denominado de receptor (receiver). Cada conexão com um porto de entrada possui associado um receptor. Na figura 2.4, temos duas conexões associadas. Cada conexão também é denominada de canal. Quando um porto possui mais de um canal, como na figura 2.4, deve−se especificar no método send() e get() por qual canal o token deve ser enviado ou recebido. Isso é feito através do primeiro argumento desses métodos. Uma vez que os dados estejam presentes no respectivo receptor, o ator de destino pode executar o método get() e obter os dados. No pacote Actor, o receptor não é uma classe concreta, mas sim uma interface. O receptor é implementado como parte do modelo computacional, pois diferentes modelos possuem semânticas distintas de comunicação entre elementos. Por exemplo, atores em um modelo data flow comunicam−se através de filas. As filas são implementadas em um receptor. Já no modelo Discrete Event, o receptor deve enviar os dados para uma fila global. Controle da Execução A classe Director do pacote Actor tem o principal papel no controle da execução. A implementação de um modelo computacional deve derivar essa classe a fim de implementar métodos como fire(), prefire() e postfire() definidos na interface Executable. Em um Director, esses métodos são responsáveis pelo controle da execução dos blocos do sistema. Para tal, é introduzido o conceito de iteração. A cada iteração da execução, o método prefire() é o primeiro a ser chamado, em seguida o método fire(), seguido pelo método postfire(). O comportamento exato de cada método é definido pela implementação de um modelo computacional. Em geral, o escalonador5 de um MoC é implementado nos métodos fire() e postfire() do respectivo Director. Um Director deve sempre estar associado a um único ator Composite. Essa associação torna o ator opaco. A utilização de um Director é ilustrada na figura 2.5. Figura 2.5 − Exemplo de topologia para ilustrar o uso da classe Director. O Director D1 está associado ao ator E0, que representa o nível mais alto da hierarquia (ator toplevel). Nesse nível, existem três atores: E1, E2, E3. O bloco E1 é um ator atômico. O bloco E3 é um ator hierárquico transparente, já que não existe nenhum Director associado à ele. Quem governa a execução da sub−topologia do ator E3 é o Director D1. Já o bloco E2 é um ator hierárquico opaco, pois o Director D2 está associado à ele. Para o Director D1, o bloco E2 é um ator atômico. Ao chamar o método fire() de E2, o controle é passado para o Director D2. Dessa forma, a ferramenta implementa um mecanismo transparente para a co−simulação de sistemas utilizando MoCs distintos. A figura também apresenta um Manager. Este deve ser único no sistema e associado ao ator toplevel. Sua função é iniciar, interromper e coordenar a execução de todo o sistema. 2.2.1.3 Outras Classes Importantes 4 Como será descrito adiante no texto, o tipo ObjectToken é uma exceção à essa regra. 5 Escalonador é um algoritmo utilizado para determinar uma ordem de execução dos atores. O escalonador pode ser seqüencial (apenas um ator executa a cada momento) ou paralelo (mais de um ator executa a cada momento). E0 D1: local director E1 P1 P2 P5 E4 P6 E2 D2: local director E5 P7P4P3 E3
  23. 23. 8 Além dos pacotes descritos acima e os que implementam diversos modelos computacionais, o ambiente Ptolemy apresenta um conjunto de classes auxiliares, como o pacote Plot, uma aplicação para visualizar gráficos bidimensionais, pacotes de funções matemáticas e um pacote para implementação de um sistema de tipos de dados (type system). Tipos de Dados no Ambiente Ptolemy A classe Token e suas derivadas compõem o coração do pacote de dados do ambiente Ptolemy. Como mencionado anteriormente, todos os dados transmitidos entre atores são encapsulados em tokens. A classe Token apresenta apenas a definição de alguns métodos utilitários, como operações aritméticas. Entretanto, o ambiente possui um sistema de tipos com várias subclasses para diferentes tipos de dados. A figura 2.6 apresenta o type lattice do ambiente. Os tipos Numerical e Scalar são classes abstratas. Figura 2.6 − Type lattice do ambiente Ptolemy. Em geral, os portos de entrada/saída e os parâmetros6 de um ator podem ser criados com um tipo associado. Esse tipo pode ser especificado pelo usuário de forma exata, utilizando o método setTypeEquals(), ou de forma relativa. Neste caso, três métodos estão disponíveis: setTypeAtLeast(), especifica que o tipo do objeto em questão deve ser maior ou igual ao do parâmetro do método; setTypeAtMost(), indica que o tipo do objeto deve ser menor ou igual ao do parâmetro do método: setTypeSameAs(), indica que o tipo do objeto deve ser igual ao do parâmetro do método. No início da execução, o ambiente (mais precisamente, uma instância do objeto Manager) irá verificar se existe a consistência de tipos, ou seja, se um porto de entrada conectado à um porto de saída apresentam o mesmo tipo, ou se existe a possibilidade de conversão sem perdas (baseado no lattice da figura 2.6). Caso alguns tipos não estejam especificados ou foram especificados de forma relativa, haverá a resolução de tipos. 2.2.2 Utilizando o Ambiente Ptolemy 6 Parâmetro é um objeto que também pode armazenar um token, e dessa forma também é tipado. O parâmetro pode ser utilizado para especificar valores de configurações de um objeto, tornando−o mais flexível. General String Matrix Numerical Object BooleanMatrix Boolean FixMatrix Fix Scalar LongMatrix ComplexMatrix DoubleMatrix IntMatrix Array Long Complex Double Int NaT
  24. 24. 9 O item 2.2.1 ilustrou de forma suscinta os principais componentes internos do ambiente Ptolemy. Utilizando essa infra−estrutura, podemos criar uma especificação executável. Para isso, é necessário criar os atores da especificação, interconectá−los e associar à especificação um ou mais modelos computacionais. A figura 2.7 apresenta o esqueleto básico de um ator atômico. 1− public class AtorExemplo extends TypedAtomicActor { 2− 3− public TypedIOPort entrada; 4− public TypedIOPort saida; 5− 6− public Parameter par; 7− 8− public AtorExemplo(TypedAtomicActor container, String name) 9− throws NameDuplicationException, IllegalActionException { 10− 11− super(container, name); 12− 13− entrada = new TypedIOPort(this, ¨entrada¨, true, false); 14− entrada.setTypeEquals(BaseType.INT); 15− 16− saida = new TypedIOPort(this, ¨saida¨, false, true); 17− saida.setTypeEquals(BaseType.DOUBLE); 18− 19− par = new Parameter(this, ¨parametro1¨, new IntToken(1)); 20− 21− } 22− 23− public void initialize() throws IllegalActionException { 24− 25− IntToken it = (IntToken) par.getToken(); 26− _var = it.intValue(); 27− 28− } 29− 30− public boolean prefire() throws IllegalActionException { 31− 32− .... 33− return super.prefire(); 34− } 35− 36− public void fire() throws IllegalActionException { 37− 38− IntToken it = (IntToken) entrada.get(0); 39− 40− saida.broadcast(DoubleToken.convert(it)); 41− } 42− 43− public boolean postfire() throws IllegalActionException { 44− 45− .... 46− return super.postfire(); 47− } 48− 49− public void wrapup() throws IllegalActionException { 50− 51− super.wrapup(); 52− 53− .... 54− } 55− 56− private int _var; 57− } Figura 2.7 − Um exemplo genérico de ator atômico. Na linha 1, o ator é criado derivando a classe TypedAtomicActor, ou seja, é um ator atômico com portos tipados. Em certos modelos computacionais, novas classes de atores atômicos são criadas estendendo a classe TypedAtomicActor. Da linha 3 à linha 6, dois portos e um parâmetro são declarados como variáveis públicas. Da linha 8 à linha 21 está implementado o construtor da classe. Duas exceções implementadas pelo ambiente Ptolemy são declaradas na linha 9. Na linha 13 o porto de entrada (o terceiro parâmetro do construtor é true) é criado . Em seguida, o tipo do porto é determinado como sendo um inteiro. O porto de saída (neste caso, o quarto parâmetro do construtor deve ser true) é criado de maneira similar nas linhas 16 e 17. Na linha 19, o parâmetro do ator é criado e inicializado como tendo tipo inteiro com valor inicial igual à 1 (terceiro parâmetro).
  25. 25. 10 Observando a figura 2.1, note que a classe AtomicActor (pai da classe TypedAtomicActor) implementa a interface Executable. Nessa interface estão declarados, entre outros, os métodos initialize(), prefire(), postfire(), fire() e wrapup(). Conforme mencionado no item 2.2.1.2, esses métodos são usados pela classe Director e suas derivadas para o controle da execução. No caso de um ator atômico, esses métodos são definidos pelo usuário para implementar o comportamento desejado. A função de cada método é:   initialize() (linha 23 à 28): chamado uma única vez durante a execução, antes de todos os outros métodos. No exemplo da figura 2.7, esse método é utilizado para obter e armazenar o valor do parâmetro do ator em uma variável interna7 (linhas 25 e 26);   prefire() (linha 30 à 34): primeiro a ser chamado, uma única vez, durante uma iteração da execução. Caso um valor false seja retornado, isso indica que o ator não está apto para ser executado;   fire() (linha 36 à 41): pode ser chamado várias vezes em uma mesma iteração, após o método prefire(). Na linha 38, um token é lido do porto de entrada, utilizando o método get(). Na linha 40, o valor do token é convertido de inteiro para real, e enviado utilizando o método broadcast(). Esse método envia o dado para todos os portos de entrada conectados à ele;   postfire() (linha 43 à 47): similar ao método prefire(). Ele é o último método a ser chamado em uma iteração;   wrapup() (linha 49 à 54): chamado uma única vez ao final da execução. Uma vez que todos os atores de uma especificação são criados, é necessário interconectá−los e criar os objetos que irão controlar a execução. A figura 2.8 apresenta o esqueleto básico de um trecho de código para tal função. 1− public class Sistema { 2− 3− public static void main(String args[]) throws 4− IllegalStateException, IllegalActionException, 5− NameDuplicationException { 6− 7− TypedCompositeActor toplevel = new TypedCompositeActor(); 8− toplevel.setName("teste1"); 9− 10− Manager exec = new Manager("exec"); 11− toplevel.setManager(exec); 12− 13− Director local = new Director(toplevel, "Local"); 14− 15− AtorExemplo a1 = new AtorExemplo(toplevel, ¨a1¨); 16− a1.par.setToken(new IntToken(10)); 17− 18− AtorExemplo a2 = new AtorExemplo(toplevel, ¨a2¨); 19− AtorExemplo a3 = new AtorExemplo(toplevel, ¨a3¨); 20− 21− toplevel.connect(a1.saida, a2.entrada); 22− 23− TypedIORelation r1 = new TypedIORelation(toplevel, ¨r1¨); 24− a2.saida.link(r1); 25− a3.entrada.link(r1); 26− 27− exec.run(); 28− } 29− } Figura 2.8− Exemplo de arquivo principal de uma especificação executável. Na linha 7, o ator de nível mais alto (toplevel) é criado. Nenhum outro ator Composite é utilizado, dessa forma, o exemplo da figura 2.8 não é hierárquico. Na linha 10, uma instância de objeto Manager é criada e associada ao ator hierárquico toplevel (linha 11). Na linha 13, um Director é criado e associado ao ator hierárquico. Esse ator, um objeto Manager e um objeto Director, sempre estarão presentes em qualquer especificação executável. Três instâncias do ator da figura 2.7 são utilizadas. Na linha 16, o valor padrão do parâmetro par do AtorExemplo exemplo é modificado. Na linha 21, é feita a conexão entre dois portos, através do método connect() do ator hierárquico. Outra forma de criar uma 7 Adotamos como notação adicionar um caractere _ ao início de um nome de variável quando esta for private.
  26. 26. 11 conexão é exemplificada da linha 23 à linha 25, através da criação explícita de um objeto Relation. O comando da linha 27 é utilizado para iniciar a execução. 2.3 Os Modelos Computacionais Descreveremos nesse item a semântica dos seis modelos computacionais (MoC) que utilizamos e características referentes à implementação desses modelos no ambiente Ptolemy. Iremos ressaltar dois pontos importantes de um MoC: o escalonador e o modelo de tempo. Em seguida, apresentaremos uma lista não exaustiva de outros modelos. É importante notar que um mesmo MoC pode ser implementado de várias maneiras diferentes. Todos os resultados desse trabalho são referentes as implementações adotadas no ambiente Ptolemy. 2.3.1. Discrete Event O modelo computacional Discrete Event [MUL99] (DE) é baseado no processamento de eventos produzidos pelos atores. Um evento é um par composto por um token e um valor numérico real. Esse valor numérico é denominado de timestamp e sua função é modelar um valor temporal, ou seja, o modelo DE possui uma noção explícita de tempo. O tempo nesse modelo é compartilhado por todos os atores da especificação. Quando um ator produz um evento, este é enviado para uma fila de eventos controlada pelo escalonador, e não para o ator de destino. Os eventos são mantidos ordenados de forma crescente na fila, com base no valor do timestamp. A cada iteração, o escalonador remove o próximo evento da fila e envia−o ao ator de destino. Esse ator é então ativado, isto é, o escalonador executa os métodos prefire(), fire() e postfire(). É possível criar uma especificação com atores que não manipulam o valor do timestamp. Esse tipo de ator é denominado de atraso zero (zero delay). A execução de uma especificação no modelo DE é interrompida quando não há mais nenhum evento na fila ou quando um valor de tempo especificado para o fim da execução é alcançado. Uma situação de conflito que pode ocorrer nesse modelo é a presença de eventos simultâneos, ou seja, eventos com um mesmo timestamp. A figura 2.9 ilustra esse situação. Figura 2.9 − Situação de eventos simultâneos no MoC DE. Na situação da figura 2.9, o ator A produziu dois eventos com um mesmo timestamp T. Um evento é para o ator B, e o outro para o ator C. Nessa situação, qual deve ser o próximo ator a ser ativado? A solução implementada no ambiente Ptolemy associa a cada ator um valor inteiro não negativo e único (prioridade). Esse valor é obtido através de uma ordem topológica de um grafo, onde os nós são os atores e os arcos representam as conexões que não apresentam atraso. Como mencionado em [MUL99], essa solução torna a execução da especificação determinística. É possível que o grafo gerado contenha ciclos. Isso significa que a especificação contém um ciclo sem atraso, situação que impede a execução da especificação, pois introduz um loop com geração infinita de eventos. Neste caso, o ambiente gera uma mensagem indicando para o usuário do problema. Os principais passos do algoritmo de escalonamento do MoC DE são: 1. caso a fila de eventos esteja vazia ou o instante de tempo final tenha sido alcançado, vá para o passo 9; 2. obtenha o próximo evento da fila; Ramp A Ramp B Ramp C T T
  27. 27. 12 3. atualize o instante de tempo atual para o valor do timestamp do evento obtido no passo 2; 4. determine o ator de destino do evento obtido e introduza o token no respectivo porto de destino; 5. caso não exista nenhum outro evento simultâneo para o ator do passo 4, vá para o passo 7; 6. obtenha todos os eventos simultâneos para o ator do passo 4 e introduza−os nos respectivos portos do ator; 7. ative o ator até que todos os tokens em seus portos tenham sido consumidos; 8. vá para o passo 1; 9. fim. Quando mais que um evento com o mesmo timestamp estiver disponível para um ator, todos são removidos da fila de eventos (passos 4, 5, 6). Nessa condição, caso mais que um evento seja para o mesmo porto, uma fila é utilizada no porto de entrada/saída, respeitando a ordem desses eventos na fila do escalonador. É possível criar atores de atraso zero utilizando as classes TypedAtomicActor e TypedAtomicPort, mencionadas no item 2.2. Entretanto, para utilizar as características específicas do MoC DE, as classes DEIOPort e DEActor estão disponíveis. A figura 2.10 apresenta um trecho de código de um ator utilizando tais classes. 1− .... 2− import ptolemy.domains.de.kernel.*; 3− import ptolemy.domains.de.lib.DETransformer; 4− .... 5− 6− public class Delay extends DETransformer { 7− 8− public Delay(TypedCompositeActor container, String name) throws 9− NameDuplicationException, IllegalActionException { 10− super(container, name); 11 12− delay = new Parameter(this, "delay", new DoubleToken(1.0)); 13− delay.setTypeEquals(BaseType.DOUBLE); 14 15− input.delayTo(output); 16− } 17− 18− public Parameter delay; 19− 20− .... 21− 22− public void fire() throws IllegalActionException { 23− _currentInput = input.get(0); 24− } 25− 26− public boolean postfire() throws IllegalActionException { 27− output.broadcast(_currentInput, 28− ((DoubleToken)delay.getToken()).doubleValue()); 29− return super.postfire(); 30− } 31− 32− private Token _currentInput; 33− } Figura 2.10 − O ator Delay no MoC DE. O ator da figura 2.10 implementa um atraso por um tempo especificado através de um parâmetro (linha 18). O comando da linha 15 indica que existe um caminho com atraso entre um porto de entrada e um porto de saída. Essa informação é utilizada durante a criação do grafo utilizado para determinar o valor de prioridade de cada ator. Nas linhas 27 e 28 o evento é criado, através de uma versão específica do método broadcast(). Nessa versão, o segundo parâmetro indica o valor do atraso. 2.3.2 Synchronous Reactive O modelo computacional Synchronous Reactive [EDW94][EDW97] (SR) é baseado na hipótese
  28. 28. 13 de sincronismo: o sistema é capaz de produzir uma resposta à estímulos externos de forma infinitamente rápida. Cada reação do sistema é instantânea e atômica, dessa forma, a evolução do tempo é dividida em uma série de instantes discretos. A hipótese de sincronismo também é utilizada por uma classe de linguagens de programação, tais como Esterel, Lustre, Signal, denominada de síncrona [BER98][HAL93][BEN91], além de circuitos digitais síncronos. Antes de descrevermos com maior detalhe a semântica do modelo SR, é necessário mencionar algumas definições, proposições e teoremas importantes. As demonstrações para esses teoremas e proposições podem ser encontradas em [EDW97]. Definição 1: Um conjunto parcialmente ordenado (poset) é um conjunto S com uma relação parcial de ordem ¡ que, para quaisquer x, y, e z pertencentes à S, satisfaz:   x ¡ x (reflexiva);   x ¡ y e y ¡ x implica que x = y (antissimétrica);   x ¡ y e y ¡ z implica que x ¡ z (transitiva); Definição 2: Um limite superior de um conjunto T é um elemento u tal que t ¡ u para todos t ¢ T. O menor limite superior de um conjunto T, representado por £ T, é um elemento l tal que l ¡ u para todos limites superiores u. Proposição 1: O menor limite superior de um conjunto, se existir, é único. Definição 3: Uma cadeia é um conjunto totalmente ordenado C, isto é, para todo x, y ¢ C, ou x ¡ y ou y ¡ x. Definição 4: Um poset, onde toda cadeia em S possui um menor limite superior em S, é denominado de conjunto parcialmente ordenado completo (CPO). Proposição 2: O menor limite superior de uma cadeia finita sempre existe e é seu maior elemento. Corolário 1: Um poset apenas com cadeias finitas é um CPO. Definição 5: O limite inferior de um poset, representado por ¤ , é um membro de S tal que ¤ ¡ s para todo s ¢ S. Um poset com um limite inferior é denominado de poset pontual. Proposição 3:
  29. 29. 14 Se D1 e D2 são CPOs, então D1 ¥ D2 é um CPO sob a ordem (x1, x2) ¡ (y1, y2) se e somente se x1 ¡ y1 e x2 ¡ y2 e se x1 = (x1 1, x1 2) x2 = (x2 1, x2 2), .... ¦ {x1 ,x2 ,...} = ( £ {x1 1, x2 1, ...}, £ {x1 2, x2 2, ...}). Definição 6: Uma função f:D § E entre posets D e E é monotônica se para todo x,y ¢ D tal que x ¡ y, f(x) ¡ f(y). Definição 7: Uma função f:D § E entre CPOs D e E é contínua se para todas as cadeias C ⊆ D, f( £ C) =£ {f(c) ¨ c ¢ C}. Proposição 4: Uma função contínua é monotônica. Proposição 5: Uma função monotônica cujo domínio é um CPO com apenas cadeias finitas é contínua. Proposição 6: A composição de duas funções contínuas também é contínua. Proposição 7: A composição de duas funções monotônicas também é monotônica. Proposição 8: Seja D, E e F CPOs. Se f:D § E e g:D § F contínuas, então f¥ g também é contínua. Definição 8: Seja D um poset, f:D § D uma função e x © D:   se f(x) ¡ x, então x é um ponto prefixo;   se f(x) = x, então x é também um ponto fixo;   se x é um ponto prefixo e x ¡ p para todo ponto prefixo p, então x é um menor ponto prefixo;   se x é um ponto fixo e x ¡ y para todo ponto fixo y, então x é um menor ponto fixo; Teorema 1:
  30. 30. 15 Seja f:D § D uma função contínua sobre um CPO pontual D. Então: fix(f) ≡ £ {¤ f(¤ ), f(f(¤ )), ...., fk (¤ ), ...} existe e é tanto um único menor ponto fixo como um único menor ponto prefixo de f. Definição 9: Seja I = I1 ¥ .... ¥ In e O = O1 ¥ .... ¥ Om vetores de CPOs pontuais. Denomina−se bloco uma função vetorial contínua de I sobre O. Definição 10: Seja b : I § O um bloco, J = J1 ¥ .... ¥ Ja um vetor de CPOs pontuais e w1,....,wn uma seqüência tal que wk ¢ {1, .... , a}. Se Jwk ⊆ Ik, então o bloco conectado à J com as conexões w1, ...., wn é a função c : J § O tal que c(j1, ...., ja) = b(jw1, ...., jwn) onde (j1, ...., ja) ¢ J. Definição 11: Seja b1 : I § O, b2 : I § O, ...., bn : I § O um conjunto de blocos, I = I1 ¥ .... ¥ In um vetor de CPOs pontuais, O = O1 ¥ .... ¥ Os e J = I ¥ O. O sistema aberto composto por esses blocos é a função d: J § O tal que d(j) = c1(j) ¥ c2(j) ¥ .... ¥ cs(j) onde ck é o bloco bk conectado ao vetor J, e j ¢ J. O modelo computacional SR enxerga o sistema como sendo uma função. Seja d um sistema aberto, a função SR é a menor função e:I § O que satisfaça e(i) = d(i, e(i)), (1) onde I e O são vetores de CPOs pontuais. A figura 2.11 apresenta uma ilustração das definições 10, 11 e de uma função SR.
  31. 31. 16 Figura 2.11 − Ilustrações das definições do MoC SR: (a) O sistema; (b) O sistema aberto correspondente; (c) O bloco correspondente. A equação (1) é um ponto fixo, onde a função e é o parâmetro. Dessa forma, podemos escrever: e = B(e), onde B:(I § O) § (I § O) é uma função que transforma uma função em outra função. Utilizando o teorema 1, Edwards demonstra que a função B apresenta um único menor ponto fixo. Para tal, ele demonstra que o domínio de B é um CPO pontual e que B é contínua. Isso implica que o MoC SR é determinístico. O valor de cada sinal no MoC SR pode estar em um de três estados: indefinido, definido e ausente (nenhum evento no instante) ou definido e presente (evento com um valor no instante). No início de cada instante, todos os sinais, a menos das entradas do sistema, estão no estado indefinido. Uma vez que um sinal passa do estado indefinido para um definido, esse sinal não pode mais mudar de estado ou valor. Essa regra é necessária para assegurar que o ator implementa uma função monotônica (e pela proposição 5, contínua). Os três estados formam uma CPO, com o estado indefinido sendo o limite inferior. A implementação do MoC SR no ambiente Ptolemy consiste de um escalonador que resolva o cálculo de um menor ponto fixo para o sistema. Edwards descreve um método capaz de determinar em tempo de compilação uma ordem de ativamento de atores que encontra o menor ponto fixo. Entretanto, o método é relativamente complexo para ser descrito brevemente nessa dissertação. O escalonador que utilizamos baseia−se no teorema 1 para encontrar o menor ponto fixo: 1. execute todos os atores e verifique se algum sinal passou do estado indefinido para o definido; 2. se não houver modificação no estado dos sinais, então o ponto fixo foi encontrado. Do contrário, repita o passo 1. Em [EDW94], Edwards prova que esse escalonador irá encontrar o menor ponto fixo em um Ramp F1 F2 F3 F4 F4 F1 F2 F3 1 2 3 4 5 1 2 3 4 5 O O J I d I Oe (c) (b) (a)
  32. 32. 17 número finito de iterações. No MoC SR, um ator atômico é dividido em dois tipos: Strict e Non−Strict. Atores Strict são aqueles que requerem que todos os sinais de entrada estejam definidos para ocorrer o ativamento. Atores Non−Strict não possuem essa restrição, e portanto, são mais flexíveis. Uma das razões para a existência de atores desse tipo é que em caminhos de realimentação, caso apenas atores Strict fossem utilizados, o sistema entraria em deadlock. A figura 2.12 apresenta um exemplo de ator Non−Strict que implementa um atraso por um instante. 1− .... 2− public class SRPre extends TypedAtomicActor { 3− 4− public SRIOPort input; 5− public SRIOPort output; 6− 7− public SRPre(TypedCompositeActor container, String name) 8− throws IllegalActionException, NameDuplicationException { 9− super(container, name); 10− 11− input = new SRIOPort(this, input1, true, false); 12− input.setTypeEquals(BaseType.INT); 13− 14− output = new SRIOPort(this, output, false, true); 15− output.setTypeEquals(BaseType.INT); 16− output.setMultiport(true); 17− 18− ((SRDirector) getDirector()).setStrict(this, false); 19− } 20− 21− public void initialize() throws IllegalActionException { 22− super.initialize(); 23− _state = 0; 24− } 25− 26− public void fire() throws IllegalActionException { 27− if(!output.known(0)) { 28− output.send(0, new IntToken(_state)); 29− } 30− } 31− 32− public boolean postfire() throws IllegalActionException { 33− if(input.present(0)) { 34− _state = ((IntToken) input.get(0)).intValue(); 35− } 36− return true; 37− } 38− 39− private int _state; 40− } Figura 2.12 − Ator de atraso no MoC SR. A linha 18 utiliza o método setStrict() para determinar que o ator é do tipo Non−Strict. Na linha 27, é determinado se o sinal de saída ainda não está definido. Caso positivo, o valor atual da variável interna é enviado. No MoC SR, o método fire() pode ser chamado inúmeras vezes a cada instante. Dessa forma, ações que o usuário deseje realizar uma única vez por instante devem ser efetuadas no método postfire(). No caso do ator da figura 2.12, a atualização do estado (linha 34) é feita nesse método. 2.3.3 Communicating Sequential Processes O modelo computacional Communicating Sequential Processes (CSP) [HOA78] [HOA85] [SMY98] é fundamentado no uso de processos concorrentes, cada ator associado à um único processo. O escalonamento dos processos é feito pelo ambiente de execução da linguagem Java. Nesse modelo não há armazenamento de dados entre processos, a transferência de dados é feita através do protocolo de rendezvous. Nesse protocolo, um ator A executa o método send() ou broadcast() para enviar um dado à um ator B. O ator A permanece bloqueado enquanto o ator B não consome o token. O mesmo acontece quando um ator tenta consumir um token quando este ainda não está disponível. O MoC CSP permite o rendezvous não−determinístico através de comandos de comunicação
  33. 33. 18 condicional (guarded). Esses comandos apresentam a seguinte forma: guard; comunicação = lista de comandos; O guard é uma expressão que retorna um valor booleano. Não é permitido que seu cálculo produza alterações no estado interno do processo. Caso o valor retornado seja falso, o comando é encerrado. Caso contrário, o comando de comunicação especificado é iniciado e quando ele for completado, a lista de comandos é executada. Dois tipos de comando de comunicação condicional estão disponíveis: CIF e CDO. O comando CIF apresenta a seguinte forma: CIF { guard1; comunicação1 = lista de comandos1; [] guard2; comunicação2 = lista de comandos2; [] .... } Para cada caminho do comando CIF, os respectivos guards são verificados. Essa verificação é feita concorrentemente, ou seja, é irrelevante a ordem dos guards. Caso um ou mais guards sejam verdadeiros, os respectivos comandos de comunicação são iniciados. Caso nenhum comando de comunicação esteja pronto, todo o comando CIF irá bloquear até que uma comunicação esteja pronta. Caso mais que uma comunicação esteja pronta, a escolha de uma é feita de maneira não−determinística. Uma vez que a comunicação é completada, a lista de comandos associada é executada e o comando CIF é encerrado. O comando CIF é ignorado quando todos os guards forem falsos. O comando CDO é similar ao comando CIF. Entretanto, ao acabar a execução de uma das listas de comandos, o comando CDO é reiniciado. Esse comando é encerrado apenas quando todos os guards forem falsos. A implementação do MoC CSP no ambiente Ptolemy apresenta alguns métodos adicionais para implementar os comandos CIF e CDO. A figura 2.13 ilustra o comando CDO. 1− boolean continueCDO = true; 2− 3− while(continueCDO) { 4− 5− ConditionalBranch [] branches = new ConditionalBranch[3]; 6− 7− branches[0] = new ConditionalReceive(true, input, 0, 0); 8− branches[1] = new ConditionalReceive(true, input, 0, 1); 9− 10− token = new Token(); 11− branches[2] = new ConditionalSend(true, output, 0, 2, token); 12− 13− int result = chooseBranch(branches); 14− 15− if(result == 0) { 16− .... 17− Token t = branches[0].getToken(); 18− .... 19− } 20− else 21− if(result == 1) { 22− .... 23− Token t = branches[1].getToken(); 24− .... 25− } 26− else 27− if(result == 2) { 28− .... 29− } 30− else 31− if(result == −1) { 32− continueCDO = false; 33− } 34− }
  34. 34. 19 Figura 2.13 − O comando CDO no ambiente Ptolemy. A primeira tarefa é a criação dos diferentes caminhos do comando utilizando os objetos ConditionalReceive e ConditionalSend. Isso é feito da linha 5 à linha 11. No exemplo da figura 2.13, dois caminhos possuem comandos de comunicação para recepção de dados (linha 7 e 8) e um caminho é para envio de um dado (linha 11). O primeiro parâmetro dos construtores é o guard do comando, que neste exemplo é sempre verdadeiro. O quarto parâmetro é um valor inteiro único associado ao caminho em questão. A segunda tarefa é a escolha de um dos caminhos, utilizando o método chooseBranch(). Esse método irá retornar o número inteiro associado com o caminho escolhido. Finalmente, a lista de comandos para o caminho ativado é executada (linhas 15 à 33). Embora originalmente esse modelo não apresente uma noção de tempo, a implementação no ambiente Ptolemy introduziu essa característica. A exemplo do MoC DE, esse MoC também utiliza o tempo centralizado. Cada processo (ator) pode se suspender por uma duração de tempo determinada. Quando esse instante for alcançado, o escalonador ativa novamente o processo. O tempo é avançado quando todos os processos se suspenderam ou quando todos os processos estão bloqueados devido ao rendezvous e pelo menos um processo se suspendeu. Nestas situações, o tempo atual é avançado o suficiente para ativar algum processo que se suspendeu. 2.3.4 Synchronous Data Flow O modelo computacional Synchronous Data Flow (SDF) [LEE87a][LEE87b pertence à classe dos modelos data flow [DAV82][DEN80][KAR66]. O modelo data flow foi inicialmente desenvolvido para descrever e analisar programas paralelos. Nesse modelo, o sistema é abstraído por um grafo onde os nós são atores e os arcos indicam dependência de dados entre os atores. Em cada arco do grafo existe uma fila unidirecional utilizada para a troca de dados. É introduzido o conceito de ativamento de um ator (nó): um nó executa apenas quando todos os dados necessários estiverem disponíveis (o ator está pronto), e sua execução é atômica. Não existe o conceito de fluxo de controle em grafos data flow. No modelo SDF, além de respeitar a semântica data flow, deve ser especificado, para cada ator, quantos tokens são consumidos (no caso de um porto de entrada) ou produzidos (no caso de um porto de saída) para todos os seus portos. Esses valores (também chamados de taxas de amostragem) são fixos e conhecidos em tempo de compilação. Um grafo SDF possui um escalonamento (seqüencial ou paralelo) estático, ou seja, antes da execução é determinado quantas vezes cada ator deve ser ativado e qual é a ordem de ativamento. A figura 2.14 apresenta dois grafos SDF. Descreveremos o modelo SDF mais formalmente seguindo [LEE87b]. Iremos considerar o caso de escalonamento seqüencial. O caso paralelo está descrito em [LEE87a]. Figura 2.14 − Dois grafos SDF. Os números próximos aos nós são as taxas de amostragem. Um grafo SDF pode ser representado por uma matriz de incidência: as linhas representam os arcos e as colunas os nós. Cada posição da matriz é uma taxa de amostragem: positiva quando o ator produz o token na respectiva conexão, negativa quando ele consome. Essa matriz é denominada de matriz de topologia. As matrizes de topologia para os grafos da figura 2.14 (a) e (b) são respectivamente: 1 2 3 1 2 3 1 2 11 1 1 1 2 3 1 2 3 1 2 21 1 1 (a) (b) 1 −1 0 2 0 −1 0 1 −1 1 −1 0 2 0 −1 0 2 −1 (a) (b) Γ Γa b = =
  35. 35. 20 Durante a execução, a quantidade de dados em cada fila de comunicação irá variar. Em um determinado momento n, a quantidade de dados em cada fila é dada por um vetor coluna b(n). Para um escalonamento seqüencial, o vetor coluna v(n) indica qual ator é ativado em um instante n. Podemos descrever a variação de dados em cada fila pela equação b(n + 1) = b(n) + Γv(n). O valor do vetor b quando n = 0 indica em quais conexões existem dados antes do início da execução. Para se determinar um escalonamento de um grafo SDF, é necessário verificar se a matriz de topologia é consistente, ou seja, se as taxas de amostragem especificadas são válidas. Foi demonstrado que o rank da matriz de topologia, igual ao número de nós menos um, é uma condição necessária para a consistência. Por exemplo, o rank da matriz Γa é igual a três, enquanto que o rank da matriz Γb é igual à dois. Dessa forma, o grafo da figura 2.14 (a) é inválido e o da figura (b) é válido. Quando a matriz de topologia for válida, existe um vetor coluna q que satisfaz: Γq = 0. Para a matriz Γb, q = J[1 1 2]T , para qualquer J positivo. O vetor q determina quantas vezes cada nó deve ser ativado para a obtenção de um escalonamento periódico, ou seja, um escalonamento que quando completado, faz com que o valor do vetor b permaneça inalterado. Dessa forma, o grafo SDF pode ser executado infinitamente com capacidade limitada e conhecida de memória (filas). Mesmo quando a matriz de topologia é consistente, é possível que a especificação do grafo seja inválida. Isso ocorre quando existirem ciclos no grafo sem a quantidade adequada de dados no momento inicial da execução. A figura 2.15 ilustra essa situação. Figura 2.15 − Dois grafos SDF inválidos mas com matrizes consistentes. O losango da figura 2.15 (b) representa um ator de atraso, ou seja, um ator que no instante n envia o token recebido no instante n − 1. Para isso, esse ator produz tokens antes do início da execução (a entrada no vetor b com n = 0 para o porto de saída desse ator é maior que zero). Ambos os grafos da figura 2.15 não possuem condições iniciais válidas: a grafo da figura (a) não possui nenhum atraso, o da figura (b) apresenta um atraso de apenas um token, o que é insuficiente. A figura 2.16 apresenta a implementação de um ator de atraso no ambiente Ptolemy. 1− public class Delay extends Transformer { 2− public Delay(TypedCompositeActor container, String name) 3− throws IllegalActionException, NameDuplicationException { 4− 5− super(container, name); 6− new Parameter(output, TokenInitProduction, 7− new IntToken(1)); 8− 9− output.setTypeAtLeast(input); 10− } 11− 12− public void fire() throws IllegalActionException { 1 1 1 1 1 2 1 2 D (a) (b)
  36. 36. 21 13− Token message = input.get(0); 14− output.broadcast(message); 15− } 16− 17− public void initialize() throws IllegalActionException { 18− output.broadcast(new Token()); 19− } 20− } Figura 2.16 − O ator Delay no MoC SDF. A linha 6 modifica o parâmetro TokenInitProduction que especifica a quantidade de tokens a serem produzidos antes do início da execução. Outra forma de fazer tal especificação é através do método setTokenInitProduction() da classe SDFIOPort. Métodos similares existem para especificar a produção e consumo de tokens a cada ativamento do ator. Quando o grafo SDF for consistente e com a quantidade necessária de atrasos, o seguinte algoritmo pode ser usado para a obtenção de um escalonamento seqüencial8 : 1. encontre o menor vetor q; 2. obtenha uma lista L de todos os atores da especificação; 3. percorra a lista L e para cada ator pronto, escalone−o; 4. caso cada ator α tenha sido escalonado qα vezes, FIM; 5. caso nenhum ator da lista L esteja pronto, ocorreu um deadlock (a especificação é inválida); 6. do contrário, vá para 3. O algoritmo encontra um escalonamento simulando a execução do sistema. Para encontrar o vetor q do passo 1, o seguinte método é utilizado: 1. escolha aleatoriamente um ator e assuma que ele é ativado uma única vez, ou seja, qa = 1; 2. para um ator B adjacente à A, calcule o valor de qb = (qa . pa)/cb, onde pa é a quantidade de tokens produzidos pelo ator A na conexão e cb a quantidade de tokens consumidos por B. O valor obtido pode ser fracional mas sempre racional; 3. repita o passo 2 recursivamente para um ator adjacente a B; 4. uma vez obtidos todos os valores de q, encontre o menor denominador comum desses valores a fim de torná−los inteiros. É fácil perceber que o método descrito irá encontrar o vetor q em tempo linear ao número de nós e arcos do grafo. No modelo SDF, não é necessário implementar explicitamente filas para a comunicação entre os atores. O fato desse MoC ser escalonado estaticamente permite associar uma posição de memória específica para cada dado a ser consumido ou escrito por um ator, em cada ativamento do mesmo. Entretanto, a semântica de comunicação por filas é respeitada. O modelo SDF não apresenta uma noção de tempo. 2.3.5 Dynamic Data Flow Assim como o modelo SDF, o modelo computacional Dynamic Data Flow [LEE95] (DDF) respeita a semântica data flow, e também não possui uma noção de tempo. Ao contrário do modelo SDF9 , não existe a necessidade de especificar as taxas de consumo e produção de tokens de cada porto, embora isso seja permitido. Esses valores podem variar durante a execução. Dois exemplos de atores DDF são mostrados na figura 2.17. 8 Outros algoritmos para escalonamento seqüencial de grafos SDF estão descritos em [BHA94]. 9 O modelo SDF é um subconjunto do modelo DDF.
  37. 37. 22 Figura 2.17 − Os atores Switch e Select no modelo DDF. O ator Switch consome um token do porto de dados e baseado no valor do token do porto de controle, envia o token de dado para um dos dois portos de saída. Dessa forma, apenas um porto de saída produzirá dados a cada ativamento do ator Switch. O ator Select consome um token de dados, baseado no valor do token de controle. Podemos observar que no caso do ator Select, mais de uma condição de presença de dados pode ativá−lo. Esse fato é conhecido como as regras de ativamento de um ator (firing rules). No caso do modelo SDF, só existe uma regra para cada ator. No caso do modelo DDF, várias regras podem ser especificadas para um mesmo ator. Por exemplo, o ator Select possui duas regras: R1 = {[*], ¤ , [0]} R2 = {¤ , [*], [1]} A primeira posição das regras representa a entrada Dado1, a segunda a entrada Dado2 e a terceira a entrada Controle. O símbolo ¤ indica que a regra pode ser satisfeita independentemente da respectiva entrada. O símbolo * indica que é necessário um token, independente de seu valor. Os números dentro de colchetes indicam o valor necessário do token. O modelo DDF é determinístico (assim como o SDF), isto é, dado um mesmo conjunto de entradas, as saídas sempre terão o mesmo valor, independentemente da ordem de ativamento dos atores. Entretanto, para que uma especificação utilizando o MoC DDF seja válida (determinística), todos os atores devem implementar funções contínuas. Isso pode ser obtido utilizando regras de ativamento seqüenciais. Um algoritmo para determinar quando as regras de ativamento são seqüenciais é: 1. encontre um porto de entrada j tal que [*] ¡ Ri,j para todas as regras i = 1, ..., N, isto é, um porto de entrada tal que todas as regras necessitem de pelo menos um token neste porto. Caso nenhum porto seja encontrada, as regras não são seqüenciais; 2. para o porto j encontrado no passo 1, divida as regras em subconjuntos de acordo com o primeiro valor de Ri,j para todas as regras. Caso Ri,j = [*, ....], então Ri,j deve aparecer em todos os subconjuntos; 3. remova o primeiro elemento de Ri,j para todas as regras i; 4. caso todos os subconjuntos sejam vazios, então as regras de ativamento são seqüencias. Caso contrário, repita os passos para cada subconjunto não vazio. Para as regras do ator Select, o primeiro passo irá identificar j = 3. Dois subconjuntos são formados, um para cada regra. As duas novas regras são R1 = {[*], ¤¤ } e R2 = {¤ , [*], ¤ }. O procedimento encerra trivialmente para cada um dos subconjuntos. No ambiente Ptolemy, as regras de ativamento de um ator não são enumeradas explicitamente. Para garantir a validade do ator, a semântica de leitura bloqueante é utilizada, ou seja, ao tentar consumir um ou mais tokens, o ator fica bloqueado enquanto os dados não estiverem disponíveis. Note que o algoritmo para determinar se um conjunto de regras é seqüencial pode ser implementado através do uso de leitura bloqueante. A figura 2.18 exemplifica essa situação através do código do ator Select. 1− public class Select extends DDFAtomicActor { 2− 3− public DDFIOPort control; 4− public DDFIOPort data1; 5− public DDFIOPort data2; Switch Select Dado Controle Controle Dado1 Dado2 Saída1 Saída2 Saída
  38. 38. 23 6− public DDFIOPort output; 7− 8− public Select(TypedCompositeActor container, String name) throws 9− IllegalActionException, NameDuplicationException { 10− 11− super(container, name); 12− 13− control = new DDFIOPort(this, control, true, false); 14− control.setTokenConsumptionRate(1); 15− control.setTypeEquals(BaseType.DOUBLE); 16− 17− data1 = new DDFIOPort(this, data1, true, false); 18− data1.setTokenConsumptionRate(0); 19− 20− data2 = new DDFIOPort(this, data2, true, false); 21− data2.setTokenConsumptionRate(0); 22− 23− output = new DDFIOPort(this, output, false, true); 24− output.setTokenProductionRate(1); 25− } 26− 27− public void fire() throws IllegalActionException { 28− int i; 29− 30− if(_readyToGo == false) { 31− DoubleToken t = (DoubleToken) control.get(0); 32− _ctrl = (double) t.doubleValue(); 33− } 34− 35− if(_ctrl == 0.0) { 36− if(data1.hasToken(0)) { 37− _readyToGo = false; 38− waitFor(control, 1); 39− output.broadcast(data1.get(0)); 40− } 41− else { 42− _readyToGo = true; 43− waitFor(data1, 1); 44− } 45− } 46− else { 47− if(data2.hasToken(0)) { 48− _readyToGo = false; 49− waitFor(control, 1); 50− output.broadcast(data2.get(0)); 51− } 52− else { 53− _readyToGo = true; 54− waitFor(data2, 1); 55− } 56− } 57− } 60− 61− public void initialize() throws IllegalActionException { 62− super.initialize(); 63− 64− _readyToGo = false; 65− waitFor(control, 1); 66− _ctrl = 0.0; 67− } 68− 69− private boolean _readyToGo; 70− private double _ctrl; 71− } Figura 2.18 − Código do ator Select no MoC DDF. As linhas 18 e 21 indicam que os portos de entrada data1 e data2 não possuem taxas de consumo constante. A leitura bloqueante é implementada através da utilização do método waitFor(). O primeiro parâmetro desse método é o porto de entrada e o segundo parâmetro indica quantos tokens devem ser lidos para o ativamento. Inicialmente, o ator Select deve ler o token de controle (linhas 65, 38 e 49) para em seguida ler o dado. Caso esse não esteja disponível, a leitura bloqueante é utilizada novamente para os portos de dados (linhas 43 e 54). Note a utilização de uma variável interna (_readyToGo) para indicar o estado em que o ator se encontra e assim determinar de qual porto o próximo token deve ser consumido.
  39. 39. 24 Ao contrário do modelo SDF, o escalonador do MoC DDF não é estático. Dois tipos de escalonadores dinâmicos existem [PAR95]: data driven e demand driven. Escalonadores tipo data driven ativam um ator assim que uma de suas regras de ativamento seja válida. Já escalonadores tipo demand driven ativam um ator baseado na demanda de tokens de um ator sucessor. O ambiente Ptolemy utiliza um escalonador tipo data driven, classificando os atores prontos para serem ativados como deferrable ou não. Um ator é deferrable quando alguns de seus sucessores já possuem tokens suficientes na conexão com o ator. Um ator deferrable só é ativado quando não existirem atores classificados como não deferrable. Nesse caso, um dos atores deferrable é escolhido aleatoriamente para ser ativado. A classificação de ator deferrable visa evitar o acúmulo desnecessário de tokens em uma fila. Outra característica do MoC DDF é que, ao contrário do MoC SDF, não é possível determinar a quantidade necessária de armazenamento de cada fila de comunicação. É possível que uma execução venha a ser prematuramente interrompida devido ao estouro de espaço de memória. 2.3.6 Kahn Process Networks Assim como o MoC CSP, uma especificação executável utilizando o modelo computacional Kahn Process Networks [KA74][KAH77][GOE98][PAR95] é composta por uma rede de processos, onde cada ator da especificação é associado à um processo. Tal como nos modelos data flow, cada conexão entre atores contém uma fila. O modelo PN é determinístico quando cada processo implementa uma função contínua. Assim como no MoC DDF, isso é implementado através de leitura bloqueante: quando um ator tenta consumir um token de uma fila vazia, o respectivo processo é bloqueado, sendo reativado quando o token estiver disponível. O MoC PN não permite o teste da presença de um token, pois isso tornaria o modelo não−determinístico. Também não é permitido que um ator espere por tokens em mais de um porto ao mesmo tempo. Tal como no MoC DDF, não é possível determinar a capacidade necessária de cada fila. A solução adotada no ambiente Ptolemy utiliza a escrita bloqueante, ou seja, quando um ator tenta produzir um token e a respectiva fila está cheia, o processo do ator é bloqueado. Quando houver espaço na fila, o processo é reativado. É possível que uma execução venha a entrar em deadlock, ou seja, quando todos os atores estiverem bloqueados. Quando não existe nenhum ator bloqueado devido à situação de filas cheias, diz− se que o deadlock é real. Nessa situação a execução chegou ao fim. Caso contrário, temos um deadlock artificial. Neste caso, o ambiente Ptolemy determina uma fila cheia e aumenta seu tamanho, reativando o respectivo processo e prosseguindo com a execução. A implementação desse MoC no ambiente Ptolemy possui uma noção de tempo, similar ao do modelo CSP, ou seja, um processo pode se suspender até um determinado instante de tempo. 2.4 Outros Modelos Computacionais Vários outros modelos computacionais foram desenvolvidos, além dos seis modelos computacionais que utilizamos nesse trabalho. O próprio ambiente Ptolemy implementa outros três modelos. Enumeramos alguns modelos importantes e descritos na literatura:   Cyclo−Static Data Flow [BIL96]: modelo data flow que estende o MoC SDF permitindo que um ator tenha mais que uma regra de ativamento. Entretanto, as regras devem apresentar taxas de consumo e produção constantes e a ordem de utilização de cada regra é definida antes da execução. Esse modelo também apresenta um escalonamento estático;   Boolean Data Flow [BUC93]: modelo data flow que estende o MoC SDF permitindo a variação das taxas de consumo e produção durante a execução. Entretanto, diferentemente do MoC DDF, essa variação deve sempre estar condicionada à um valor booleano obtido de outro porto (por exemplo, os atores da figura 2.17). Em alguns casos, é possível encontrar um escalonamento estático;
  40. 40. 25   Máquinas de Estado Finito [GAJ00]: modelo computacional clássico baseado em autômatos finitos;   Redes de Petri [PET81]: modelo de estados explícitos onde a especificação é composta por dois tipos de elementos: place e transição. Cada place pode conter um elemento denominado de token. Um place pode ser conectado à uma transição (place de entrada da transição) e uma transição pode ser conectada à um place (place de saída da transição). Quando todos os place de entrada de uma transição tiverem pelo menos um token, diz−se que a transição está pronta para ser ativada. O ativamento consiste em remover um token de todos os place de entrada e adicionar um token à todos os places de saída. A concorrência é possível pois mais de uma transição pode estar pronta para ser ativada em um mesmo instante. Neste caso, a escolha é feita de forma não determinística;   StateChars [HAR87]: modelo que adicionada à máquinas de estado finito o conceito de hierarquia e concorrência. A hierarquia é representada através de estados que contenham outras máquinas de estado. Quando ocorre a transição para um estado hierárquico, a máquina de estado interna é ativada. A concorrência é modelada através da possibilidade de que mais de um estado estar ativado simultaneamente. Nesse modelo, é permitido transições de estados pertencentes à diferentes níveis de hierarquia;   *Charts [GIR99]: modelo implementado no ambiente Ptolemy que adiciona os conceitos de hierarquia e concorrência às máquinas de estados finitos. Diferentemente do modelos StateCharts, o modelo *Charts não define estados concorrentes. A concorrência é obtida quando vários atores Composite, que implementam subsistemas em *Charts, são incluídos em uma topologia governada por um modelo com concorrência. Não é permitido transições entre estados de diferentes hierarquias;   Codesign Finite State Machine [LAV00]: modelo baseado em uma rede de máquinas de estado. A comunicação é feita através de broadcast de sinais: uma máquina produz um evento em um sinal e todas as outras máquinas que dependem desse sinal podem obter o novo evento. A hipótese de sincronismo é assumida para todas as máquinas de estado mas não aplicada à interação das máquinas, ou seja, uma vez que um novo evento é produzido, a resposta de outra máquina à esse novo evento não é infinitamente rápida. Dessa forma, é possível que eventos não sejam capturados por máquinas com reação lenta, uma vez que não existe o armazenamento de eventos;   Control−Data Flow Graph [MIC94]: modelo utilizado para representar um algoritmo seqüencial através de um grafo direcionado. Existem dois tipos básicos de nós: nós de controle e basic blocks. Um nó tipo basic block contém uma seqüência de comandos. Nós de controle determinam os diferentes caminhos possíveis para o fluxo de controle;   Continuous Time [LIU98]: modelo implementado no ambiente Ptolemy fundamentado na utilização de equações diferenciais para representar um sistema. Esse modelo possui uma noção de tempo contínuo. O escalonador desse modelo é composto por um algoritmo que obtenha resultados aproximados para o sistema de equações em alguns instantes de tempo. Esse modelo é mais apropriado para representar sistemas analógicos e mecânicos;   Distributed Discrete Event [DAV99]: modelo implementado no ambiente Ptolemy que procura solucionar os problemas relacionados ao emprego de uma noção global de tempo, tal como no modelo DE. O modelo mantém uma noção local de tempo em cada conexão entre atores. Cada ator é associado à um processo e este pode avançar seu valor de tempo para o mínimo entre os valores de suas conexões de entrada.
  41. 41. 26 2.5 A Ferramenta de Depuração/Profile Conforme foi ilustrado no item 2.2, uma especificação executável no ambiente Ptolemy é composta por classes na linguagem Java, escritas pelo usuário, e por classes disponíveis pelo ambiente. Essas classes passam por um processo de compilação e o código resultante pode ser executado. A análise do comportamento da execução e dos resultados obtidos fica a cargo do usuário, isto é, o usuário deve adicionar trechos de códigos à especificação para coletar e apresentar informações relevantes à execução. Até o presente momento, o ambiente Ptolemy provê auxilio para esta tarefa apenas através de atores que utilizam o aplicativo PtPlot. Este aplicativo é capaz de ilustrar dados através de vários tipos de gráficos bidimensionais. Uma alternativa disponível para a análise da execução seria o uso de uma ferramenta de depuração para a linguagem Java. Essa solução é recomendável para encontrar erros no código fonte de cada ator, uma vez que cada comando do código pode ser analisado. Entretanto, esse tipo de ferramenta não é adequada para a análise de características mais genéricas referentes à interação entre diferentes atores sob um modelo computacional. Essas informações podem ser úteis para o usuário entender mais detalhadamente os resultados da execução da especificação e para encontrar erros lógicos não associados ao código de um ator isoladamente. Sob a luz do estudo apresentado nessa dissertação, uma ferramenta para a análise da execução de uma especificação torna−se útil, pois tal ferramenta auxilia identificar as diferenças encontradas ao utilizar modelos computacionais distintos na representação de uma mesma primitiva computacional. Dessa forma, uma ferramenta denominada de PTII Analyzer foi desenvolvida com esse objetivo. Sua principal função é reproduzir uma execução, ilustrando a troca de tokens entre diferentes atores. Informações estatísticas também podem ser extraídas a partir dos dados coletados. 2.5.1 Dados coletados A ferramenta desenvolvida baseia−se em dados coletados durante a execução de uma especificação. Para tal, acrescentamos trechos de código em classes específicas do ambiente Ptolemy. Dois tipos de conjunto de dados são armazenados: a produção ou o consumo de um token e a mudança de estado de um ator. Para cada evento de consumo ou produção de um token, armazenamos o seguinte conjunto de informações:   tipo do evento: consumo ou produção;   identificador do token: um valor inteiro único para cada token durante a execução;   ator de origem;   porto de origem;   ator de destino;   porto de destino;   valor do tempo no momento do evento;   instante. O instante é um valor inteiro único para cada conjunto de informações e utilizado a fim de ordenar os dados coletados permitindo ilustrar a reprodução da execução. O segundo tipo de conjunto de dados armazenado é referente a mudança de estado de um ator. Definimos três possíveis estados: bloqueado, pronto ou executando. Em alguns MoCs, subdividimos o estado bloqueado em bloqueado no consumo ou na produção de um token. Quando ocorre uma mudança de estado, armazenamos o seguinte conjunto de dados:   ator;   novo estado;   valor do tempo no momento do evento;   instante.

×