Note:
I converted the original process-run.py using ChatGPT because I am too lasy to have another python on my server. I shared the file below as someone may also need one.
Hopefully it won’t involve me into copyright issues, but if it did, please kindly tell me.
process-run.py for Python3
And sure, if you’re not interested in setting your own parameters to do further testing, or you happen to be inconvenient to run the script yourself, you can just refer to the outputs I provided with below.
- python3 ./process-run.py -l 5:100,5:100
Expected: The CPU using rate will be 100%.
Actual: It did.
~# python3 ./process-run.py -l 5:100,5:100 -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:cpu READY 1
3 RUN:cpu READY 1
4 RUN:cpu READY 1
5 RUN:cpu READY 1
6 DONE RUN:cpu 1
7 DONE RUN:cpu 1
8 DONE RUN:cpu 1
9 DONE RUN:cpu 1
10 DONE RUN:cpu 1
Stats: Total Time 10
Stats: CPU Busy 10 (100.00%)
Stats: IO Busy 0 (0.00%)
As there is no chance that a IO operation will be executed, the CPU is always occupied.
- python3 ./process-run.py -l 4:100,1:0 -c -p
Expected: I forget whether another process will be switched to simutaneously when the current process switches into IO state or not. My instinct tells me it’s not. IOs cost one unit and CPU cost 4 units of time, so I thought it would be 5 units of time.
Actual: It takes 10 units.
~# python3 ./process-run.py -l 4:100,1:0 -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:cpu READY 1
3 RUN:cpu READY 1
4 RUN:cpu READY 1
5 DONE RUN:io 1
6 DONE WAITING 1
7 DONE WAITING 1
8 DONE WAITING 1
9 DONE WAITING 1
10* DONE DONE
Stats: Total Time 10
Stats: CPU Busy 5 (50.00%)
Stats: IO Busy 4 (40.00%)
I neglected the fact that a IO process takes 5 units of time by default. However, there is one thing worth noticing: the final time segment. It simply doesn’t nothing but was still counted into total times, and has a special asterisk mark on itself. Personally I think it should not be counted as it has no active task being executed actually.
- python3 ./process-run.py -l 1:0,4:100 -c -p
Expected: As the sequence changes, in the first unit of time, a IO process will be activated and the current process will be switched to the 2nd process. And as the policy is switching to another when the whole process is done, it won’t switch back to the first even if the io process is done. So I thought it would be:
1 2
1 IO, wait
2 wait, CPU
3 wait, CPU
4 wait, CPU
5 IO fin,but still waiting CPU
6* done done
Actual: Partially correct.
~# python3 ./process-run.py -l 1:0,4:100 -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 WAITING RUN:cpu 1 1
3 WAITING RUN:cpu 1 1
4 WAITING RUN:cpu 1 1
5 WAITING RUN:cpu 1 1
6* DONE DONE
Stats: Total Time 6
Stats: CPU Busy 5 (83.33%)
Stats: IO Busy 4 (66.67%)
At first It seems my guessing is wrong as it immediately switchs its current process and make good use of the vacant CPU when a IO happens. But I noticed that the first CPU period is actually used by the first process and it’s also counted into IO length! That is so confusing as there is not only IO usage counted in the IO length.
Furthermore, by “Partially correct” I mean while I was writing the correct sequence of processingm I overlooked the actual state of both processes. If a process is not blocked it should not be “waiting” but “ready”.
- python3 ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_END
Expected: SWITCH_ON_END means switch to another process when the current whole process is end, which means you can’t make good use of the idle CPU. So it would be:
RUN:IO READY
WAITING READY
WAITING READY
WAITING READY
WAITING READY
DONE RUN:CPU
DONE RUN:CPU
DONE RUN:CPU
DONE RUN:CPU
DONE DONE
Actual: It does.
~# python3 ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_END
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 WAITING READY 1
3 WAITING READY 1
4 WAITING READY 1
5 WAITING READY 1
6* DONE RUN:cpu 1
7 DONE RUN:cpu 1
8 DONE RUN:cpu 1
9 DONE RUN:cpu 1
Notice that there is no double DONE for the last segment. I don’t know why but I don’t care 😀
- python3 ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_IO
Expected:
RUN:IO READY
WAITING RUN:CPU
WAITING RUN:CPU
WAITING RUN:CPU
WAITING RUN:CPU
DONE DONE
Actually:
~# python3 ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_IO
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 WAITING RUN:cpu 1 1
3 WAITING RUN:cpu 1 1
4 WAITING RUN:cpu 1 1
5 WAITING RUN:cpu 1 1
6* DONE DONE
Now I have another guessing that the asterisk is to especially point out when the IO process actually done.
- python3 ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -IIO_RUN_LATER -c -p
This one is kinda complicated at the first glance. But Noticed that there is only one IO related process and it won’t switch back until another CPU related process is done. Roughly I thought it would be:
RUN:IO READY READY READY
WAITING RUN:CPU READY …
WAITING RUN:CPU READY …
WAITING RUN:CPU READY …
WAITING RUN:CPU READY …
RUN:IO DONE READY …
WAITING DONE RUN:CPU …
Actually:
~# python3 ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -IIO_RUN_LATER -c -p
Time PID: 0 PID: 1 PID: 2 PID: 3 CPU IOs
1 RUN:io READY READY READY 1
2 WAITING RUN:cpu READY READY 1 1
3 WAITING RUN:cpu READY READY 1 1
4 WAITING RUN:cpu READY READY 1 1
5 WAITING RUN:cpu READY READY 1 1
6* READY RUN:cpu READY READY 1
7 READY DONE RUN:cpu READY 1
8 READY DONE RUN:cpu READY 1
9 READY DONE RUN:cpu READY 1
10 READY DONE RUN:cpu READY 1
11 READY DONE RUN:cpu READY 1
12 READY DONE DONE RUN:cpu 1
13 READY DONE DONE RUN:cpu 1
14 READY DONE DONE RUN:cpu 1
15 READY DONE DONE RUN:cpu 1
16 READY DONE DONE RUN:cpu 1
17 RUN:io DONE DONE DONE 1
18 WAITING DONE DONE DONE 1
19 WAITING DONE DONE DONE 1
20 WAITING DONE DONE DONE 1
21 WAITING DONE DONE DONE 1
22* RUN:io DONE DONE DONE 1
23 WAITING DONE DONE DONE 1
24 WAITING DONE DONE DONE 1
25 WAITING DONE DONE DONE 1
26 WAITING DONE DONE DONE 1
27* DONE DONE DONE DONE
Stats: Total Time 27
Stats: CPU Busy 18 (66.67%)
Stats: IO Busy 12 (44.44%)
I think I have a misunderstanding of IO_RUN_LATER. That LATER is later later, as it won’t switch back until all the other process finished.
- python3 ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -IIO_RUN_IMMEDIATE -c -p
Thought it would be:
RUN:IO READY READY READY
WAITING RUN:CPU READY …
WAITING RUN:CPU READY …
WAITING RUN:CPU READY …
WAITING RUN:CPU READY …
RUN:IO READY READY …
WAITING RUN:CPU READY …
WAITING DONE RUN:CPU …
WAITING DONE RUN:CPU …
WAITING DONE RUN:CPU …
…
Actually:
~# python3 ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -IIO_RUN_IMMEDIATE -c -p
Time PID: 0 PID: 1 PID: 2 PID: 3 CPU IOs
1 RUN:io READY READY READY 1
2 WAITING RUN:cpu READY READY 1 1
3 WAITING RUN:cpu READY READY 1 1
4 WAITING RUN:cpu READY READY 1 1
5 WAITING RUN:cpu READY READY 1 1
6* RUN:io READY READY READY 1
7 WAITING RUN:cpu READY READY 1 1
8 WAITING DONE RUN:cpu READY 1 1
9 WAITING DONE RUN:cpu READY 1 1
10 WAITING DONE RUN:cpu READY 1 1
11* RUN:io DONE READY READY 1
12 WAITING DONE RUN:cpu READY 1 1
13 WAITING DONE RUN:cpu READY 1 1
14 WAITING DONE DONE RUN:cpu 1 1
15 WAITING DONE DONE RUN:cpu 1 1
16* DONE DONE DONE RUN:cpu 1
17 DONE DONE DONE RUN:cpu 1
18 DONE DONE DONE RUN:cpu 1
Stats: Total Time 18
Stats: CPU Busy 18 (100.00%)
Stats: IO Busy 12 (66.67%)
Correct.
IO-related process produces vacant CPU times. Starting IO process earlier means more chance for other CPU-related process to have better use of these vacant times.
8.Randomly Generated Param:
~# python3 ./process-run.py -s 1 -l 3:50,3:50
Produce a trace of what would happen when you run these processes:
Process 0
cpu
io
io
Process 1
cpu
cpu
cpu
Important behaviors:
System will switch when the current process is FINISHED or ISSUES AN IO
After IOs, the process issuing the IO will run LATER (when it is its turn)
Starts with process 1 but process 2 finishes earlier due to io waiting.
# python3 ./process-run.py -s 1 -l 3:50,3:50 -c
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:io READY 1
3 WAITING RUN:cpu 1 1
4 WAITING RUN:cpu 1 1
5 WAITING RUN:cpu 1 1
6 WAITING DONE 1
7* RUN:io DONE 1
8 WAITING DONE 1
9 WAITING DONE 1
10 WAITING DONE 1
11 WAITING DONE 1
12* DONE DONE
~# python3 ./process-run.py -s 2 -l 3:50,3:50
Produce a trace of what would happen when you run these processes:
Process 0
io
io
cpu
Process 1
cpu
io
io
Important behaviors:
System will switch when the current process is FINISHED or ISSUES AN IO
After IOs, the process issuing the IO will run LATER (when it is its turn)
Two processes finishes almost at the same time as they have the same proportion of IO tasks even though the sequence is different, which produces more cpu vacant time.
~# python3 ./process-run.py -s 2 -l 3:50,3:50 -c
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 WAITING RUN:cpu 1 1
3 WAITING RUN:io 1 1
4 WAITING WAITING 2
5 WAITING WAITING 2
6* RUN:io WAITING 1 1
7 WAITING WAITING 2
8* WAITING RUN:io 1 1
9 WAITING WAITING 2
10 WAITING WAITING 2
11* RUN:cpu WAITING 1 1
12 DONE WAITING 1
13* DONE DONE
python3 ./process-run.py -s 3 -l 3:50,3:50
Produce a trace of what would happen when you run these processes:
Process 0
cpu
io
cpu
Process 1
io
io
cpu
Important behaviors:
System will switch when the current process is FINISHED or ISSUES AN IO
After IOs, the process issuing the IO will run LATER (when it is its turn)
Process 0 finishes earlier and there is too much cpu vacant time.
~# python3 ./process-run.py -s 3 -l 3:50,3:50 -c
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:io READY 1
3 WAITING RUN:io 1 1
4 WAITING WAITING 2
5 WAITING WAITING 2
6 WAITING WAITING 2
7* RUN:cpu WAITING 1 1
8* DONE RUN:io 1
9 DONE WAITING 1
10 DONE WAITING 1
11 DONE WAITING 1
12 DONE WAITING 1
13* DONE RUN:cpu 1
I have no idea if I should toy with the -I and -S options. But let’s have a look at -S SWITCH_ON_END first. I think it would be a disaster if there are two much IO-related tasks. Take
python3 ./process-run.py -s 2 -l 3:50,3:50 as a Example:
root@C202511211157657:~# python3 ./process-run.py -s 2 -l 3:50,3:50 -S SWITCH_ON_END -c
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 WAITING READY 1
3 WAITING READY 1
4 WAITING READY 1
5 WAITING READY 1
6* RUN:io READY 1
7 WAITING READY 1
8 WAITING READY 1
9 WAITING READY 1
10 WAITING READY 1
11* RUN:cpu READY 1
12 DONE RUN:cpu 1
13 DONE RUN:io 1
14 DONE WAITING 1
15 DONE WAITING 1
16 DONE WAITING 1
17 DONE WAITING 1
18* DONE RUN:io 1
19 DONE WAITING 1
20 DONE WAITING 1
21 DONE WAITING 1
22 DONE WAITING 1
23* DONE DONE
Yes, the sequence grows almost 1 time bigger than the other one.
As for the -IIO_RUN_LATER, I think it would have the exact same effect on our -s 2 scenario:
~# python3 ./process-run.py -s 2 -l 3:50,3:50 -IIO_RUN_LATER -c
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 WAITING RUN:cpu 1 1
3 WAITING RUN:io 1 1
4 WAITING WAITING 2
5 WAITING WAITING 2
6* RUN:io WAITING 1 1
7 WAITING WAITING 2
8* WAITING RUN:io 1 1
9 WAITING WAITING 2
10 WAITING WAITING 2
11* RUN:cpu WAITING 1 1
12 DONE WAITING 1
13* DONE DONE
But actually it wasn’t. I think the reason maybe they both have almost the same proportion of IO, and if I change the ratio and instruction number for the 2nd process, there would be a disaster, let’s see:
~# python3 ./process-run.py -s 2 -l 3:50,20:100 -IIO_RUN_LATER -c
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 WAITING RUN:cpu 1 1
3 WAITING RUN:cpu 1 1
4 WAITING RUN:cpu 1 1
5 WAITING RUN:cpu 1 1
6* READY RUN:cpu 1
7 READY RUN:cpu 1
8 READY RUN:cpu 1
9 READY RUN:cpu 1
10 READY RUN:cpu 1
11 READY RUN:cpu 1
12 READY RUN:cpu 1
13 READY RUN:cpu 1
14 READY RUN:cpu 1
15 READY RUN:cpu 1
16 READY RUN:cpu 1
17 READY RUN:cpu 1
18 READY RUN:cpu 1
19 READY RUN:cpu 1
20 READY RUN:cpu 1
21 READY RUN:cpu 1
22 RUN:io DONE 1
23 WAITING DONE 1
24 WAITING DONE 1
25 WAITING DONE 1
26 WAITING DONE 1
27* RUN:cpu DONE 1
For comparision let’s change the -I option:
~# python3 ./process-run.py -s 2 -l 3:50,20:100 -c -IIO_RUN_IMMEDIATE
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 WAITING RUN:cpu 1 1
3 WAITING RUN:cpu 1 1
4 WAITING RUN:cpu 1 1
5 WAITING RUN:cpu 1 1
6* RUN:io READY 1
7 WAITING RUN:cpu 1 1
8 WAITING RUN:cpu 1 1
9 WAITING RUN:cpu 1 1
10 WAITING RUN:cpu 1 1
11* RUN:cpu READY 1
12 DONE RUN:cpu 1
13 DONE RUN:cpu 1
14 DONE RUN:cpu 1
15 DONE RUN:cpu 1
16 DONE RUN:cpu 1
17 DONE RUN:cpu 1
18 DONE RUN:cpu 1
19 DONE RUN:cpu 1
20 DONE RUN:cpu 1
21 DONE RUN:cpu 1
22 DONE RUN:cpu 1
23 DONE RUN:cpu 1
A considerable improvement. I think it would be more considerable if the number of IO tasks for the first process grows bigger.
So we might draw the conclusion that -S SWITCH_ON_END would be a disaster if there is too much IO; and -IIO_RUN_LATER would be a disaster if there is a huge difference for the ratio of IO tasks and CPU tasks for each processes.
Thanks for your reading. Leave a comment if you have any idea, question or mistakes found in the post.