Vamos começar com o agendador de IO primeiro. Há um agendador de I / O por dispositivo de bloco. Sua tarefa é agendar (ordenar) as solicitações que se acumulam na fila de dispositivos. Existem três algoritmos diferentes atualmente enviados no kernel do Linux: deadline
, noop
e cfq
. cfq
é o padrão e, de acordo com seu documento:
The CFQ I/O scheduler tries to distribute bandwidth equally among all processes in the system. It should provide a fair and low latency working environment, suitable for both desktop and server systems
Você pode configurar qual agendador controla qual dispositivo por meio do arquivo scheduler
correspondente ao seu dispositivo de bloco em /sys/
(Você pode emitir o seguinte comando para encontrá-lo: find /sys | grep queue/scheduler
).
O que essa breve descrição não diz é que cfq
é o único agendador que analisa o ioprio
de um processo. ioprio
é uma configuração que você pode atribuir ao processo, e o algoritmo levará isso em consideração ao escolher uma solicitação antes da outra. ioprio
pode ser definido através do utilitário ionice
.
Depois, há o agendador de tarefas. Sua tarefa é alocar as CPUs entre os processos que estão prontos para serem executados . Leva em conta coisas como a prioridade, a classe e a gentileza de um processo de doação, bem como quanto tempo esse processo foi executado e outras heurísticas.
Agora, para suas perguntas:
What is relationship between IO scheduler and CPU scheduler?
Não muito, além do nome. Eles agendem diferentes recursos compartilhados. O primeiro ordena as requisições para os discos, e o segundo programa as requisições (você pode ver um processo como requisitando tempo de CPU para poder rodar) para a CPU.
CPU scheduling happens first. IO scheduler is a thread itself and subject to CPU scheduling.
Isso não acontece como o algoritmo do agendador de IO é executado por qualquer processo que esteja enfileirando uma solicitação. Uma boa maneira de ver isso é observar as falhas que têm elv_add_request()
em seu caminho. Por exemplo :
[...]
[<c027fac4>] error_code+0x74/0x7c
[<c019ed65>] elv_next_request+0x6b/0x116
[<e08335db>] scsi_request_fn+0x5e/0x26d [scsi_mod]
[<c019ee6a>] elv_insert+0x5a/0x134
[<c019efc1>] __elv_add_request+0x7d/0x82
[<c019f0ab>] elv_add_request+0x16/0x1d
[<e0e8d2ed>] pkt_generic_packet+0x107/0x133 [pktcdvd]
[<e0e8d772>] pkt_get_disc_info+0x42/0x7b [pktcdvd]
[<e0e8eae3>] pkt_open+0xbf/0xc56 [pktcdvd]
[<c0168078>] do_open+0x7e/0x246
[<c01683df>] blkdev_open+0x28/0x51
[<c014a057>] __dentry_open+0xb5/0x160
[<c014a183>] nameidata_to_filp+0x27/0x37
[<c014a1c6>] do_filp_open+0x33/0x3b
[<c014a211>] do_sys_open+0x43/0xc7
[<c014a2cd>] sys_open+0x1c/0x1e
[<c0102b82>] sysenter_past_esp+0x5f/0x85
Observe como o processo entra no kernel chamando open (), e isso acaba envolvendo o algoritmo elevator ( elv
).