Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
Próxima revisão | Revisão anterior | ||
software:simulacao [2008/05/09 17:18] – external edit 127.0.0.1 | software:simulacao [2020/08/18 22:48] (atual) – edição externa 127.0.0.1 | ||
---|---|---|---|
Linha 1: | Linha 1: | ||
+ | ====== Simpatica ====== | ||
+ | |||
+ | [ [[software: | ||
+ | |||
+ | '' | ||
+ | |||
+ | * Escrita em linguagem C ANSI. | ||
+ | * Estrutura interna simples, de fácil compreensão e amplamente comentada, permitindo seu uso didático. | ||
+ | * Extensivamente testada em ambientes Linux 32 e 64 bits. | ||
+ | * Baseada no paradigma atores/ | ||
+ | * Concebida visando um baixo consumo de memória, o que permite criar simulações com dezenas de milhares de entidades ativas (suportou 150.000 tarefas simultâneas em um computador com 4 GB de memória). | ||
+ | * Excelente desempenho, por usar //threads// leves implementadas pela própria biblioteca, que não dependem do escalonador do sistema operacional. | ||
+ | * A fila do escalonador é implementada usando um //heap// binário, o que permite alcançar um bom desempenho em simulações de larga escala. | ||
+ | * Software aberto de livre acesso (licença GNU). | ||
+ | |||
+ | A biblioteca '' | ||
+ | |||
+ | * **Tarefa**: uma tarefa é uma entidade ativa, que tem seu comportamento definido por uma função, da mesma forma que uma thread (threads de usuário são usadas para implementar as tarefas). Cada tarefa tem um identificador único no sistema. As tarefas podem produzir e consumir mensagens, que são transferidas através de filas. | ||
+ | * **Fila**: é um depósito de mensagens ordenado por data de chegada (ordem FIFO). Tarefas podem depositar mensagens nas filas ou retirar mensagens delas. Filas e tarefas são independentes: | ||
+ | * **Mensagem**: | ||
+ | |||
+ | {{ software: | ||
+ | |||
+ | ===== Arquivos ===== | ||
+ | |||
+ | * {{software: | ||
+ | |||
+ | ===== Interface ===== | ||
+ | |||
+ | Esta biblioteca oferece um conjunto de funções em C ANSI para a construção de modelos de simulação. Por convenção, | ||
+ | |||
+ | <code c> | ||
+ | void init_simulation (int maxTasks, int maxQueues) | ||
+ | </ | ||
+ | |||
+ | Inicializa as estruturas internas necessárias para cada simulação. Esta função deve ser chamada somente uma vez, sempre no inicio do programa principal (função '' | ||
+ | |||
+ | <code c> | ||
+ | void run_simulation (double maxTime) | ||
+ | </ | ||
+ | |||
+ | Executa a simulação até que o relógio de simulação atinja o valor '' | ||
+ | |||
+ | <code c> | ||
+ | ... // inicializa e cria tarefas | ||
+ | |||
+ | run_simulation (1000) ; // executa a simulação no intervalo t = [0 - 1000) | ||
+ | |||
+ | ... // trata resultados parciais | ||
+ | |||
+ | run_simulation (2000) ; // continua a simulação no intervalo t = [1000 - 2000) | ||
+ | |||
+ | ... // trata resultados parciais | ||
+ | </ | ||
+ | |||
+ | <code c> | ||
+ | void kill_simulation () | ||
+ | </ | ||
+ | |||
+ | Encerra uma simulação, | ||
+ | |||
+ | <code c> | ||
+ | void trace_interval (double startTime, double stopTime) | ||
+ | </ | ||
+ | |||
+ | Gera mensagens de //tracing// quando o relógio de simulação estiver dentro do intervalo ['' | ||
+ | |||
+ | **ATENÇÃO**: | ||
+ | |||
+ | <code c> | ||
+ | uint task_create (void (*taskBody)(void *), | ||
+ | void* startArg, | ||
+ | int stackPages) | ||
+ | </ | ||
+ | |||
+ | Cria uma nova tarefa. O parâmetro '' | ||
+ | |||
+ | É importante observar que pilhas muito pequenas podem levar a erros de acesso à memória ou comportamento errático do modelo, enquanto pilhas muito grandes consomem mais memória e assim limitam o número máximo de tarefas que o modelo pode criar. O tamanho da pilha deve ser estimado em função do comportamento da tarefa: quantidade de variáveis locais, funções chamadas pela tarefa, etc. Modelos simples geralmente funcionam bem com pilhas com 1 a 3 páginas de memória, mas isso deve ser estimado caso a caso. | ||
+ | |||
+ | Obs: a função '' | ||
+ | |||
+ | <code c> | ||
+ | void task_exit () | ||
+ | </ | ||
+ | |||
+ | Encerra a tarefa corrente (em execução), | ||
+ | |||
+ | <code c> | ||
+ | void task_destroy (int task_id) | ||
+ | </ | ||
+ | |||
+ | Destrói a tarefa indicada como parâmetro, liberando os recursos utilizados por ela. | ||
+ | |||
+ | <code c> | ||
+ | void task_sleep (double t) | ||
+ | </ | ||
+ | |||
+ | A tarefa corrente vai dormir durante '' | ||
+ | |||
+ | <code c> | ||
+ | void task_passivate () | ||
+ | </ | ||
+ | |||
+ | A tarefa corrente vai dormir indefinidamente, | ||
+ | |||
+ | <code c> | ||
+ | void task_activate (int task_id, double waitTime) | ||
+ | </ | ||
+ | |||
+ | Acorda a tarefa indicada por '' | ||
+ | |||
+ | <code c> | ||
+ | int task_id () | ||
+ | </ | ||
+ | |||
+ | Retorna o ID (identificador único) da tarefa corrente, que é um inteiro positivo (1, 2, 3, ...). Se chamada fora de uma tarefa (por exemplo, no programa principal ou no escalonador), | ||
+ | |||
+ | <code c> | ||
+ | double time_now () | ||
+ | </ | ||
+ | |||
+ | Informa o valor atual do relógio simulado. | ||
+ | |||
+ | <code c> | ||
+ | int queue_create (int capacity, int policy) | ||
+ | </ | ||
+ | |||
+ | Cria uma nova fila com a capacidade (número máximo de mensagens) e política de ordenamento indicadas. Na versão atual, ambos os parâmetros são ignorados: todas as filas são ilimitadas e têm comportamento FIFO. | ||
+ | |||
+ | <code c> | ||
+ | int queue_destroy (int queue_id) | ||
+ | </ | ||
+ | |||
+ | Destrói a fila indicada, eliminando todas as mensagens nela contidas e as estruturas de dados que a representam. | ||
+ | |||
+ | <code c> | ||
+ | void queue_stats (uint queue_id, | ||
+ | uint *size, | ||
+ | uint *max, | ||
+ | double *mean, | ||
+ | double *var, | ||
+ | ulong *put, | ||
+ | ulong *got) | ||
+ | </ | ||
+ | |||
+ | Fornece informações estatísticas relativas à fila indicada, computadas a partir do início da simulação: | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Para cada informação, | ||
+ | |||
+ | <code c> | ||
+ | queue_stats (q1, &size, 0, 0, 0, 0, 0) ; | ||
+ | </ | ||
+ | |||
+ | <code c> | ||
+ | void* msg_create (short size) | ||
+ | </ | ||
+ | |||
+ | Cria uma nova mensagem com tamanho '' | ||
+ | |||
+ | Retorna um ponteiro para a mensagem criada. | ||
+ | |||
+ | <code c> | ||
+ | void msg_destroy (void *msg) | ||
+ | </ | ||
+ | |||
+ | Destrói a mensagem indicada. Todas as mensagens devem ser destruidas ao encerrar sua vida útil, para liberar a memória utilizada e assim permitir simulações maiores e/ou mais longas, sem esgotar a memória do computador. | ||
+ | |||
+ | <code c> | ||
+ | void msg_put (int queue_id, void* msg) | ||
+ | </ | ||
+ | |||
+ | Coloca a mensagem indicada no final da fila indicada. | ||
+ | |||
+ | <code c> | ||
+ | void* msg_get (void *msg) | ||
+ | </ | ||
+ | |||
+ | Retira a mensagem indicada da fila onde ela se encontra, retornando um ponteiro para a mensagem. | ||
+ | |||
+ | <code c> | ||
+ | void* msg_wait (int queue_id, double timeOut) | ||
+ | </ | ||
+ | |||
+ | Espera uma mensagem na fila indicada. A tarefa fica suspensa até receber uma mensagem ou esgotar o tempo de espera '' | ||
+ | |||
+ | <code c> | ||
+ | void* msg_first (int queue_id) | ||
+ | void* msg_last | ||
+ | void* msg_prev | ||
+ | void* msg_next | ||
+ | </ | ||
+ | |||
+ | Permitem navegar em uma fila de mensagens. Retornam um ponteiro para uma mensagem na fila ou NULL, caso não exista a mensagem solicitada. | ||
+ | |||
+ | <code c> | ||
+ | void msg_attr (void *msg, | ||
+ | long *id, | ||
+ | | ||
+ | | ||
+ | long *creator, | ||
+ | long *sender, | ||
+ | int *queue) | ||
+ | </ | ||
+ | |||
+ | Informa os seguintes atributos da mensagem indicada: | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Para cada atributo, deve ser informado o endereço da variável que irá recebê-lo, ou NULL para ignorá-lo (vide chamada '' | ||
+ | |||
+ | ===== Forma de uso ===== | ||
+ | |||
+ | O uso desta biblioteca é bastante simples: basta escrever um programa C, usando as funções da biblioteca para definir o modelo e os parâmetros da simulação, | ||
+ | |||
+ | < | ||
+ | $ cc simpatica.c modelo.c | ||
+ | $ a.out | ||
+ | </ | ||
+ | |||
+ | O arquivo '' | ||
+ | |||
+ | ===== Exemplo de simulação ===== | ||
+ | |||
+ | Eis abaixo um exemplo de simulação no qual 1000 tarefas '' | ||
+ | |||
+ | <code c modelo.c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | int queue ; | ||
+ | |||
+ | // variaveis para o calculo do tempo medio entre geracao e consumo das msgs | ||
+ | long num_msgs = 0 ; | ||
+ | double soma_tempos = 0.0 ; | ||
+ | |||
+ | // mensagens sao structs com conteudo definido pelo programador | ||
+ | typedef struct msg_t | ||
+ | { | ||
+ | int value ; | ||
+ | } msg_t ; | ||
+ | |||
+ | // corpo das tarefas " | ||
+ | void sourceBody (void *arg) | ||
+ | { | ||
+ | msg_t *msg ; | ||
+ | | ||
+ | for (;;) | ||
+ | { | ||
+ | // cria uma nova mensagem | ||
+ | msg = (msg_t*) msg_create (sizeof (msg_t)) ; | ||
+ | |||
+ | // preenche a mensagem com um valor aleatorio | ||
+ | msg-> | ||
+ | |||
+ | // coloca a mensagem na fila " | ||
+ | msg_put (queue, msg) ; | ||
+ | |||
+ | // dorme durante um tempo aleatorio | ||
+ | task_sleep (15 + random() % 5) ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // corpo da tarefa " | ||
+ | void sinkBody (void *arg) | ||
+ | { | ||
+ | msg_t *msg ; | ||
+ | | ||
+ | | ||
+ | for (;;) | ||
+ | { | ||
+ | // espera uma mensagem na fila e a retira | ||
+ | msg = (msg_t*) msg_get (msg_wait (queue, INFINITY)) ; | ||
+ | |||
+ | // obtem a data de criacao da mensagem | ||
+ | msg_attr (msg, 0, & | ||
+ | |||
+ | // simula o tempo gasto no tratamento da mensagem | ||
+ | task_sleep (1) ; | ||
+ | |||
+ | // acumula tempos | ||
+ | soma_tempos += (time_now() - data_criacao) ; | ||
+ | num_msgs ++ ; | ||
+ | |||
+ | // destroi a mensagem recebida (libera recursos) | ||
+ | msg_destroy (msg) ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int i ; | ||
+ | | ||
+ | |||
+ | // prepara a simulacao para 1001 tarefas e uma fila | ||
+ | | ||
+ | | ||
+ | // cria 1000 tarefas " | ||
+ | for (i=0; i< 1000; i++) | ||
+ | | ||
+ | |||
+ | // cria uma tarefa " | ||
+ | | ||
+ | |||
+ | // cria uma fila " | ||
+ | queue = queue_create (0, 0) ; | ||
+ | |||
+ | // executa a simulacao ate 50000 segundos | ||
+ | | ||
+ | |||
+ | // imprime resultados obtidos | ||
+ | | ||
+ | | ||
+ | |||
+ | // imprime o tamanho medio da fila e seu desvio padrão | ||
+ | | ||
+ | | ||
+ | |||
+ | // libera os recursos da simulacao | ||
+ | | ||
+ | |||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | A compilação do modelo é feita através da seguinte linha de comando: | ||
+ | |||
+ | < | ||
+ | $ cc simpatica.c modelo.c | ||
+ | </ | ||
+ | |||
+ | A execução do modelo gera os seguintes resultados: | ||
+ | |||
+ | < | ||
+ | $ a.out | ||
+ | -- Simulation initialized, | ||
+ | -- Simulation in interval t=[0.000, 50000.000), 1001 tasks | ||
+ | -- Simulation time: 5000.000, | ||
+ | -- Simulation time: 10000.000, | ||
+ | -- Simulation time: 15000.000, | ||
+ | -- Simulation time: 20000.000, | ||
+ | -- Simulation time: 25000.000, | ||
+ | -- Simulation time: 30000.000, | ||
+ | -- Simulation time: 35000.000, | ||
+ | -- Simulation time: 40000.000, | ||
+ | -- Simulation time: 45000.000, | ||
+ | -- Simulation time: 50000.000, | ||
+ | -- Simulation completed in 6 seconds (mem: 246963Kb) | ||
+ | Tempo medio entre producao e consumo das mensagens: 24583.696 | ||
+ | Tamanho da fila: media 1445994.474, | ||
+ | -- Simulation killed (mem: 0Kb) | ||
+ | </ | ||
+ | |||
+ | No exemplo acima, as linhas que iniciam com "'' | ||
+ | |||
+ | ===== Opções de compilação ===== | ||
+ | |||
+ | Existem algumas opções de compilação que permitem ativar testes e mensagens adicionais. Essas opções são úteis para a depuração das funcionalidades e mecanismos internos da biblioteca em si, não tendo muita utilidade para a depuração dos modelos de simulação. | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | A forma de uso dessas opções é a seguinte: | ||
+ | |||
+ | < | ||
+ | $ cc -DQUIET -DNOTESTS simpatica.c modelo.c | ||
+ | </ | ||
+ | |||
+ | ===== Concorrência ===== | ||
+ | |||
+ | Em sistemas com tarefas executando simultaneamente, | ||
+ | |||
+ | Nesta biblioteca, uma tarefa em execução só perde o processador quando solicita uma operação que possa fazer avançar o tempo simulado, ou seja: '' | ||