análise de escalonador de processos de múltiplas filas
DESCRIPTION
Durante o percorrer do curso, estudamos na matéria de Sistemas Operacionais os Sistemas Operacionais em si e sua funcionalidades básicas, será apresentado neste documento uma explicação sobre escalonador (scheduler) e variáveis que fazem parte de sua implementação e execução. Também será apresentado apresentada a implementação de um escalonador básico, e os testes realizados em cada cenário no escalonador implementado.Este trabalho possui licensa Creative CommonsAtribuição-Uso Não-Comercial-Vedada a Citações de Obras Derivadas 3.0 Unported.- Você pode: copiar, distribuir e executar a obra.- sob as seguintes condições:-- Atribuição: Você deve dar crédito ao autor original, da forma especificada pelo autor ou licenciante.-- Uso Não-Comercial: Você não pode utilizar desta obra com finalidades comerciais-- Vedada a Criação de Obras Derivadas: Você não pode alterar, transformar ou criar outra obra com base nesta.- Para cada novo uso ou distribuição, você deve deixar claro para outros os termos da liçença desta obra.- Qualquer uma destas condições podem ser renunciadas, desde que Você obtenha permissão do autor.- Nothing in this license impais or restrict the author's moral right.- Qualquer direito de uso legítimo (ou "fair use") conhecido por lei, ou qualuqer outro direito protegido pela legislação local, não são em hipótese alguma afetados pelo disposto acima.- Este é um sumário para leigos da Licença judiciária (na Íntegra).TRANSCRIPT
PONTIFÍCIA UNIVERSIDADE CATÓLICA DE MINAS GERAIS Campus de Poços de Caldas
Curso de Graduação em Ciência da Computação
LABORATÓRIO DE SISTEMAS OPERACIONAIS
Escalonador
Dyego Henrique Melo Dias Professor: Dr. João Carlos de Moraes Morselli Junior
Poços de Caldas 11/06/2010
2
PONTIFÍCIA UNIVERSIDADE CATÓLICA DE MINAS GERAIS Campus de Poços de Caldas
Curso de Graduação em Ciência da Computação
LABORATÓRIO DE SISTEMAS OPERACIONAIS:
Escalonador
Trabalho apresentada à disciplina de Laboratório de Sistemas Operacionais, do Curso de Ciência da Computação como requisito parcial para obtenção do título de Bacharel em Ciência da Computação da Pontifícia Universidade Católica de Minas Gerais.
Dyego Henrique Melo Dias Professor: Dr. João Carlos de Moraes Morselli Junior
Poços de Caldas 11/06/201
3
Sumário U1.U UIntroduçãoU ................................................................................................................ 5
U2.U USistema OperacionalU ................................................................................................ 6
U2.1.U USystem CallsU ...................................................................................................... 6
U2.2.U UProcessosU ........................................................................................................... 6
U2.3.U UArquivosU ............................................................................................................ 7
U3.U UEscalonador de ProcessosU ........................................................................................ 8
U3.1.U UObjetivos do EscalonamentoU ............................................................................. 8
U3.2.U UAlgoritmos EscalonadoresU ................................................................................. 8
U3.2.1.U UFIFOU ........................................................................................................... 9
U3.2.2.U USJFU .............................................................................................................. 9
U3.2.3.U USRTU ............................................................................................................ 9
U3.2.4.U UAlgoritmo LoteriaU ...................................................................................... 9
U3.2.5.U UEscalonamento garantidoU ........................................................................... 9
U3.2.6.U URRU .............................................................................................................. 9
U3.2.7.U UMúltiplas FilasU ............................................................................................ 9
U4.U USimulaçãoU ............................................................................................................... 10
U5.U UFuncionamentoU ....................................................................................................... 11
U6.U UFILASU ..................................................................................................................... 12
U7.U USimulaçõesU ............................................................................................................. 13
U7.1.U USimulação 1U ..................................................................................................... 13
U7.2.U USimulação 2U ..................................................................................................... 14
U7.3.U USimulação 3U ..................................................................................................... 15
U7.4.U USimulação 4U ..................................................................................................... 16
U8.U UComparandoU ........................................................................................................... 17
U8.3.U UQuantidade total de starvation durante a simulação.U ....................................... 18
U8.4.U UConclusão das SimulaçõesU .............................................................................. 19
U9.U UOutras SimulaçõesU .................................................................................................. 20
U9.1.U USimulação 5U ..................................................................................................... 20
U9.2.U USimulação 6U ..................................................................................................... 21
U9.3.U USimulação 7U ..................................................................................................... 22
U9.4.U USimulação 8U ..................................................................................................... 23
U10.U UMédia de ThroughputU .......................................................................................... 24
U11.U UCOMPARAÇÃO DAS SIMULAÇÕES 6, 7, 8 e 9U ............................................ 27
U11.1.U UQuantidade total de processos criados durante a simulação.U ....................... 27
U11.2.U UQuantidade total de processos executados durante a simulação.U ................. 28
U11.3.U UQuantidade total de starvation durante a simulação.U ................................... 28
4
U13.U UCONCLUSÃO SIMULAÇÃO 2U ........................................................................ 29
U14.U UBibliografiaU ......................................................................................................... 30
U15.U UAnexosU ................................................................................................................ 31
U15.1.U UEscalonador.cU ............................................................................................... 31
U15.2.U UBibli.hU .......................................................................................................... 34
U15.3.U UEstatistica.txtU ................................................................................................ 38
5
1. Introdução
Durante o percorrer do curso, estudamos na matéria de Sistemas
Operacionais os Sistemas Operacionais em si e sua funcionalidades básicas,
será apresentado neste documento uma explicação sobre escalonador
(scheduler) e variáveis que fazem parte de sua implementação e execução.
Também será apresentado apresentada a implementação de um
escalonador básico, e os testes realizados em cada cenário no escalonador
implementado.
6
2. Sistema Operacional
Segundo Tanenbaum & Woodhull em [Sistemas Operacionais, 2000], o
programa de sistemas mais fundamental é o Sistema Operacional, que controla
todos os recursos do computador e fornece a base sobre a qual os programas
aplicativos podem ser escritos.
São os sistemas operacionais que proporcionam uma interface de
iteração para o usuário e o hardware, ele funciona como um intermediador
entre usuário e hardware.
Um Sistema Operacional é dividido em partes para seu funcionamento
ser realizado com sucesso, estas partes são, as System Calls, os Processos,
os Arquivos e o Shell.
2.1. System Calls
System Calls são instruções estendidas que fazem a interface entre o
Sistema Operacional e os Programas de Usuários. Tais Instruções variam de
Sistema Operacional para Sistema Operacional.
2.2. Processos
O conceito mais importante no estudo de sistemas operacionais, é o
conceito de processo. Em um computador multiprogramado, que contem vários
programas executando simultaneamente na memória, corresponde a um
procedimento ou seqüência de instruções e um conjunto de dados variáveis
utilizadas pelo programa. Além das instruções e dados, cada programa em
execução possui uma área de memória correspondente para armazenar os
valores dos registradores da UCP, quando o programa, por algum motivo, não
estiver sendo executado. Essa área de memória é conhecida como registro
7
descritor e, além dos valores dos registradores da UCP, contém outras
informações.
Assim, em um determinado sistema, cada programa em execução
constitui um processo. Portanto, podemos definir processo como sendo um
programa em execução, o qual é constituído por uma seqüência de instruções,
um conjunto de dados e um registro descritor.
2.3. Arquivos
Arquivos são informações contidas em Disco ou dispositivos de I/O,
segundo Tanenbaum & Woodhull em [Sistemas Operacionais, 2000], as
chamadas de sistemas são necessárias para criar, para remover, para ler e
para escrever arquivos. Antes de um arquivo poder ser lido, ele deve ser aberto
e depois de lido deve ser fechado, assim chamadas são fornecidas para tais
coisas. Tais chamadas são interpretadas e executadas pelo Sistema
Operacional, que manipula o disco onde o arquivo e informações presentes
nele estão contidas.
8
3. Escalonador de Processos
Quando um ou mais processos estão prontos para serem executados, o
Sistema Operacional deve decidir qual deles vai ser executado primeiro. A
parte do Sistema Operacional responsável por essa decisão é chamada de
escalonador, e o algoritmo usado para tal é chamado de algoritmo de
escalonamento. Em sistemas multiusuários e de tempo compartilhado o
algoritmo de escalonamento é bem complexo.
O Escalonador de Processos (scheduling), é uma atividade exercida
pelo escalonador, possibilitando assim que se execute mais processos de uma
só vez, onde estes processos são divididos por prioridade, assim os processos
com maior prioridade como os de I/O Bound e os Computacionalmente
intensivos.
3.1. Objetivos do Escalonamento
Justiça: fazer com que cada processo ganhe seu tempo justo, para
usarem o mesmo tempo na CPU;
Eficiência: manter a CPU ocupada a maior parte do tempo;
Tempo de Reposta: minimizar o tempo de resposta para os usuários
interativos;
Tempo de Turnaround: minimizar o tempo que usuários devem esperar
pelo resultado;
Throughput: maximizar o número de tarefas executados por unidade de
tempo.
3.2. Algoritmos Escalonadores
Existem dois tipos de algoritmos de escalonamento os preemptivos e os
não preemptivos, onde os algoritmos preemptivos permitem que os processos
sejam interrompidos durante sua execução e os algoritmos não preemptivos,
por serem utilizados exclusivamente em sistemas monoprocessados.
9
Alguns algoritmos de escalonamento mais utilizados são:
3.2.1. FIFO (First in, First Out) ou FCFS (First come, first served) que
como seu próprio nome já diz, o primeiro que chega será o primeiro
a ser executado;
3.2.2. SJF (Shortest Job First): Onde o menor processo ganhará a CPU
e atrás do mesmo formar uma fila de processos por ordem
crescente de tempo de execução;
3.2.3. SRT (Shortest Remaining Time): Neste algoritmo é escolhido o
processo que possua o menor tempo restante, mesmo que esse
processo chegue à metade de uma operação, se o processo novo
for menor ele será executado primeiro;
3.2.4. Algoritmo Loteria: O Sistema Operacional distribui tokens
(fichas), numerados entre os processos, para o escalonamento é
sorteado um numero aleatório para que o processo ganhe a vez na
CPU, processos com mais tokens têm mais chance de receber
antes a CPU.
3.2.5. Escalonamento garantido: Este algoritmo busca cumprir
promessas de alocação de CPU o mais preciso possível.
3.2.6. RR (Round-Robin): Nesse escalonamento o sistema operacional
possui um timer, chamado de quantum, onde todos os processos
ganham o mesmo valor de quantum para rodarem na CPU. Com
exceção do algoritmo RR e escalonamento garantido, todos os
outros sofrem do problema de Inanição (starvation).
3.2.7. Múltiplas Filas: São usadas várias filas de processos prontos
para executar, cada processo e colocado em uma fila, e cada fila
tem uma política de escalonamento própria e outra entre filas.
10
4. Simulação
Para que seja simulado um escalonador de processos de um sistema
operacional foi desenvolvido um algoritmo em múltiplas filas que durante sua
execução gera informações que são gravadas em um arquivo de estatísticas
para que os resultados obtidos possam ser analisados.
Neste algoritmo levamos em consideração alguns aspectos de
funcionamento de um escalonador verdadeiro, como: tamanho dos processos,
prioridades, quamtum (tempo que o processo recebe de CPU) e starvation
(processos que demoram muito tempo para ganhar a CPU).
Para obter alguns dados relativos ao escalonamento, usamos, neste
mesmo algoritmo, uma estrutura com algumas variáveis que armazenavam
informações para gerar uma estatística de desempenho. Com esses dados
sabemos, por exemplo, quantos processos foram criados e executados por
cada fila de prioridade, podendo assim saber o throughput. Abaixo
mostraremos o funcionamento do algoritmo e o software utilizado para gerar os
gráficos, e a seguir cada etapa da simulação e comentários a respeito dos
testes.
11
5. Funcionamento
O algoritmo aqui comentado, implementa um simulador de um
escalonador de processos, este algoritmo foi desenvolvido na linguagem C.
Neste algoritmo foram implementados estruturas que simulam as propriedades
e atributos de uma CPU e os Processos, filas com faixas crescentes de
prioridade inclusive uma para processo de sistema em tempo real, e algumas
outras funções.
A cada iteração, é chamada uma função que verifica a necessidade de
criar novos processos, esta função atribui um valor randômico a uma variável,
que é comparada a fim de saber se deve ser criado um novo processo ou não.
Caso um novo processo seja criado, é atribuído inicia-se uma nova instancia da
estrutura processo com os atributos de ID, prioridade, tamanho e quantum, que
após sua criação ele é inserido em uma fila de acordo com sua prioridade.
Se não for criado um processo nessa iteração com a CPU, é chamado o
escalonador. Este verifica as filas, para saber em qual fila há processo
esperando por CPU, e executa o processo com prioridade maior. Nesta
execução é dado um quantum, o tempo que o processo pode usar de CPU, e
após a execução, é diminuído o tamanho do processo em relação a este
quantum.
Um processo é considerado como executado quando seu tamanho
quantum é zero, isto significa que ele não precisa mais ser levado à CPU e
pode ser retirado das filas de Processos e realocado de acordo com sua
prioridade.
No final das iterações estipuladas, o algoritmo gera um relatório com os
dados colhidos ante sua execução, e os grava em um arquivo em disco
chamado “estatísticas.txt”.
12
6. FILAS
Usamos a seguinte política para separar os processos por prioridade.
Fila 1: esta fila é usada no caso de chegar algum processo de extrema
importância, por exemplo, de tempo real. Somente é colocado nesta fila
processos com prioridade 0 (zero). Estes processos são executados por inteiro,
sem poder ser retirado da CPU antes de terminar.
Fila 2: processos com prioridade de 1 até 19.
Fila 3: processos com prioridade de 20 até 39.
Fila 4: processos com prioridade de 40 até 59.
Fila 5: processos com prioridade de 60 até 79.
Fila 6: processos com prioridade de 80 até 99.
13
7. Simulações
7.1. Simulação 1
Nesta primeira simulação utilizamos a função rand() para atribuir o
quantum aleatoriamente aos novos processos gerados. Foi feita uma
simulação com probabilidade de 20% de ser criado um processo, em 2000
iterações do sistema. Pegamos informações em 4 faixas de tempo que são: 0-
499, 500-999, 1000-1499 e 1500-1999 iterações.
Verificamos que com esta probabilidade de criar novos processos, o
escalonador executou todos processos gerados.
0
10
20
30
40
50
60
70
80
90
100
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
14
7.2. Simulação 2
Nesta segunda simulação continuamos utilizando a função rand() para
atribuir o quantum aleatoriamente aos novos processos gerados, mas
alteramos a probabilidade de criar processos de 20 para 40% em 2000
iterações do sistema. Pegamos informações em 4 faixas de tempo que são: 0-
499, 500-999, 1000-1499 e 1500-1999 iterações.
Com esta probabilidade de criar processos, o escalonador já não
conseguiu executar a totalidade dos processos. Reparamos também que na
última faixa de tempo, o escalonador executou mais processos, isso por que a
criação de novos processos diminuiu, conseqüentemente diminuindo os
processos em starvation e aumentado um pouco o throughput.
0
10
20
30
40
50
60
70
80
90
100
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
15
7.3. Simulação 3
Nesta terceira simulação continuamos utilizando a função rand() para
atribuir o quantum aleatoriamente aos novos processos gerados, mas
alteramos a probabilidade de criar processos de 40 para 60% em 2000
iterações do sistema. Pegamos informações em 4 faixas de tempo que são: 0-
499, 500-999, 1000-1499 e 1500-1999 iterações.
Com 60% de probabilidade de criar novos processos, o escalonador não
conseguiu executar muitos processos, tendo uma queda considerável de
rendimento. Até a terceira faixa de tempo percebemos que o starvation
aumentou progressivamente e após passar das 1500 interações ocorreu uma
queda acentuada do mesmo.
0
10
20
30
40
50
60
70
80
90
100
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
16
7.4. Simulação 4
Nesta quarta simulação continuamos utilizando a função rand() para
atribuir o quantum aleatoriamente aos novos processos gerados, mas
alteramos a probabilidade de criar processos de 60 para 80% em 2000
iterações do sistema. Pegamos informações em 4 faixas de tempo que são: 0-
499, 500-999, 1000-1499 e 1500-1999 iterações.
Ao aumentar a probabilidade de criar novos processos de 60% para
80%, ouve um aumento no numero de processos criados, mas, o desempenho
continuou caindo, pois o numero de processos executados é quase
desprezível. Em relação ao Starvation não tivemos muitas alterações. Até a
terceira faixa de tempo percebemos que o starvation aumentou
progressivamente e após passar das 1500 interações ocorreu uma queda
acentuada do mesmo.
0
10
20
30
40
50
60
70
80
90
100
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
17
8. Comparando
Vamos mostrar alguns gráficos com as comparações de processos
criados, executados, throughput, e starvation com a criação em quantidade
baixa, média e grande de novos processos.
Iterações = 2000
Quantum = randômico
Probabilidade de criar novo processo = 20%, 40%, 60% 80%
8.1. Quantidade total de processos criados durante a simulação:
0
10
20
30
40
50
60
70
80
90
100
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
#REF!
18
8.2. Quantidade total de processos executados durante a simulação.
8.3. Quantidade total de starvation durante a simulação.
Como podemos observar no segundo gráfico, o número de processos
executados não aumentou muito em relação a mudança de quantidade de
processos novos, apesar do número de novos processos ter aumentado
0
100
200
300
400
500
600
700
800
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
#REF!
0
100
200
300
400
500
600
700
800
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
#REF!
19
significativamente, como observamos no primeiro gráfico. Em relação ao
starvation, podemos ver que o aumento de starvation foi proporcional ao
aumento de novos processos.
8.4. Conclusão das Simulações
Analisando os gráficos, chegamos a conclusão que atribuindo um
quantum aleatoriamente aos processos que serão executados, o desempenho
do escalonador só é aceitável quando o número de novos processos chegando
a CPU é baixo.
Quanto mais processos chegam a CPU em um curto espaço de tempo,
menos processos são executados, especialmente quando têm prioridade
menor, já que os processos com prioridade maior, ainda tem uma boa
porcentagem de execução.
20
9. Outras Simulações
Nas próximas simulações (6, 7, 8 e 9) atribuímos o quantum aos novos
processos de forma diferente. Pegamos o tamanho do processo que está
chegando a CPU e dividimos por dois. O resultado será utilizado como
quantum para a execução. Foram feitas simulações com probabilidades de
20%, 40%, 60% e 80% de ser criado um processo, em 2000 iterações do
sistema. Pegamos informações em 4 faixas de tempo que são: 0-499, 500-999,
1000-1499 e 1500-1999 iterações.
9.1. Simulação 5
Iterações = 2000
Quantum = tamanho / 2
Probabilidade de criar novo processo = 20%
Verificamos que com esta probabilidade de criar novos processos, o
escalonador executou todos. Somente na terceira faixa de tempo, ficaram
alguns sem executar, o que foi compensado na parte final.
0
10
20
30
40
50
60
70
80
90
100
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
21
9.2. Simulação 6
Iterações = 2000
Quantum = tamanho / 2
Probabilidade de criar novo processo = 40%
Com esta probabilidade de criar processos, o escalonador continuou
executando um bom número de processos. Na terceira faixa de tempo teve um
aumento de processos novos, o que acarretou uma queda de throughput, e
aumento do starvation.
Como na parte final, a criação de processos foi maior, o escalonador
diminuiu a execução de processos.
0
100
200
300
400
500
600
700
800
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
22
9.3. Simulação 7
Iterações = 2000
Quantum = tamanho / 2
Probabilidade de criar novo processo = 60%
Com muitos processos precisando utilizar a CPU, o escalonador não
conseguiu executar muitas vezes. Pelo gráfico percebemos que a execução se
manteve constante praticamente todo tempo, mesmo tendo uma pequena
variação na quantidade de processos criados.
0
100
200
300
400
500
600
700
800
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
23
9.4. Simulação 8
Iterações = 2000
Quantum = tamanho / 2
Probabilidade de criar novo processo = 80%
Os gráficos indicam que com a criação de processos em 80% A CPU
não modificou muito a sua forma de execução, ficando muito parecido com o
gráfico de 60% de probabilidade, tendo apenas um aumento no starvation e
uma queda dos processos executados.
0
200
400
600
800
1000
1200
1400
0 500 1000 1500 2000
Processos criados
processos executados
starvattion
24
10. Média de Throughput
As médias de throughput foram calculadas a partir de cada interação
executada, visando assim mostrar em cada interação a quantidade de
processos executados.
Foram feitas quatro interações, onde sua duração é determinada por um
loop de 500 voltas, de onde foram tirados os dados dos processos executados
por fase de interação que seria a unidade de tempo necessária para calcular o
throughput.
0
10
20
30
40
50
60
70
500 1000 1500 2000
Fila 1
Fila 1
0
5
10
15
20
25
500 1000 1500 2000
Fila 2
Fila 2
25
020406080
100120140
500 1000 1500 2000
Fila 3
Fila 3
0
20
40
60
80
100
120
140
500 1000 1500 2000
Fila 4
Fila 4
0
50
100
150
200
500 1000 1500 2000
Fila 5
Fila 5
26
Para todas as médias de throughput calculadas, foram obtidos seis
gráficos que demonstram o crescimento dos processos executados a cada
faixa de tempo interações que foram realizados. Assim mostro abaixo um
gráfico com um comparativo entre o crescimento do throughput para cada fila.
Para cada fila tem-se um diferencial de crescimento devido à adição do
tempo quantum para cada fila de acordo com sua prioridade, assim mostrando
um crescimento variado para cada fila.
020406080
100120140160
500 1000 1500 2000
Fila 6
Fila 6
0
20
40
60
80
100
120
140
160
180
500 1000 1500 2000
Fila 1
Fila 2
Fila 3
Fila 4
Fila 5
Fila 6
27
11. COMPARAÇÃO DAS SIMULAÇÕES 6, 7, 8 e 9
Iterações = 12000
Quantum = tamanho / 2
Probabilidade de criar novo processo = 20%, 40%, 60% e 80%
Vamos mostrar alguns gráficos com as comparações de processos
criados, executados e starvation com a criação em quantidade baixa, média e
alta de novos processos.
11.1. Quantidade total de processos criados durante a simulação.
0
50
100
150
200
250
300
350
400
450
500
0 500 1000 1500 2000
20%
40%
60%
80%
28
11.2. Quantidade total de processos executados durante a simulação.
11.3. Quantidade total de starvation durante a simulação.
Como podemos observar pelos gráficos, o número de processos
executados com probabilidade menor de criação de novos processos em
relação ao tempo, é igual a quantidade de processos criados, gerando um bom
throughput. Quando aumentamos a quantidade de processos, o número fica
bem abaixo, o que gera um aumento no starvation.
0
10
20
30
40
50
60
70
80
90
100
0 500 1000 1500 2000
20%
40%
60%
80%
0
200
400
600
800
1000
1200
1400
0 500 1000 1500 2000
20%
40%
60%
80%
29
12. CONCLUSÃO SIMULAÇÃO 2
Analisando os gráficos observamos que o número de processos executados que
possuem uma prioridade maior foi satisfatória. Em compensação, processos com
prioridades muito baixa, praticamente não foram a CPU. somente quando tem poucos
processos chegando ao mesmo tempo, estes conseguem acesso a CPU para serem
executados.
Como a quantidade de processos utilizada na terceira fase da simulação foi
elevada, é compreensível o escalonador ter agido desta maneira, por ter dado
preferência à execução dos processos mais importantes. Nas simulações que geraram
uma quantidade razoável de processos, tanto processos com prioridade maior, como
processos com prioridade menor foram executados em bom número. Conseguimos um
bom throughput.
13. CONCLUSÃO SIMULAÇÃO 2
Analisando os gráficos observamos que o número de processos executados que
possuem uma prioridade maior foi satisfatória. Em compensação, processos com
prioridades muito baixa, praticamente não foram a CPU. somente quando tem poucos
processos chegando ao mesmo tempo, estes conseguem acesso a CPU para serem
executados.
Como a quantidade de processos utilizada na terceira fase da simulação foi
elevada, é compreensível o escalonador ter agido desta maneira, por ter dado
preferência à execução dos processos mais importantes. Nas simulações que geraram
uma quantidade razoável de processos, tanto processos com prioridade maior, como
processos com prioridade menor foram executados em bom número. Conseguimos um
bom throughput.
30
14. Bibliografia TANENBAUM, ANDREW S. – Sistemas Operacionais: projeto e implementação / Andrew S. Tanenbaum e Albert S. Woodhull; trad: Edson Furmankiewicz. – 2ª Edição, Porto Alegre: Bookman, 2000. ISBN 85-7307-530-9. ESCALONAMENTO DE PROCESSOS, Uhttp://pt.wikipedia.org/wiki/ Escalonamento_de_processosU - Esta página foi modificada pela última vez às 00h43min de 11 de maio de 2010.
31
15. Anexos
15.1. Escalonador.c #include <stdio.h> #include <stdlib.h> #include <time.h> #include "bibli.h" main(){ int i, j, x, iteracao=0; lista Lista1Processos, Lista2Processos, Lista3Processos; lista Lista4Processos, Lista5Processos, Lista6Processos; c.tempo = 0; ARQ = fopen("estatisticas.txt","w"); create(&Lista1Processos); create(&Lista2Processos); create(&Lista3Processos); create(&Lista4Processos); create(&Lista5Processos); create(&Lista6Processos); for (i=0; i<6; i++){ for (j=0; j<4; j++){ e[i][j].cont_proc_novos = 0; e[i][j].cont_proc_executados = 0; e[i][j].cont_proc = 0; e[i][j].cont_proc_starvation = 0; } } while (iteracao < 2000) { // verifica se foi criado um novo processo. caso criou, coloca na fila correta if (cria_processo(iteracao)) { if (p.prioridade == 0) { insert(&Lista1Processos, p); atualiza_estatistica(1, 1, iteracao); } else if ((p.prioridade >= 1) && (p.prioridade <= 19)) { insert(&Lista2Processos,p); atualiza_estatistica(1, 2, iteracao); } else if ((p.prioridade >= 20) && (p.prioridade <= 39)) { insert(&Lista3Processos, p); atualiza_estatistica(1, 3, iteracao); } else if ((p.prioridade >= 40) && (p.prioridade <= 59)){ insert(&Lista4Processos, p); atualiza_estatistica(1, 4, iteracao); }
32
else if ((p.prioridade >= 60) && (p.prioridade <= 79)){ insert(&Lista5Processos, p); atualiza_estatistica(1, 5, iteracao); } else if ((p.prioridade >= 80) && (p.prioridade <= 99)){ insert(&Lista6Processos, p); atualiza_estatistica(1, 6, iteracao); } } // caso não tenha sido criado novo processo, simula execução de um processo else { if (!isEmpty(Lista1Processos)){ if (executa_processo(&Lista1Processos)) insert(&Lista1Processos, p); else atualiza_estatistica(2, 1, iteracao); } else if (!isEmpty(Lista2Processos)){ if (executa_processo(&Lista2Processos)) insert(&Lista2Processos, p); else atualiza_estatistica(2, 2, iteracao); } else if (!isEmpty(Lista3Processos)){ if (executa_processo(&Lista3Processos)) insert(&Lista3Processos, p); else atualiza_estatistica(2, 3, iteracao); } else if (!isEmpty(Lista4Processos)){ if (executa_processo(&Lista4Processos)) insert(&Lista4Processos, p); else atualiza_estatistica(2, 4, iteracao); } else if (!isEmpty(Lista5Processos)){ if (executa_processo(&Lista5Processos)) insert(&Lista5Processos, p); else atualiza_estatistica(2, 5, iteracao); } else if (!isEmpty(Lista6Processos)){ if (executa_processo(&Lista6Processos)) insert(&Lista6Processos, p); else atualiza_estatistica(2, 6, iteracao); } } fprintf(ARQ,"Iteracoes: %d\t", iteracao); fprintf(ARQ,"Processos criados: %d\t", e[0][0].cont_proc_novos); fprintf(ARQ,"Processos executados: %d\n", e[0][0].cont_proc_executados); // verifica quantos processos tem em cada fila e se há starvation if (iteracao == 499){ verifica_starvation(Lista1Processos, 1, 1); verifica_starvation(Lista2Processos, 2, 1); verifica_starvation(Lista3Processos, 3, 1); verifica_starvation(Lista4Processos, 4, 1); verifica_starvation(Lista5Processos, 5, 1); verifica_starvation(Lista6Processos, 6, 1);
33
} else if (iteracao == 999){ verifica_starvation(Lista1Processos, 1, 2); verifica_starvation(Lista2Processos, 2, 2); verifica_starvation(Lista3Processos, 3, 2); verifica_starvation(Lista4Processos, 4, 2); verifica_starvation(Lista5Processos, 5, 2); verifica_starvation(Lista6Processos, 6, 2); } else if (iteracao == 1449){ verifica_starvation(Lista1Processos, 1, 3); verifica_starvation(Lista2Processos, 2, 3); verifica_starvation(Lista3Processos, 3, 3); verifica_starvation(Lista4Processos, 4, 3); verifica_starvation(Lista5Processos, 5, 3); verifica_starvation(Lista6Processos, 6, 3); } else if (iteracao == 2000){ verifica_starvation(Lista1Processos, 1, 4); verifica_starvation(Lista2Processos, 2, 4); verifica_starvation(Lista3Processos, 3, 4); verifica_starvation(Lista4Processos, 4, 4); verifica_starvation(Lista5Processos, 5, 4); verifica_starvation(Lista6Processos, 6, 4); // para armazenar o total e[0][0].cont_proc = e[0][4].cont_proc; e[0][0].cont_proc_starvation = e[0][4].cont_proc_starvation; } iteracao++; } fprintf(ARQ,"::::::::: FILA 1 ::::::::::\n"); imprime(Lista1Processos); fprintf(ARQ,"::::::::: FILA 2 ::::::::::\n"); imprime(Lista2Processos); fprintf(ARQ,"::::::::: FILA 3 ::::::::::\n"); imprime(Lista3Processos); fprintf(ARQ,"::::::::: FILA 4 ::::::::::\n"); imprime(Lista4Processos); fprintf(ARQ,"::::::::: FILA 5 ::::::::::\n"); imprime(Lista5Processos); fprintf(ARQ,"::::::::: FILA 6 ::::::::::\n"); imprime(Lista6Processos); fprintf(ARQ,"Processos criados: %d", e[0][0].cont_proc_novos); fprintf(ARQ,"\nProcessos executados: %d", e[0][0].cont_proc_executados); mostra_estatistica(); printf("Arquivo com as informações de execução foi gravado em disco!\n");
34
fclose(ARQ); } // fim do main
15.2. Bibli.h #define TRUE 1 #define FALSE 0 typedef struct{ int id; int prioridade; int tamanho; int tamanho_restante; int quantum; }processo; typedef struct{ int id; int tempo; }cpu; typedef struct{ int cont_proc_novos; int cont_proc_executados; int cont_proc; int cont_proc_starvation; }estatistica; processo p; cpu c; estatistica e[7][5]; FILE *ARQ; struct no{ processo dado; struct no *prox; }; typedef struct { struct no *inicio; } lista; void create(lista *q){ q->inicio=NULL; } int isEmpty(lista q){ if (q.inicio==NULL) return TRUE; else return FALSE; }
35
int cria_processo(int iteracoes){ int x; srand(time(NULL) * (e[0][0].cont_proc_novos + 1 * iteracoes + 1)); x = rand()%100; if (x < 80){ p.id = e[0][0].cont_proc_novos + 1; p.prioridade = rand()%100; p.tamanho = 1 + rand()%9; p.tamanho_restante = p.tamanho; p.quantum = p.tamanho / 2; return(TRUE); } return(FALSE); } int insert(lista *q, processo d){ struct no *aux, *atual, *anterior; aux = (struct no *) malloc(sizeof(struct no)); if (aux!=NULL){ aux->dado=d; aux->prox=NULL; anterior = NULL; atual = q->inicio; while ((atual != NULL) && (d.prioridade > atual->dado.prioridade)){ anterior = atual; atual = atual->prox; } if (anterior == NULL){ aux->prox = q->inicio; q->inicio = aux; } else { anterior->prox=aux; aux->prox = atual; } } } int executa_processo(lista *q){ struct no *aux, *atual, *anterior; srand(time(NULL) * (e[0][0].cont_proc_novos + 1 * (q->inicio)->dado.tamanho)); // atribui um quantum ao processo e diminui o tamanho restante if ((q->inicio)->dado.prioridade == 0) (q->inicio)->dado.quantum = (q->inicio)->dado.tamanho; else (q->inicio)->dado.quantum = 1 + rand()%(q->inicio)->dado.tamanho; (q->inicio)->dado.tamanho_restante = (q->inicio)->dado.tamanho_restante - (q->inicio)->dado.quantum; c.tempo = c.tempo + (q->inicio)->dado.quantum; if ((q->inicio)->dado.tamanho_restante <= 0){ aux = q->inicio; q->inicio = (q->inicio)->prox; free(aux); return(FALSE); } else{
36
// guarda os dados do processo atual p.id = (q->inicio)->dado.id; p.prioridade = (q->inicio)->dado.prioridade; p.tamanho = (q->inicio)->dado.tamanho; p.tamanho_restante = (q->inicio)->dado.tamanho_restante; p.quantum = (q->inicio)->dado.quantum; // deleta ele da lista para recolocá-lo aux = q->inicio; q->inicio = (q->inicio)->prox; free(aux); return(TRUE); } } void verifica_starvation(lista q, int f, int i){ struct no *aux; aux = q.inicio; if (!isEmpty(q)){ while (aux != NULL){ e[0][i].cont_proc++; e[f][i].cont_proc++; if (aux->dado.tamanho == aux->dado.tamanho_restante){ e[0][i].cont_proc_starvation++; e[f][i].cont_proc_starvation++; } aux = aux->prox; } } } void imprime(lista q){ struct no *aux; int ContadorNos = 0; aux = q.inicio; if (!isEmpty(q)){ while (aux != NULL){ ContadorNos++; fprintf(ARQ,"ID: %d", aux->dado.id); fprintf(ARQ,"\tTamanho: %d", aux->dado.tamanho); fprintf(ARQ,"\tRestante: %d", aux->dado.tamanho_restante); fprintf(ARQ,"\tQuantum: %d", aux->dado.quantum); fprintf(ARQ,"\tPrioridade: %d\n", aux->dado.prioridade); aux = aux->prox; } fprintf(ARQ,"\n\nQuantidade de processos: %d", ContadorNos); } fprintf(ARQ,"\n\n\n"); } void atualiza_estatistica(int tipo, int fila, int interacoes){ if (tipo == 1){ e[0][0].cont_proc_novos++; e[fila][0].cont_proc_novos++;
37
if (interacoes <= 499){ e[0][1].cont_proc_novos++; e[fila][1].cont_proc_novos++; } else if ((interacoes >= 500) && (interacoes <= 999)){ e[0][2].cont_proc_novos++; e[fila][2].cont_proc_novos++; } else if ((interacoes >= 1000) && (interacoes <= 1499)){ e[0][3].cont_proc_novos++; e[fila][3].cont_proc_novos++; } else if ((interacoes >= 1500) && (interacoes <= 1999)){ e[0][4].cont_proc_novos++; e[fila][4].cont_proc_novos++; } } else if (tipo == 2){ e[0][0].cont_proc_executados++; - 42 - e[fila][0].cont_proc_executados++; if (interacoes <= 499){ e[0][1].cont_proc_executados++; e[fila][1].cont_proc_executados++; } else if ((interacoes >= 500) && (interacoes <= 999)){ e[0][2].cont_proc_executados++; e[fila][2].cont_proc_executados++; } else if ((interacoes >= 1000) && (interacoes <= 1499)){ e[0][3].cont_proc_executados++; e[fila][3].cont_proc_executados++; } else if ((interacoes >= 1500) && (interacoes <= 1999)){ e[0][4].cont_proc_executados++; e[fila][4].cont_proc_executados++; } } } void mostra_estatistica(){ int i; int j; int faixa = 499; fprintf(ARQ,"\n_______________________________________________________________\n\n"); fprintf(ARQ,"ESTATISTICAS"); fprintf(ARQ,"\n_______________________________________________________________\n\n"); for(i=0;i<5;i++){ if(i==0) fprintf(ARQ,"GERAL\n"); else fprintf(ARQ," FAIXA %d (%d a %d)\n",i,faixa-499,faixa); fprintf(ARQ,"Fila\tProcessos Criados\tProcessos Executados\tQtd Processos\tStarvation\n");
38
for(j=1;j<7;j++){ fprintf(ARQ," %d\t\t%2d\t\t\t%2d\t\t %2d\t %2d\n",j, e[j][i].cont_proc_novos, e[j][i].cont_proc_executados, e[j][i].cont_proc, e[j][i].cont_proc_starvation); } if(j>6) fprintf(ARQ, " T\t\t%2d\t\t\t%2d\t\t %2d\t %2d\n", e[0][i].cont_proc_novos, e[0][i].cont_proc_executados, e[0][i].cont_proc, e[0][i].cont_proc_starvation); fprintf(ARQ,"\n__________________________________________________________________"); fprintf(ARQ,"\n\n"); faixa += 500; } }
15.3. Estatistica.txt
Devido ao grande número de linhas geradas pelo escalonador, estarei
disponibilizando o arquivo na URL seguinte:
http:\\www.comp.pucpcaldas.br/~al550316968/estatísticas.txt