<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Satoru Takeuchi</title>
    <description>The latest articles on DEV Community by Satoru Takeuchi (@satorutakeuchi).</description>
    <link>https://dev.to/satorutakeuchi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F149780%2Fb9809ef5-02e4-4a37-a8e5-31a3cd7fc64f.jpg</url>
      <title>DEV Community: Satoru Takeuchi</title>
      <link>https://dev.to/satorutakeuchi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/satorutakeuchi"/>
    <language>en</language>
    <item>
      <title>How Linux Works: Chapter 3 Process Scheduler (Part 3)</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Sat, 27 Jul 2024 03:45:02 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-3-cif</link>
      <guid>https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-3-cif</guid>
      <description>&lt;h2&gt;
  
  
  Context Switch
&lt;/h2&gt;

&lt;p&gt;Switching the process running on a logical CPU is called a 'context switch.' The following figure shows a context switch when Process 0 and Process 1 are present.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmihahjxflfhauuh0r4w1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmihahjxflfhauuh0r4w1.jpg" alt="Context switch" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Context switches occur without mercy, regardless of the code the process runs when its timeslice expires. Without understanding this, it is easy to misunderstand as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1g6cob1r0wuccczuai1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1g6cob1r0wuccczuai1.jpg" alt="Wrong understanding about context switches" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But in reality, there is no guarantee that bar() will be executed immediately after foo(). If the timeslice expires right after the execution of foo(), the execution of bar() could occur sometime later. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rsnnh12yv4pjrq9zpwd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rsnnh12yv4pjrq9zpwd.jpg" alt="Correst understanding about context switches" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Understanding this can provide a different perspective when a certain operation takes longer than expected to complete. Rather than rashly concluding that there must be a problem with the operation itself, one could consider the possibility that a context switch occurred during the operation and another process was running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Complying with the system's performance requirements is important. For instance, the following indicators are used for this purpose.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turnaround Time: The time from when the system is asked to process until each process is finished.&lt;/li&gt;
&lt;li&gt;Throughput: The number of processes that can be completed per unit of time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's measure these values. Here, we will get the following performance information for the &lt;code&gt;measure.sh&lt;/code&gt; program.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Average Turnaround Time: The average value of the 'real' values of all &lt;code&gt;load.sh&lt;/code&gt; processes, which just consumes CPU times.&lt;/li&gt;
&lt;li&gt;Throughput: The number of processes over'real' value of the &lt;code&gt;multiload.sh&lt;/code&gt; program.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To obtain this information, we use the &lt;code&gt;cpuperf.sh&lt;/code&gt; program.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cpuperf.sh
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

usage() {
    exec &amp;gt;&amp;amp;2
    echo "Usage: $0 [-m] &amp;lt;maximum process count&amp;gt;
1. Save performance information to a file named 'cpuperf.data'
  * The number of entries is &amp;lt;maximum process count&amp;gt;
  * The format of each line is '&amp;lt;process count&amp;gt; &amp;lt;average turnaround time [seconds]&amp;gt; &amp;lt;throughput [processes/second]&amp;gt;'
2. Create a graph of the average throughput based on the performance information and save it as 'avg-tat.jpg'
3. Similarly, create a graph of the throughput and save it as 'throughput.jpg'

The -m option is passed directly to the measure program."
    exit 1
}

measure() {
    local nproc=$1
    local opt=$2
    bash -c "time ./multiload.sh $opt $nproc" 2&amp;gt;&amp;amp;1 | grep real | sed -n -e 's/^.*0m\([.0-9]*\)s$/\1/p' | awk -v nproc=$nproc '
BEGIN{
    sum_tat=0
}
(NR&amp;lt;=nproc){
    sum_tat+=$1
}
(NR==nproc+1) {
    total_real=$1
}
END{
    printf("%d\t%.3f\t%.3f\n", nproc, sum_tat/nproc, nproc/total_real)    
}'
}

while getopts "m" OPT ; do
    case $OPT in
        m)
            MEASURE_OPT="-m"
            ;;
        \?)
            usage
            ;;
    esac
done

shift $((OPTIND - 1))

if [ $# -lt 1 ]; then
    usage
fi

rm -f cpuperf.data
MAX_NPROC=$1
for ((i=1;i&amp;lt;=MAX_NPROC;i++)) ; do
    measure $i $MEASURE_OPT  &amp;gt;&amp;gt;cpuperf.data
done

./plot-perf.py $MAX_NPROC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;plot-perf.py
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/python3

import sys
import plot_sched

def usage():
    print("""usage: {} &amp;lt;max_nproc&amp;gt;
    * create graphs from cpuperf.data
    * "avg-tat.jpg": aveage turnaroun time
    * "throughput.jpg: troughput""".format(progname, file=sys.stderr))
    sys.exit(1)

progname = sys.argv[0]

if len(sys.argv) &amp;lt; 2:
    usage()

max_nproc = int(sys.argv[1])
plot_sched.plot_avg_tat(max_nproc)
plot_sched.plot_throughput(max_nproc)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;plot_sched.py
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/python3

import numpy as np
from PIL import Image
import matplotlib
import os

matplotlib.use('Agg')

import matplotlib.pyplot as plt

plt.rcParams['font.family'] = "sans-serif"
plt.rcParams['font.sans-serif'] = "TakaoPGothic"

def plot_avg_tat(max_nproc):
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    x, y, _ = np.loadtxt("cpuperf.data", unpack=True)
    ax.scatter(x,y,s=1)
    ax.set_xlim([0, max_nproc+1])
    ax.set_xlabel("# of processes ")
    ax.set_ylim(0)
    ax.set_ylabel("average turnaround time[s]")

    # Save as png and convert this to jpg to bypass the following bug.
    # https://bugs.launchpad.net/ubuntu/+source/matplotlib/+bug/1897283?comments=all
    pngfilename = "avg-tat.png"
    jpgfilename = "avg-tat.jpg"
    fig.savefig(pngfilename)
    Image.open(pngfilename).convert("RGB").save(jpgfilename)
    os.remove(pngfilename)

def plot_throughput(max_nproc):
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    x, _, y = np.loadtxt("cpuperf.data", unpack=True)
    ax.scatter(x,y,s=1)
    ax.set_xlim([0, max_nproc+1])
    ax.set_xlabel("# of processes")
    ax.set_ylim(0)
    ax.set_ylabel("Throughput[process/s]")

    # Save as png and convert this to jpg to bypass the following bug.
    # https://bugs.launchpad.net/ubuntu/+source/matplotlib/+bug/1897283?comments=all
    pngfilename = "avg-tat.png"
    jpgfilename = "throughput.jpg"
    fig.savefig(pngfilename)
    Image.open(pngfilename).convert("RGB").save(jpgfilename)
    os.remove(pngfilename)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;multiload.sh
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

MULTICPU=0
PROGNAME=$0
SCRIPT_DIR=$(cd $(dirname $0) &amp;amp;&amp;amp; pwd)

usage() {
    exec &amp;gt;&amp;amp;2
    echo "usage: $PROGNAME [-m] &amp;lt;# of processes&amp;gt;
    Run load-testing processes, which just consumes CPU time, and show the elapsed time after waiting for the end of all processes.
    These processes run on one CPU by default.

options:
    -m: allow to run load-testong processes in arbitrary CPUs"
    exit 1
}

while getopts "m" OPT ; do
    case $OPT in
        m)
            MULTICPU=1
            ;;
        \?)
            usage
            ;;
    esac
done

shift $((OPTIND - 1))

if [ $# -lt 1 ] ; then
    usage
fi

CONCURRENCY=$1

if [ $MULTICPU -eq 0 ] ; then
    taskset -p -c 0 $$ &amp;gt;/dev/null
fi

for ((i=0;i&amp;lt;CONCURRENCY;i++)) do
    time "${SCRIPT_DIR}/load.py" &amp;amp;
done

for ((i=0;i&amp;lt;CONCURRENCY;i++)) do
    wait
done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;load.sh
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/python3

NLOOP=100000000

for _ in range(NLOOP):
    pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we'll show the results of limiting the load processing process's execution to one logical CPU and setting the maximum number of processes to 4, i.e., executing &lt;code&gt;./cpuperf 4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3zjtv7k2jpgkggb0og7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3zjtv7k2jpgkggb0og7.jpg" alt="Average Turnaround Time with Maximum of 4 Processes on One Logical CPU" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfwxppvpabfey4432rd1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfwxppvpabfey4432rd1.jpg" alt="Throughput with Maximum of 4 Processes on One Logical CPU" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that increasing the number of processes more than the number of logical CPUs only lengthens the average turnaround time. In addition, it does not improve the throughput.&lt;/p&gt;

&lt;p&gt;If you continue to increase the number of processes, the context switches caused by the scheduler will gradually increase the average turnaround time and decrease the throughput. From a performance perspective, simply increasing the number of processes is not enough when the CPU resources are fully utilized.&lt;/p&gt;

&lt;p&gt;Let's dig a little deeper into the turnaround time. Suppose you have a web application that does the following processing on your system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receives requests from users over The Internet.&lt;/li&gt;
&lt;li&gt;Generates HTML files according to the request.&lt;/li&gt;
&lt;li&gt;Sends the results back to the user over The Internet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If such processing arrives anew in a situation where the load on the logical CPU is high, the average turnaround time will get longer and longer. This directly connects to the response time of the web application operation from the user's perspective, compromising the user experience. For a system that prioritizes response performance, keeping each machine's CPU usage lower than a system that prioritizes throughput is necessary.&lt;/p&gt;

&lt;p&gt;Next, we will collect data for the case where all logical CPUs can be used. The number of logical CPUs can be obtained by the &lt;code&gt;grep -c processor /proc/cpuinfo&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;grep -c processor /proc/cpuinfo
8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the author's environment, there are 8 logical CPUs because it has 4 cores and 2 threads.&lt;/p&gt;

&lt;p&gt;In this experiment, if the system has SMT enabled, we will disable SMT, as shown below. The reason for disabling it will be discussed in another article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;cat /sys/devices/system/cpu/smt/control #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;If the output is &lt;span class="s1"&gt;'on'&lt;/span&gt;, SMT is enabled. If the file does not exist, the CPU does not support SMT &lt;span class="k"&gt;in &lt;/span&gt;the first place.
&lt;span class="go"&gt;on

&lt;/span&gt;&lt;span class="gp"&gt;echo off &amp;gt;&lt;/span&gt;/sys/devices/system/cpu/smt/control
&lt;span class="go"&gt;cat /sys/devices/system/cpu/smt/control
off

grep -c processor /proc/cpuinfo
4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this state, when the maximum number of processes is set to 8 and performance information is collected, namely when &lt;code&gt;./cpuperf.sh -m 8&lt;/code&gt; is executed. The results are shown in the following figure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdmlts4bqktw68h3cebm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdmlts4bqktw68h3cebm.jpg" alt="Average turnaround time when all logical CPUs are utilized and the maximum number of processes is 8" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhkk42tse0sqmgtxdd3tf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhkk42tse0sqmgtxdd3tf.jpg" alt="Throughput when all logical CPUs are utilized and the maximum number of processes is 8" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that the average turnaround time gradually increases until the number of processes equals the number of logical CPUs (4 in this case). However, after that, it increases significantly.&lt;/p&gt;

&lt;p&gt;Next, the degree of parallelism improves until it equals the number of logical CPUs, but then it plateaus. From this, we can say the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Even if a machine has many logical CPUs, its throughput will only improve if a sufficient number of processes run on it.&lt;/li&gt;
&lt;li&gt;Blindly increasing the number of processes will not increase the throughput.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If SMT was enabled before the experiment, it should be re-enabled as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;on &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/sys/devices/system/cpu/smt/control
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The importance of parallel execution of programs is increasing year by year. This is because the approach to improving CPU performance has changed. Once upon a time, with every new generation of CPUs, one could expect a dramatic improvement in the performance per logical CPU, referred to as single-threaded performance. In this case, the processing speed kept increasing without having to modify the program at all. However, the situation has changed over the past decade or so. It has become difficult to improve single-threaded performance due to various circumstances. As a result, when a CPU generation changes, single-threaded performance no longer improves as much as it used to. Instead, the trend has been to increase the total performance of the CPU by increasing the number of CPU cores.&lt;/p&gt;

&lt;p&gt;The kernel has also been improving scalability when increasing the number of cores, which is in line with these changing times. As times change, common sense changes, and software changes to adapt to this new common sense.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-1phi"&gt;previous part&lt;/a&gt;&lt;br&gt;
&lt;a href=""&gt;next part&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  NOTE
&lt;/h1&gt;

&lt;p&gt;This article is based on &lt;a href="https://amzn.to/3K9q9Ke" rel="noopener noreferrer"&gt;my book&lt;/a&gt; written in Japanese. Please contact me via &lt;a href="mailto:satoru.takeuchi@gmail.com"&gt;satoru.takeuchi@gmail.com&lt;/a&gt; if you're interested in publishing this book's English version.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How Linux Works: Chapter 3 Process Scheduler (Part 2)</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Wed, 04 Oct 2023 20:51:12 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-1phi</link>
      <guid>https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-1phi</guid>
      <description>&lt;h1&gt;
  
  
  Time Slice
&lt;/h1&gt;

&lt;p&gt;In the previous section, we found out that the number of processes that can run simultaneously on one CPU is only one. However, we didn't learn how the CPU resources are distributed from the experiment in the previous section. Therefore, in this section, we will confirm through experiments that the scheduler allows executable processes to use the CPU in time slice units.&lt;/p&gt;

&lt;p&gt;We will use a program called sched.py for the experiment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/python3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;plot_sched&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Usage: sched.py &amp;lt;number of processes&amp;gt;
        * After starting &amp;lt;number of processes&amp;gt; load processing processes on logical CPU0, which consume CPU resources for about 100 milliseconds simultaneously, wait for all processes to end.
        * Write out a graph showing the execution results to a file named &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sched-&amp;lt;number of processes&amp;gt;.jpg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.
        * The x-axis of the graph represents elapsed time [milliseconds] from the start of the load processing process, and the y-axis represents progress [%].&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;progname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Find the appropriate load for this experimentation.
# This estimation is expected to take several seconds.
# Please increment/decrement NLOOP_FOR_ESTIMATION if this process takes too long/short time.
&lt;/span&gt;&lt;span class="n"&gt;NLOOP_FOR_ESTIMATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100000000&lt;/span&gt;
&lt;span class="n"&gt;nloop_per_msec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;progname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;estimate_loops_per_msec&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;  &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NLOOP_FOR_ESTIMATION&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NLOOP_FOR_ESTIMATION&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;child_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nloop_per_msec&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;pass&lt;/span&gt;
        &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}.data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;concurrency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;concurrency&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;the number of processes&amp;gt; should be &amp;gt;= 1: {}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Force to run on logical CPU0
&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sched_setaffinity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;nloop_per_msec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;estimate_loops_per_msec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;child_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;plot_sched&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot_sched&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This program continuously runs one or more load-processing processes that use CPU time and collects the following statistical information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At a certain point, which process is running on the logical CPU&lt;/li&gt;
&lt;li&gt;How much progress each one has made&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By analyzing this data, we will check whether the explanation of the scheduler given at the beginning is correct. The specification of the experimental program sched.py is as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Usage: sched &amp;lt;number of processes&amp;gt;
        * After starting &amp;lt;number of processes&amp;gt; load processing processes on logical CPU0, which consume CPU resources for about 100 milliseconds simultaneously, wait for all processes to end.
        * Write out a graph showing the execution results to a file named "sched-&amp;lt;number of processes&amp;gt;.jpg".
        * The x-axis of the graph represents elapsed time [milliseconds] from the start of the load processing process, and the y-axis represents progress [%].
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file plot_sched.py is also used for graph drawing, so if you are running the sched program, please place plot_sched.py in the same directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/python3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;PIL&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;matplotlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Agg&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;

&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rcParams&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;font.family&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sans-serif&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rcParams&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;font.sans-serif&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TakaoPGothic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_sched&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_subplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadtxt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}.data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;unpack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Visualize timeslice(concurrency={})&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;elapsed time[ms]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;progress[%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;legend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;load&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Save the image as png temporarily and convert this to jpg to avoid a bug in matplotlib exists in Ubuntu 20.04.
&lt;/span&gt;    &lt;span class="c1"&gt;# https://bugs.launchpad.net/ubuntu/+source/matplotlib/+bug/1897283?comments=all
&lt;/span&gt;    &lt;span class="n"&gt;pngfilename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sched-{}.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;jpgfilename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sched-{}.jpg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;savefig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RGB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jpgfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_avg_tat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_nproc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_subplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadtxt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpuperf.data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unpack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_nproc&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;concurrency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;average turn around time[秒]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Save the image as png temporarily and convert this to jpg to avoid a bug in matplotlib exists in Ubuntu 20.04.
&lt;/span&gt;    &lt;span class="c1"&gt;# https://bugs.launchpad.net/ubuntu/+source/matplotlib/+bug/1897283?comments=all
&lt;/span&gt;    &lt;span class="n"&gt;pngfilename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;avg-tat.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;jpgfilename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;avg-tat.jpg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;savefig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RGB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jpgfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_throughput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_nproc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_subplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadtxt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpuperf.data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unpack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_nproc&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;concurrency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;throughput[process/秒]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Save the image as png temporarily and convert this to jpg to avoid a bug in matplotlib exists in Ubuntu 20.04.
&lt;/span&gt;    &lt;span class="c1"&gt;# https://bugs.launchpad.net/ubuntu/+source/matplotlib/+bug/1897283?comments=all
&lt;/span&gt;    &lt;span class="n"&gt;pngfilename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;avg-tat.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;jpgfilename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;throughput.jpg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;savefig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RGB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jpgfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pngfilename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This program will be executed with parallelism of 1, 2, and 3, respectively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;for i in 1 2 3 ;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt; ./sched &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The results are shown in the following figures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy4xblobvro445w4xv5h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy4xblobvro445w4xv5h.jpg" alt="Image description" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycrjwxq81vmjehnhpkps.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycrjwxq81vmjehnhpkps.jpg" alt="Image description" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78jzj8q86vqdre28bf7c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78jzj8q86vqdre28bf7c.jpg" alt="Image description" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These graphs show that when multiple processes are running on a single logical CPU, each process is using the CPU alternately in time slices of a few milliseconds.&lt;/p&gt;

&lt;h1&gt;
  
  
  Column: How Time Slices Work
&lt;/h1&gt;

&lt;p&gt;Looking closely at Figure XX, you can see that each process's time slice is shorter when  is 3 compared to when it's 2. In fact, Linux's scheduler is designed to ensure that CPU time is obtained once per period, called a latency target, which is indicated by the value of the sysctl parameter kernel.sched_latency_ns (in nanoseconds).&lt;/p&gt;

&lt;p&gt;In the author's environment, this parameter is set to the following value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sysctl kernel.sched_latency_ns
&lt;span class="gp"&gt;kernel.sched_latency_ns = 24000000  #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;24000000/1000000 &lt;span class="o"&gt;=&lt;/span&gt; 24 milliseconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The time slice for each process is kernel.sched_latency_ns /  [nanoseconds].&lt;/p&gt;

&lt;p&gt;The relationship between the latency target and the time slice when there are 1 to 3 executable processes on a logical CPU is shown in the following figure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqy205ge62i0dvp6er1k7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqy205ge62i0dvp6er1k7.jpg" alt="Image description" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the scheduler of the Linux kernel before 2.6.23, the time slice was a fixed value (100 milliseconds), but this posed a problem as CPU time wouldn't efficiently rotate between processes when the number of processes increased. To improve this issue, the current scheduler adjusts the time slice according to the number of processes.&lt;/p&gt;

&lt;p&gt;The calculation of the latency target and time slice values becomes slightly more complicated with &lt;/p&gt;

&lt;p&gt;increasing numbers of processes or in the case of multicore CPUs, varying depending on elements such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The number of logical CPUs equipped in the system&lt;/li&gt;
&lt;li&gt;The number of processes running/waiting on logical CPUs exceeding a certain value&lt;/li&gt;
&lt;li&gt;The nice value that represents the priority of the process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this section, we will discuss the effect of the nice value. The nice value is a setting that defines the execution priority of a process within a range from "-20" to "19" (the default is "0"). -20 is the highest priority and 19 is the lowest. Any user can lower the priority, but only users with root privileges can raise it.&lt;/p&gt;

&lt;p&gt;The nice value can be changed using the nice command, renice command, nice() system call, setpriority() system call, and so on. The scheduler gives more time slices to processes with a low nice value (i.e., a high priority).&lt;/p&gt;

&lt;p&gt;Let's try running the nice sched_nice.py p with the following specifications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Usage: sched_nice.py &amp;lt;nice value&amp;gt;
        * After launching two load processing processes that consume about 100 milliseconds of CPU resources on logical CPU0, wait for both processes to finish.
        * The nice values of load processes 0 and 1 are set to 0 (default) and &amp;lt;nice value&amp;gt;, respectively.
        * Writes a graph showing the execution result to a file named "sched-2.jpg".
        * The x-axis of the graph represents the elapsed time from the start of the process [milliseconds], and the y-axis represents the progress [%].
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The source code is here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/python3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;plot_sched&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Usage: sched_nice.py &amp;lt;nice value&amp;gt;
        * After launching two load processing processes that consume about 100 milliseconds of CPU resources on logical CPU0, wait for both processes to finish.
        * The nice values of load processes 0 and 1 are set to 0 (default) and &amp;lt;nice value&amp;gt;, respectively.
        * Writes a graph showing the execution result to a file named &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sched-2.jpg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.
        * The x-axis of the graph represents the elapsed time from the start of the process [milliseconds], and the y-axis represents the progress [%].&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;progname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Find the appropriate load for this experimentation.
# This estimation is expected to take several seconds.
# Please increment/decrement NLOOP_FOR_ESTIMATION if this process takes too long/short time.
&lt;/span&gt;&lt;span class="n"&gt;NLOOP_FOR_ESTIMATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100000000&lt;/span&gt;
&lt;span class="n"&gt;nloop_per_msec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;progname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;estimate_loops_per_msec&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;  &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NLOOP_FOR_ESTIMATION&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NLOOP_FOR_ESTIMATION&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;child_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nloop_per_msec&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;pass&lt;/span&gt;
        &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}.data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;nice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;concurrency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;concurrency&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;the number of processes&amp;gt; should be &amp;gt;= 1: {}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Force running on logical CPU0
&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sched_setaffinity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;nloop_per_msec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;estimate_loops_per_msec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;concurrency&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;child_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;plot_sched&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot_sched&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, let's specify 5 for .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./sched-nice 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The results are shown in the following graph.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiufgxbyus7eh5hprb1o0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiufgxbyus7eh5hprb1o0.jpg" alt="Image description" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As expected, you can see that load process 0 has more time slices than load process 1.&lt;/p&gt;

&lt;p&gt;By the way, the "%nice" field in the output of sar shows the proportion of time that processes with a priority lower than the default value of 0 are executing in user mode (%user is for nice value 0). Let's run the inf-loop program we used in Chapter XX with a lowered priority (we'll set it to 5 here), and check the CPU usage with sar at that time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;nice&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 5 taskset &lt;span class="nt"&gt;-c&lt;/span&gt; 0 ./inf-loop &amp;amp;
&lt;span class="go"&gt;[1] 168376
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sar &lt;span class="nt"&gt;-P&lt;/span&gt; 0 1 1
&lt;span class="go"&gt;Linux 5.4.0-74-generic (coffee)         2021年12月04日  _x86_64_        (8 CPU)

05時57分58秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
05時57分59秒       0      0.00    100.00      0.00      0.00      0.00      0.00
Average:          0      0.00    100.00      0.00      0.00      0.00      0.00
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;kill &lt;/span&gt;168376
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that it's not %user, but %nice that has reached 100.&lt;/p&gt;

&lt;p&gt;Note that what we have discussed in this column is not defined by standards such as POSIX, so it may change as the kernel version changes. For example, the default value of kernel.sched_latency_ns has been changed many times in the past. Please be aware that even if you tune your system depending on the behavior mentioned here, it may not necessarily be effective in the future.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-115d"&gt;previous part&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-3-cif"&gt;next part&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  NOTE
&lt;/h1&gt;

&lt;p&gt;This article is based on &lt;a href="https://amzn.to/3K9q9Ke" rel="noopener noreferrer"&gt;my book&lt;/a&gt; written in Japanese. Please contact me via &lt;a href="mailto:satoru.takeuchi@gmail.com"&gt;satoru.takeuchi@gmail.com&lt;/a&gt; if you're interested in publishing this book's English version.&lt;/p&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>How Linux Works: Chapter2 Process Management (Part3)</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Sat, 10 Jun 2023 04:49:54 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part3-12ip</link>
      <guid>https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part3-12ip</guid>
      <description>&lt;h1&gt;
  
  
  Job control in Shell
&lt;/h1&gt;

&lt;p&gt;In this section, we will explain the concepts of sessions and process groups, which exist for the implementation of shell's job control.&lt;/p&gt;

&lt;p&gt;For those unfamiliar with jobs, a job is a mechanism that shells like bash use to control processes running in the background. For example, you might use it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;infinity &amp;amp;
&lt;span class="gp"&gt;[1] 6176 #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;1] is the job number
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;infinity &amp;amp;
&lt;span class="gp"&gt;[2] 6200 #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;2] is the job number
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;jobs&lt;/span&gt; &lt;span class="c"&gt;# List the jobs&lt;/span&gt;
&lt;span class="go"&gt;[1]-  Running                 sleep infinity &amp;amp;
[2]+  Running                 sleep infinity &amp;amp;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;fg &lt;/span&gt;1 &lt;span class="c"&gt;# Make job 1 the foreground job&lt;/span&gt;
&lt;span class="go"&gt;sleep infinity
&lt;/span&gt;&lt;span class="gp"&gt;^Z #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Press Ctrl+z and control returns to bash
&lt;span class="go"&gt;[1]+  Stopped                 sleep infinity
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sessions
&lt;/h2&gt;

&lt;p&gt;A session corresponds to a login session when a user logs into the system through a terminal emulator like &lt;code&gt;gterm&lt;/code&gt; or &lt;code&gt;ssh&lt;/code&gt;. All sessions have a terminal attached for controlling the session. When you want to operate processes within the session, you instruct them through the terminal to processes, including the shell, and receive the output from these processes. Normally, a virtual terminal named &lt;code&gt;pty/&amp;lt;n&amp;gt;&lt;/code&gt; is assigned to each session.&lt;/p&gt;

&lt;p&gt;Let's consider a situation where three sessions exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alice's session: The login shell is &lt;code&gt;bash&lt;/code&gt;. Developing a Go program with &lt;code&gt;vim&lt;/code&gt; on it, and currently building some program with &lt;code&gt;go build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bob's session 1: The login shell is &lt;code&gt;zsh&lt;/code&gt;. Using &lt;code&gt;ps aux&lt;/code&gt; on it to list all processes in the system, and receiving the results with &lt;code&gt;less&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bob's session 2: The login shell is &lt;code&gt;zsh&lt;/code&gt;. Running a custom calculation program called &lt;code&gt;calc&lt;/code&gt; on it."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This situation can be illustrated as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhop06lzump37edajqd24.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhop06lzump37edajqd24.jpg" alt="Example of sessions" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each session is assigned a unique value, called a "session ID" (or "SID"). Each session has a process called a session leader, which is typically a shell like &lt;code&gt;bash&lt;/code&gt;. The PID of the session leader equals the ID of the session. Information about the session can be obtained by &lt;code&gt;ps ajx&lt;/code&gt;. In the author's environment, it is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps ajx
&lt;span class="go"&gt;   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;  19261   19262   19262   19262 pts/0      19647 Ss    1000   0:00 -bash
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;  19262   19647   19647   19262 pts/0      19647 R+    1000   0:00 ps ajx
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we can see that there is a session (SID=19262) with &lt;code&gt;bash(19262)&lt;/code&gt; as the session leader, and &lt;code&gt;ps ajx&lt;/code&gt; (PID=19647) belongs to this session. Commands launched from &lt;code&gt;bash(19262)&lt;/code&gt; normally belong to this session. The &lt;code&gt;TTY&lt;/code&gt; field in &lt;code&gt;ps ajx&lt;/code&gt;, and in &lt;code&gt;ps aux&lt;/code&gt; used in previous sections, is the name of the terminal. In this session, a virtual terminal &lt;code&gt;pts/0&lt;/code&gt; is assigned.&lt;/p&gt;

&lt;p&gt;When the terminal associated with the session hangs up, a &lt;code&gt;SIGHUP&lt;/code&gt; is sent to the session leader. This happens when the terminal emulator's window is closed. &lt;code&gt;bash&lt;/code&gt; will terminate its managed jobs and then terminate itself in this case. For cases where it would be a problem if &lt;code&gt;bash&lt;/code&gt; terminated while a long-running process was executing, the following measures can be used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;nohup&lt;/code&gt; command: Launches a process with the setting to ignore &lt;code&gt;SIGHUP&lt;/code&gt;. Even if the session terminates and a &lt;code&gt;SIGHUP&lt;/code&gt; is sent afterward, the process does not terminate.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;disown&lt;/code&gt; built-in command of &lt;code&gt;bash&lt;/code&gt;: Removes a running job from &lt;code&gt;bash&lt;/code&gt;'s management. As a result, even if &lt;code&gt;bash&lt;/code&gt; terminates, a &lt;code&gt;SIGHUP&lt;/code&gt; will not be sent to the job.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Process Groups
&lt;/h2&gt;

&lt;p&gt;Process groups are used to control multiple processes collectively. Within a session, there exist several process groups. Essentially, you can think of the jobs created by the shell as corresponding to process groups&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;To be more precise, the shell itself also has its own process group, but for the sake of simplicity, we will omit this from the current discussion. &lt;/p&gt;

&lt;p&gt;Let's illustrate process groups with an example. Suppose a session is set up as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The login shell is &lt;code&gt;bash&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;From the above &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;go build &amp;lt;source name&amp;gt; &amp;amp;&lt;/code&gt; is executed.&lt;/li&gt;
&lt;li&gt;From the above &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;ps aux | less&lt;/code&gt; is executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case, bash creates two process groups (jobs) corresponding to &lt;code&gt;go build &amp;lt;source name&amp;gt; &amp;amp;&lt;/code&gt; and &lt;code&gt;ps aux | less&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With process groups, signals can be thrown to all processes belonging to a certain process group. The shell uses this feature for job control. If you specify a negative value for the process ID argument of the &lt;code&gt;kill&lt;/code&gt; command, you can send a signal to the process group. For example, if you want to send a signal to a process group with a PGID of 100, you can do so with &lt;code&gt;kill -100&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Process groups within a session can be divided into two types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Foreground process group: Corresponds to the foreground job in the shell. Only one exists in a session and has direct access to the session's terminal.&lt;/li&gt;
&lt;li&gt;Background process group: Corresponds to the background job in the shell. When a background process tries to operate the terminal, it temporarily suspends execution as when it receives a &lt;code&gt;SIGSTOP&lt;/code&gt;, and this state continues until it becomes a foreground process group (or a foreground job) by commands such as the &lt;code&gt;fg&lt;/code&gt; built-in command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The latter, the foreground process group (foreground job), is the one that can access the terminal directly. This is illustrated as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wl9gdmi0555s65node1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wl9gdmi0555s65node1.jpg" alt="Relationship between session, process group, and job" width="792" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each process group is assigned a unique ID known as a PGID. This value can be confirmed by the &lt;code&gt;PGID&lt;/code&gt; field in &lt;code&gt;ps ajx&lt;/code&gt;. In my environment, it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps ajx | less
&lt;span class="go"&gt;   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;  19261   19262   19262   19262 pts/0      19653 Ss    1000   0:00 -bash
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;  19262   19653   19653   19262 pts/0      19653 R+    1000   0:00 ps ajx
  19262   19654   19653   19262 pts/0      19653 S+    1000   0:00 less
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the output, we can see that there is a login session led by &lt;code&gt;bash(19262)&lt;/code&gt;, within which there is a process group with a PGID of 19653. The constituents of this group are &lt;code&gt;ps ajx(19653)&lt;/code&gt; and &lt;code&gt;less(19654)&lt;/code&gt;, which is piped to it.&lt;/p&gt;

&lt;p&gt;Lastly, let me also mention how to distinguish foreground process groups. In the output of &lt;code&gt;ps ajx&lt;/code&gt;, the processes belonging to the foreground process group have a &lt;code&gt;+&lt;/code&gt; in their &lt;code&gt;STAT&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;The concepts of sessions and process groups can be challenging,&lt;/p&gt;

&lt;h1&gt;
  
  
  Daemons
&lt;/h1&gt;

&lt;p&gt;You might have heard the term "daemon" in the context of UNIX or Linux countless times. This section will discuss what daemons are and how they differ from regular processes. Simply put, daemons are resident processes. While regular processes are expected to terminate after completing a series of operations initiated by a user, daemons do not necessarily behave this way and may persist from system start to finish, depending on the case.&lt;/p&gt;

&lt;p&gt;Daemons have the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They do not require terminal I/O, so no terminal is assigned to them.&lt;/li&gt;
&lt;li&gt;They possess their own session to remain unaffected even if all login sessions end.&lt;/li&gt;
&lt;li&gt;Init acts as their parent process so that the process generating the daemon does not need to worry about the daemon's termination.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If illustrated, it would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9p8rnumbh3z1220e102d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9p8rnumbh3z1220e102d.jpg" alt="Daemon" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, even if they do not meet the above conditions, they may be referred to as daemons if they are resident processes.&lt;/p&gt;

&lt;p&gt;You can determine whether a process is a daemon by looking at the results of &lt;code&gt;ps ajx&lt;/code&gt;. Let's take a look at &lt;code&gt;sshd&lt;/code&gt;, which operates as an ssh server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps ajx
&lt;span class="go"&gt;   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;      1     960     960     960 ?             -1 Ss       0   0:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, the parent process is init (PPID is 1), and the session ID equals the PID.&lt;/p&gt;

&lt;p&gt;Because daemons do not possess a terminal, the SIGHUP, which signifies a terminal hang-up, can be utilized for different purposes. By convention, it is often used as a signal for daemons to reread their configuration files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part2-5816"&gt;previous part&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-115d"&gt;next part&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  NOTE
&lt;/h1&gt;

&lt;p&gt;This article is based on &lt;a href="https://amzn.to/3K9q9Ke" rel="noopener noreferrer"&gt;my book&lt;/a&gt; written in Japanese. Please contact me via &lt;a href="mailto:satoru.takeuchi@gmail.com"&gt;satoru.takeuchi@gmail.com&lt;/a&gt; if you're interested in publishing this book's English version.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>linux</category>
      <category>process</category>
      <category>management</category>
    </item>
    <item>
      <title>How Linux Works: Chapter2 Process Management (Part2)</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Sat, 10 Jun 2023 04:41:38 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part2-5816</link>
      <guid>https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part2-5816</guid>
      <description>&lt;h1&gt;
  
  
  The Relationship between Parent Process and Child Process
&lt;/h1&gt;

&lt;p&gt;In the previous section, we discussed how a parent process generates child processes to create new processes. So where does one end up when following the parent process of the parent process...? This section will clarify this.&lt;/p&gt;

&lt;p&gt;When you boot your computer, the system is initialized in the following order:&lt;/p&gt;

&lt;p&gt;1.Turn on the power switch&lt;br&gt;
2.Firmware, such as BIOS or UEFI, boots up and initializes the hardware&lt;br&gt;
3.The firmware launches a bootloader like GRUB&lt;br&gt;
4.The bootloader launches the OS kernel. Here we'll consider the Linux kernel&lt;br&gt;
5.The Linux kernel starts the init process&lt;br&gt;
6.The init process starts child processes, which in turn start their child processes, and so on, forming a tree structure of processes&lt;/p&gt;

&lt;p&gt;Let's check if this is actually happening.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;pstree&lt;/code&gt; command displays the parent-child relationship of processes in a tree structure. &lt;code&gt;pstree&lt;/code&gt; displays only command names by default, but it is useful to also display the PID by adding the &lt;code&gt;-p&lt;/code&gt; option. In my environment, it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pstree &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;span class="go"&gt;systemd(1)-+-ModemManager(688)-+-{ModemManager}(723)
           |                   `-{ModemManager}(728)
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;           ├─sshd(960)───sshd(19191)───sshd(19261)───bash(19262)───pstree(19638)
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that the ancestor of all processes is the init process with pid=1 (displayed as &lt;code&gt;systemd&lt;/code&gt; on the &lt;code&gt;pstree&lt;/code&gt; command). You can also see, for example, that the &lt;code&gt;pstree(19638)&lt;/code&gt; was run from &lt;code&gt;bash(19262)&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  States of Processes
&lt;/h1&gt;

&lt;p&gt;In this section, we will discuss the concept of process states.&lt;/p&gt;

&lt;p&gt;As already mentioned, there are always a large number of processes in a Linux system. Do these processes always use the CPU continuously? The answer is no.&lt;/p&gt;

&lt;p&gt;The start time of a process running on the system, as well as the total amount of CPU time used, can be checked with the &lt;code&gt;START&lt;/code&gt; field and &lt;code&gt;TIME&lt;/code&gt; field of &lt;code&gt;ps aux&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps aux
&lt;span class="go"&gt;USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;sat        19262  0.0  0.0  12888  6144 pts/0    Ss   18:24   0:00 -bash
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this output, it can be seen that &lt;code&gt;bash(19262)&lt;/code&gt; started at 18:24 and has used almost no CPU time since then. The time at which I am writing this manuscript is around 20:00, so even though it has been over an hour since it was started, you can see that this process has used less than a second of CPU time. The same can be said for many other processes, which I will omit here.&lt;/p&gt;

&lt;p&gt;So, what were these processes mainly doing after they started? They were sleeping, waiting for some event to occur without using the CPU. In the case of &lt;code&gt;bash(19262)&lt;/code&gt;, it was waiting for user input, as there was nothing to do until the user input something. This can be seen from the STAT field of the ps output. A process with an &lt;code&gt;S&lt;/code&gt; in the first character of the STAT field is in a sleep state.&lt;/p&gt;

&lt;p&gt;On the other hand, a process that wants to use the CPU is said to be in a runnable state. At this time, the first character of STAT becomes &lt;code&gt;R&lt;/code&gt;. When a process is actually using the CPU, it is said to be in a running state. How a process transitions between a running state and a runnable state will be discussed in the "Time Slices" and "Context Switches" sections of Chapter 3.&lt;/p&gt;

&lt;p&gt;When a process terminates, it becomes a zombie state (STAT field is &lt;code&gt;Z&lt;/code&gt;), and then it disappears. The meaning of the zombie state will be explained later.&lt;/p&gt;

&lt;p&gt;The states of a process are summarized in the following figure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Freay5ohfken9qn1bm0d3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Freay5ohfken9qn1bm0d3.jpg" alt="States of a process" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As can be seen from this figure, a process transitions through various states during its lifetime.&lt;/p&gt;

&lt;p&gt;If all processes on the system are in a sleep state, what is happening on the logical CPU? In fact, at this time, a special process called an idle process that "does nothing" is operating on the logical CPU. The idle process is not visible from &lt;code&gt;ps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The simplest implementation of an idle process is to perform a wasteful loop until a new process is created or a sleeping process wakes up. However, this wastes power consumption, so it's not usually done. Instead, it uses a special CPU instruction to put the logical CPU into a sleep state, waiting in a state that reduces power consumption until one or more processes become runnable.&lt;/p&gt;

&lt;p&gt;One of the main reasons why the battery lasts longer on your notebook PC or smartphone when you are not running any programs is because the logical CPU spends a lot of time in an idle state, which reduces power consumption.&lt;/p&gt;

&lt;h1&gt;
  
  
  Process Termination
&lt;/h1&gt;

&lt;p&gt;In this section, we'll discuss how a process is terminated by invoking a system call called &lt;code&gt;exit_group()&lt;/code&gt;. Like &lt;code&gt;fork&lt;/code&gt; or &lt;code&gt;fork-and-exec&lt;/code&gt;, when you call the &lt;code&gt;exit()&lt;/code&gt; function, this system call is internally invoked. Even if the program itself doesn't call it, libc or other libraries will do so internally. Within &lt;code&gt;exit_group()&lt;/code&gt;, the kernel reclaims resources such as memory used by the process (see the following figure).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7lq6wzledce9jdlocbow.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7lq6wzledce9jdlocbow.jpg" alt="Memory reclaim on process termination" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a process has terminated, the parent process can obtain the following information through system calls such as &lt;code&gt;wait()&lt;/code&gt; or &lt;code&gt;waitpid()&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The process's return value. This is equal to the remainder when the argument to the &lt;code&gt;exit()&lt;/code&gt; function is divided by 256. To make it clearer, if you specify a number between 0 and 255 as the argument to &lt;code&gt;exit()&lt;/code&gt;, the return value will be the same as the argument.&lt;/li&gt;
&lt;li&gt;Whether the process was terminated by a signal (discussed later)&lt;/li&gt;
&lt;li&gt;How much CPU time the process used before termination&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Through this mechanism, for example, you can handle anomalies such as outputting error logs if a process has terminated abnormally based on its return value.&lt;/p&gt;

&lt;p&gt;In bash, you can obtain the termination status of a process that has been run in the background using the &lt;code&gt;wait&lt;/code&gt; built-in command, which internally calls the &lt;code&gt;wait()&lt;/code&gt; system call. Below, we run the &lt;code&gt;wait-ret.sh&lt;/code&gt;  program, which retrieves and outputs the return value of the always-return-1 &lt;code&gt;false&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

false &amp;amp;
wait $! # wait for the termination of "false" process. We can get the PID of this program through `$!` variable.
echo "The false command has terminated: $?" # We can get the exit state of the process from `$?` variable.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./wait-ret
&lt;span class="go"&gt;The false command has terminated: 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Zombie Processes and Orphan Processes
&lt;/h1&gt;

&lt;p&gt;The fact that a parent process can obtain the state of a child process through &lt;code&gt;wait()&lt;/code&gt; system calls implies that, conversely, a child process exists in some form on the system from the time it terminates until its parent process invokes these system calls. A process that has terminated but whose parent has not obtained its termination status is called a zombie process. The name probably comes from the state of being 'dead but not dead', which is indeed a quite vivid term.&lt;/p&gt;

&lt;p&gt;Generally, a parent process needs to appropriately reclaim the termination status of its child processes to prevent the system from overflowing with zombie processes and squandering resources. If there are a large number of zombie processes on the system during system operation, it may be worthwhile to suspect a bug in the program corresponding to the parent process.&lt;/p&gt;

&lt;p&gt;If the parent of a process terminates before &lt;code&gt;wait()&lt;/code&gt;, the process becomes an orphan process. The kernel makes &lt;code&gt;init&lt;/code&gt; the new parent of the orphan process. If the parent of a zombie process terminates, the zombie process attacks &lt;code&gt;init&lt;/code&gt;. This isn't a pleasant situation for &lt;code&gt;init&lt;/code&gt;. However, &lt;code&gt;init&lt;/code&gt; is smart and regularly issues &lt;code&gt;wait()&lt;/code&gt; to reclaim system resources. It's quite a well-implemented system.&lt;/p&gt;

&lt;h1&gt;
  
  
  Signals
&lt;/h1&gt;

&lt;p&gt;Processes generally run continuously according to a single stream of execution. Although there are conditional branch instructions, these merely shift the flow according to predefined conditional statements. In contrast, a signal is a mechanism for a process to notify another process and forcibly change the flow of execution from the outside.&lt;/p&gt;

&lt;p&gt;There are several types of signals, but the most commonly used is undoubtedly &lt;code&gt;SIGINT&lt;/code&gt;. This signal is sent when you press &lt;code&gt;Ctrl+c&lt;/code&gt; in a shell like &lt;code&gt;bash&lt;/code&gt;. By default, a process that receives &lt;code&gt;SIGINT&lt;/code&gt; terminates immediately. Regardless of how the program is structured, the ability to terminate a process the instant a signal is issued is convenient, and many Linux users use this signal, whether they are aware of its effect or not.&lt;/p&gt;

&lt;p&gt;Signals can also be sent from outside &lt;code&gt;bash&lt;/code&gt; using the &lt;code&gt;kill&lt;/code&gt; command. For example, if you want to send &lt;code&gt;SIGINT&lt;/code&gt;, execute &lt;code&gt;kill -INT &amp;lt;pid&amp;gt;&lt;/code&gt;. In addition to &lt;code&gt;SIGINT&lt;/code&gt;, there are signals like the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SIGCHLD&lt;/code&gt;: Sent to the parent process when a child process terminates. It's common to call &lt;code&gt;wait()&lt;/code&gt; within this signal handler.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SIGSTOP&lt;/code&gt;: Temporarily suspends the execution of a process. Pressing &lt;code&gt;Ctrl+z&lt;/code&gt; on &lt;code&gt;bash&lt;/code&gt; halts the execution of the running program. At this time, &lt;code&gt;bash&lt;/code&gt; is sending this signal to the process.
"- &lt;code&gt;SIGCONT&lt;/code&gt;: Resumes the execution of a process that was stopped by &lt;code&gt;SIGSTOP&lt;/code&gt; or similar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see a list of signals by running the &lt;code&gt;man 7 signal&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;As I wrote earlier that 'a process that receives &lt;code&gt;SIGINT&lt;/code&gt; will terminate by default', it does not mean that a process will always terminate when it receives the &lt;code&gt;SIGINT&lt;/code&gt; signal. A process can pre-register a signal handler for each signal. If the process receives the corresponding signal during execution, it temporarily interrupts the current operation, activates the signal handler, and then returns to the original location and resumes operation. Alternatively, it can be set to ignore the signal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wvyced2v6mneae3zwff.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wvyced2v6mneae3zwff.jpg" alt="Behavior of a process upon receipt of a signal" width="776" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By using a signal handler, you can create an annoying program (&lt;code&gt;intignore.py&lt;/code&gt;) that does not terminate even when &lt;code&gt;Ctrl+c&lt;/code&gt; is pressed. For example, you can create it in Python like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/python3

import signal

# Set to ignore SIGINT
# - 1st arg: The signal to ignore
# - 2nd arg: signal handler
signal.signal(signal.SIGINT, signal.SIG_IGN)

while True:
    pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run this program, it will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./intignore.py
&lt;span class="go"&gt;^C^C^C
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;^C&lt;/code&gt; indicates that you've typed &lt;code&gt;Ctrl+c&lt;/code&gt;. It's really annoying, isn't it?"&lt;/p&gt;

&lt;p&gt;If you've tried this command yourself, please send &lt;code&gt;intignore&lt;/code&gt; to the background with &lt;code&gt;Ctrl+z&lt;/code&gt; and then kill it with &lt;code&gt;kill&lt;/code&gt;. At this time, the default &lt;code&gt;SIGTERM&lt;/code&gt; is thrown, so it can terminate.&lt;/p&gt;

&lt;h1&gt;
  
  
  Column: The Absolutely Lethal SIGKILL Signal and the Absolutely Indestructible Process
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;SIGKILL&lt;/code&gt; could be considered the last resort to use when a process does not die gracefully by other signals like &lt;code&gt;SIGINT&lt;/code&gt;. This is a special one among all signals, as a process that receives this signal is always terminated. It is not possible to change the behavior through a signal handler. From the signal name &lt;code&gt;KILL&lt;/code&gt;, you can feel the strong intention to definitely kill the process.&lt;/p&gt;

&lt;p&gt;However, after writing all this, there are occasionally nefarious processes that won't die, even with &lt;code&gt;SIGKILL&lt;/code&gt;. For some reason, these processes are in a special state called &lt;code&gt;uninterruptible sleep&lt;/code&gt;, where they do not accept signals for a long time. The first character in the &lt;code&gt;STAT&lt;/code&gt; field of &lt;code&gt;ps aux&lt;/code&gt; for these processes is &lt;code&gt;D&lt;/code&gt;. This often occurs when disk I/O takes a long time. It may also be due to some problem with the kernel. In any case, there is often nothing that can be done from the user's side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part1-3n71"&gt;previous part&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-115d"&gt;next part&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  NOTE
&lt;/h1&gt;

&lt;p&gt;This article is based on &lt;a href="https://amzn.to/3K9q9Ke" rel="noopener noreferrer"&gt;my book&lt;/a&gt; written in Japanese. Please contact me via &lt;a href="mailto:satoru.takeuchi@gmail.com"&gt;satoru.takeuchi@gmail.com&lt;/a&gt; if you're interested in publishing this book's English version.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>process</category>
      <category>management</category>
    </item>
    <item>
      <title>How Linux Works: Chapter 3 Process Scheduler (Part 1)</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Fri, 02 Jun 2023 01:48:18 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-115d</link>
      <guid>https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-115d</guid>
      <description>&lt;p&gt;In Chapter 2, we mentioned that most processes in the system are in the sleep state. So, how does the kernel make each process run on the CPU when there are multiple executable processes in the system? In this chapter, we will discuss the Linux kernel's process scheduler (hereinafter referred to as the scheduler), which is responsible for allocating CPU resources to processes.&lt;/p&gt;

&lt;p&gt;In books about computer science, the scheduler is explained as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only one process can run at a time on a single logical CPU&lt;/li&gt;
&lt;li&gt;It allows multiple executable processes to use the CPU in turn, in units called "time slices"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if there are three processes, p0, p1, and p2, it would look like the following figure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs28zk13p93h2ieqas6w0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs28zk13p93h2ieqas6w0.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's confirm whether this is actually the case in Linux by conducting an experiment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Elapsed Time and CPU Time
&lt;/h1&gt;

&lt;p&gt;To understand the content of this chapter, it is essential to understand the concepts of elapsed time and CPU time related to processes. This section explains these times. Their definitions are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Elapsed Time: The time that passes from the start to the end of a process. It is like the time measured with a stopwatch from the start to the end of a process.&lt;/li&gt;
&lt;li&gt;CPU Time: The time that a process actually uses a logical CPU.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These terms probably won't make much sense just by looking at the explanation, so let's understand them through an experiment. If you run a process using the time command, you can get the elapsed time and CPU time from the start to the end of the target process. For example, let's run the following "load.py" which terminates after consuming some CPU resources.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

#!/usr/bin/python3

# This parameter is to change the amount of CPU time used by this program. It is convenient to change this parameter to make the CPU time consumption several seconds.
NLOOP=100000000

for _ in range(NLOOP):
    pass


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The result is as follows.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; ./load
&lt;span class="go"&gt;
real    0m2.357s
user    0m2.357s
sys     0m0.000s


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output includes three lines starting with real, user, and sys. Among these, real indicates the elapsed time, and user and sys indicate the CPU time. user refers to the time when the process was running. In contrast, sys refers to the time when the kernel was operating as a result of system calls issued by the process. The load program continues to use the CPU from the start to the end of its execution and does not issue any system calls during that time, so real and user are almost the same, and sys is almost zero. The reason why it is "almost" is because the Python interpreter calls a few system calls at the beginning and end of the process.&lt;/p&gt;

&lt;p&gt;Let's also run an experiment with the sleep command, which sleeps most of the time.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time sleep &lt;/span&gt;3
&lt;span class="go"&gt;
real    0m3.009s
user    0m0.002s
sys     0m0.000s


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Since it terminates after sleeping for 3 seconds, "real" is nearly 3 seconds. On the other hand, this command gives up the small mount of CPU time and goes to sleep right after starting, and when it begins to use only a little CPU time again 3 seconds later before terminating. So "user" and "sys" are almost 0. The differences of two values are shown in the following figure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nba7ycqimiwfif8z9al.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nba7ycqimiwfif8z9al.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When Using Only One Logical CPU
&lt;/h2&gt;

&lt;p&gt;To simplify the discussion, let's first consider the case of a single logical CPU. The "multiload.py" program will be used for the experiment. This program performs the following actions:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Usage: ./multiload [-m] &amp;lt;number of processes&amp;gt;
  Executes a specified number of load processing processes for a set period of time and waits for all to finish.
  The time it took to execute each process is outputted.
  By default, all processes run only on a single logical CPU.

  Meaning of the option:
  -m: Allows each process to run on multiple CPUs.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here is its source code.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

#!/bin/bash

MULTICPU=0
PROGNAME=$0
SCRIPT_DIR=$(cd $(dirname $0) &amp;amp;&amp;amp; pwd)

usage() {
    exec &amp;gt;&amp;amp;2
    echo Usage: ./multiload [-m] &amp;lt;number of processes&amp;gt;
    Executes a specified number of load processing processes for a set period of time and waits for all to finish.
    The time it took to execute each process is outputted.
    By default, all processes run only on a single logical CPU.

      Meaning of the option:
      -m: Allows each process to run on multiple CPUs."
    exit 1
}

while getopts "m" OPT ; do
    case $OPT in
        m)
            MULTICPU=1
            ;;
        \?)
            usage
            ;;
    esac
done

shift $((OPTIND - 1))

if [ $# -lt 1 ] ; then
    usage
fi

CONCURRENCY=$1

if [ $MULTICPU -eq 0 ] ; then
    # Pin the "load.py" program to CPU0
    taskset -p -c 0 $$ &amp;gt;/dev/null
fi

for ((i=0;i&amp;lt;CONCURRENCY;i++)) do
    time "${SCRIPT_DIR}/load.py" &amp;amp;
done

for ((i=0;i&amp;lt;CONCURRENCY;i++)) do
    wait
done


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's first set "" to 1 and run it. This is almost the same as running the load program alone.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./multiload 1
&lt;span class="go"&gt;
real    0m2.359s
user    0m2.358s
sys     0m0.000s


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In my environment, the elapsed time was 2.359 seconds. What about when the parallelism is 2 and 3?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./multiload 2
&lt;span class="go"&gt;
real    0m4.730s
user    0m2.360s
sys     0m0.004s

real    0m4.739s
user    0m2.374s
sys     0m0.000s
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./multiload 3
&lt;span class="go"&gt;
real    0m7.095s
user    0m2.360s
sys     0m0.004s

real    0m7.374s
user    0m2.499s
sys     0m0.000s

real    0m7.541s
user    0m2.676s
sys     0m0.000s


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As the level of parallelism increased by 2 times, 3 times, the CPU time did not change much, but the elapsed time increased by about 2 times, 3 times. This is because, as mentioned at the beginning, only one process can run at the same time on one logical CPU, and the scheduler gives CPU resources to each process in turn.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Using Multiple Logical CPUs
&lt;/h2&gt;

&lt;p&gt;Next, let's also take a look at the case of multiple logical CPUs. When the multiload program is run with the "-m" option, the scheduler tries to distribute the multiple load processes evenly across all logical CPUs. As a result, for instance, if there are two logical CPUs and two load processes, as shown in the following figure, the two load processes can each monopolize the resources of a logical CPU.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feiqk129qaqmw1ieioc8m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feiqk129qaqmw1ieioc8m.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The logic of load balancing is very complex, so this book avoids detailed explanation.&lt;/p&gt;

&lt;p&gt;Let's actually verify this. The results of running the multiload program with the -m option and parallelism from 1 to 3 are shown below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./multiload &lt;span class="nt"&gt;-m&lt;/span&gt; 1
&lt;span class="go"&gt;
real    0m2.361s
user    0m2.361s
sys     0m0.000s
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./multiload &lt;span class="nt"&gt;-m&lt;/span&gt; 2
&lt;span class="go"&gt;
real    0m2.482s
user    0m2.482s
sys     0m0.000s

real    0m2.870s
user    0m2.870s
sys     0m0.000s
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./multiload &lt;span class="nt"&gt;-m&lt;/span&gt; 3
&lt;span class="go"&gt;
real    0m2.694s
user    0m2.693s
sys     0m0.000s

real    0m2.857s
user    0m2.853s
sys     0m0.004s

real    0m2.936s
user    0m2.935s
sys     0m0.000s


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For all processes, the values of real and user+sys were almost the same. In other words, we can see that each process was able to monopolize the resources of a logical CPU.&lt;/p&gt;

&lt;p&gt;For all processes, the values of real and user+sys were almost the same. In other words, we can see that each process was able to monopolize the resources of a logical CPU.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cases where "user + sys" is larger than "real"
&lt;/h1&gt;

&lt;p&gt;Intuitively, you might think that "real &amp;gt;= user + sys" will always hold, but in reality, there can be cases where the value of "user + sys" is slightly larger than that of "real". This is due to the different methods used to measure each time and the fact that the precision of the measurement is not that high. There's no need to worry too much about this; it's enough to be aware that such things can happen.&lt;/p&gt;

&lt;p&gt;Furthermore, there are cases where "user + sys" can be significantly larger than "real". For example, this occurs when you run the "multiload.py" program with the "-m" option and set the number of processes to 2 or more. Now, let's try running "./multiload -m 2" through the time command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; ./multiload &lt;span class="nt"&gt;-m&lt;/span&gt; 2
&lt;span class="go"&gt;
real    0m2.510s
user    0m2.502s
sys     0m0.008s

real    0m2.725s
user    0m2.716s
sys     0m0.008s

real    0m2.728s
user    0m5.222s
sys     0m0.016s


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The first and second entries are data about the load processing processes of the "multiload.py" program. The third entry is data about the "multiload.py" program itself. As you can see, the value of user is about twice that of "real". In fact, the "user" and "sys" values obtained by the "time" command are the sums of the values for the target process and its terminated child processes. Therefore, if a process generates child processes and they each run on a different logical CPU, the value of "user+sys" could be greater than real. The "multiload.py" program fits exactly this condition.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part3-12ip"&gt;previous part&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter-3-process-scheduler-part-1-1phi"&gt;next part&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  NOTE
&lt;/h1&gt;

&lt;p&gt;This article is based on &lt;a href="https://amzn.to/3K9q9Ke" rel="noopener noreferrer"&gt;my book&lt;/a&gt; written in Japanese. Please contact me via &lt;a href="mailto:satoru.takeuchi@gmail.com"&gt;satoru.takeuchi@gmail.com&lt;/a&gt; if you're interested in publishing this book's English version.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>process</category>
      <category>management</category>
    </item>
    <item>
      <title>How Linux Works: Chapter2 Process Management (Part1)</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Fri, 31 Mar 2023 14:16:46 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part1-3n71</link>
      <guid>https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part1-3n71</guid>
      <description>&lt;p&gt;It is common for a system to have multiple processes. For example, you can list all processes in the system by running the &lt;code&gt;ps aux&lt;/code&gt; command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps aux
&lt;span class="go"&gt;USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND ...(1)
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;sat        19261  0.0  0.0  13840  5360 ?        S    18:24   0:00 sshd: sat@pts/0
sat        19262  0.0  0.0  12120  5232 pts/0    Ss   18:24   0:00 -bash
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;sat        19280  0.0  0.0  12752  3692 pts/0    R+   18:25   0:00 ps aux
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The line (1) is the header line that indicates the meaning of the output in the following lines, and after that, one process is displayed per line. Among them, the &lt;code&gt;COMMAND&lt;/code&gt; field represents the command name. We won't go into detail here, but you can see that the &lt;code&gt;sshd&lt;/code&gt; ssh server (PID=19261) started &lt;code&gt;bash (PID=19262)&lt;/code&gt;, which then executed &lt;code&gt;ps aux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can remove the header line of the &lt;code&gt;ps&lt;/code&gt; command output by using the &lt;code&gt;--no-header&lt;/code&gt; option. Now let's check the number of processes in my environment.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps aux &lt;span class="nt"&gt;--no-header&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="go"&gt;216
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There were 216 processes. What are each of these processes doing? How are they managed? In this chapter, we will explain the process management system that Linux uses to manage these processes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Process Creation
&lt;/h1&gt;

&lt;p&gt;There are two main purposes for creating new processes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a. Divide the processing of the same program into multiple processes (e.g., handling multiple requests by a web server).&lt;/li&gt;
&lt;li&gt;b. Generate a different program (e.g., creating various programs from &lt;code&gt;bash&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To achieve these, Linux uses the &lt;code&gt;fork()&lt;/code&gt; function and the &lt;code&gt;execve()&lt;/code&gt; function&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. Internally, they call the &lt;code&gt;clone()&lt;/code&gt; and &lt;code&gt;execve()&lt;/code&gt; system calls, respectively. For the case a, only the &lt;code&gt;fork()&lt;/code&gt; function is used, while for the case b, both the &lt;code&gt;fork()&lt;/code&gt; function and the &lt;code&gt;execve()&lt;/code&gt; function are used.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fork() function that splits the same process into two
&lt;/h2&gt;

&lt;p&gt;When the &lt;code&gt;fork()&lt;/code&gt; function is issued, a copy of the process that issued it is made, and both the original and the copy return from the &lt;code&gt;fork()&lt;/code&gt; function. The original process is called the parent process, and the generated process is called the child process. The flow at this time is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The parent process calls the &lt;code&gt;fork()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Allocate memory space for the child process and copy the parent process's memory into it.&lt;/li&gt;
&lt;li&gt;Both the parent and child processes return from the &lt;code&gt;fork()&lt;/code&gt; function. Since the return values of the &lt;code&gt;fork()&lt;/code&gt; function differ for the parent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq4uppcv5vi9dfx7kxsk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq4uppcv5vi9dfx7kxsk.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, in reality, the memory copy from the parent process to the child process is done at a very low cost thanks to a feature called Copy-on-Write, which will be explained in the following chapter. As a result, the overhead of dividing the processing of the same program into multiple processes in Linux is small.&lt;/p&gt;

&lt;p&gt;Let's take a look at how the &lt;code&gt;fork()&lt;/code&gt; function generates processes by creating the following &lt;code&gt;python.py&lt;/code&gt; program with the following specifications:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="c1"&gt;#!/usr/bin/python3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;child process: pid={}, parent process&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s pid={}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getppid&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parent process: pid={}, child process&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s pid={}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Call the &lt;code&gt;fork()&lt;/code&gt; function to branch the process flow.&lt;/li&gt;
&lt;li&gt;The parent process outputs its own process ID and the child process's process ID and then exits. The child process outputs its own process ID and then exits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the &lt;code&gt;fork.py&lt;/code&gt; program, when returning from the &lt;code&gt;fork()&lt;/code&gt; function, the parent process gets the child process's process ID, while the child process gets 0. Since the pid is always 1 or more, this can be used to branch the processing after the &lt;code&gt;fork()&lt;/code&gt; function call in the parent and child processes.&lt;/p&gt;

&lt;p&gt;Now, let's try running it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

./fork.py
parent process: pid=132767, child process's pid=132768
child process: pid=132768, parent peocess's pid=132767


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can see that a process with process ID 132767 has branched and created a new process with process ID 132768, and that after issuing the &lt;code&gt;fork()&lt;/code&gt; function, the processing branches according to the return value of &lt;code&gt;fork()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;fork()&lt;/code&gt; function can be quite difficult to understand at first, but please try to master it by repeatedly reading the content and sample code in this section.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;execve()&lt;/code&gt; function for launching a different program
&lt;/h2&gt;

&lt;p&gt;After creating a copy of the process with the &lt;code&gt;fork()&lt;/code&gt; function, the &lt;code&gt;execve()&lt;/code&gt; function is called on the child process. As a result, the child process is replaced with another program. The flow of processing is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call the &lt;code&gt;execve()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Read the program specified in the arguments of the &lt;code&gt;execve()&lt;/code&gt; function, and read the information required to place the program in memory (called "memory mapping").&lt;/li&gt;
&lt;li&gt;Overwrite the current process's memory with the new process's data.&lt;/li&gt;
&lt;li&gt;Start executing the process from the first instruction to be executed in the new process (the entry point).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In other words, while the &lt;code&gt;fork()&lt;/code&gt; function increases the number of processes, when creating an entirely different program, the number of processes does not increase; instead, one process is replaced with another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5anol0nsgobh36z14ry4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5anol0nsgobh36z14ry4.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To express this in a program, it would look like following &lt;code&gt;fork-and-exec.py&lt;/code&gt; program. Here, after the &lt;code&gt;fork()&lt;/code&gt; function call, the child process is replaced with the &lt;code&gt;echo &amp;lt;pid&amp;gt; Hello from &amp;lt;pid&amp;gt;&lt;/code&gt; command by the &lt;code&gt;execve()&lt;/code&gt; function.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="c1"&gt;#!/usr/bin/python3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;child process: pid={}, parent process&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s pid={}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getppid&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/bin/echo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;echo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello from pid={} &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;())],&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parent process: pid={}, child process&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s pid={}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The result of the execution looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;



```console
$ ./fork-and-exec.py
parent process: pid=5843, child process's pid=5844
child process: pid=5844, parent process's pid=5843
hello from pid=5844
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
If we illustrate this result, it would look like the following figure. For simplicity, we omit the loading of the program by the kernel and copying the program to memory.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8v0an3dq0lvxi71rmats.jpg)

To implement the `execve()` function, the executable file holds the necessary data for starting the program in addition to the program code and data. This data includes:

- The file offset, size, and memory map starting address of the code area.
- The same information for the data area.
- The memory address of the first instruction to execute (entry point).

Now let's take a look at how Linux executable files hold this information. Linux executable files are usually in the Executable and Linking Format (ELF) format. Various information about ELF can be obtained using the `readelf` command.

We will use the `pause` program again here, which we used in the following chapter. Let's start with the build.

```c


#include &amp;lt;unistd.h&amp;gt;

int main(void) {
    pause();
    return 0;
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cc &lt;span class="nt"&gt;-o&lt;/span&gt; pause &lt;span class="nt"&gt;-no-pie&lt;/span&gt; pause.c &lt;span class="c"&gt;# build pause program with -no-pie option. See the next column to know the meaning of this option&lt;/span&gt;
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The program's starting address can be obtained using &lt;code&gt;readelf -h&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;readelf &lt;span class="nt"&gt;-h&lt;/span&gt; pause
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;  Entry point address:               0x400400
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;"0x400400" on the "Entry point address" line is the entry point of this program.&lt;/p&gt;

&lt;p&gt;The file offset, size, and starting address of the code and data can be obtained using the &lt;code&gt;readelf -S&lt;/code&gt; command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;readelf &lt;span class="nt"&gt;-S&lt;/span&gt; pause
&lt;span class="go"&gt;There are 29 section headers, starting at offset 0x18e8:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;  [13] .text             PROGBITS         0000000000400400  00000400
       0000000000000172  0000000000000000  AX       0     0     16
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;  [23] .data             PROGBITS         0000000000601020  00001020
       0000000000000010  0000000000000000  WA       0     0     8
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Although we obtained a large amount of output, understanding the following points is sufficient:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The executable file is divided into multiple regions, each of which is called a section.&lt;/li&gt;
&lt;li&gt;Information about each section is displayed as a pair of two lines.&lt;/li&gt;
&lt;li&gt;All values are in hexadecimal.&lt;/li&gt;
&lt;li&gt;The main information about each section is as follows:

&lt;ul&gt;
&lt;li&gt;Section name: the second field "Name" in the first line&lt;/li&gt;
&lt;li&gt;Memory map starting address: the fourth field "Address" in the first line&lt;/li&gt;
&lt;li&gt;File offset: the fifth field "Offset" in the first line&lt;/li&gt;
&lt;li&gt;Size: the first field "Size" in the second line&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Sections with the name ".text" are code sections, and those with the name ".data" are data sections.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Summarizing this information, see the following table.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;File offset of the code&lt;/td&gt;
&lt;td&gt;0x400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size of the code&lt;/td&gt;
&lt;td&gt;0x172&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory map starting address of the code&lt;/td&gt;
&lt;td&gt;0x400400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File offset of the data&lt;/td&gt;
&lt;td&gt;0x1020&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size of the data&lt;/td&gt;
&lt;td&gt;0x10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory map starting address of the data&lt;/td&gt;
&lt;td&gt;0x601020&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entry point&lt;/td&gt;
&lt;td&gt;0x400400&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The memory map of the process created from the program can be obtained using the &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/maps&lt;/code&gt; file. Now let's take a look at the memory map of the &lt;code&gt;pause&lt;/code&gt; command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./pause &amp;amp;
&lt;span class="go"&gt;[3] 12492
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/12492/maps
&lt;span class="go"&gt;00400000-00401000 r-xp 00000000 08:02 788371                             .../pause ... (1)
00600000-00601000 r--p 00000000 08:02 788371                             .../pause
00601000-00602000 rw-p 00001000 08:02 788371                             .../pause ... (2)
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;(1) is the code region, and (2) is the data region. We can see that they fit within the memory map ranges shown in the above-mentioned table.&lt;/p&gt;

&lt;p&gt;Once you have finished with this, let's exit the &lt;code&gt;pause&lt;/code&gt; process.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;kill &lt;/span&gt;12492
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Security enhancement with Address Space Layout Randomization feature
&lt;/h2&gt;

&lt;p&gt;In this section, we explain the meaning of the &lt;code&gt;-no-pie&lt;/code&gt; option attached during the build of the pause program in the previous section. This option is related to a security feature called Address Space Layout Randomization (ASLR) that the Linux kernel has. ASLR is a feature that maps each section of a program to a different address every time it is executed. Thanks to this, attacks that assume the target code or data exists at a specific address become difficult.&lt;/p&gt;

&lt;p&gt;The conditions for using this feature are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The ASLR function of the kernel is enabled. It is enabled by default in Ubuntu 20.04&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;The program supports ASLR. Such programs are called Position Independent Executable (PIE).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;gcc (in this book's example, the cc command) in Ubuntu 20.04 builds all programs as PIE by default, but PIE can be disabled with the &lt;code&gt;-no-pie&lt;/code&gt; option. In the previous section, we set it up intentionally because if the PIE of the pause command is not disabled, it causes confusion due to reasons such as the values in &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/maps&lt;/code&gt; not being the same as those written in the executable file and being different every time it is executed.&lt;/p&gt;

&lt;p&gt;Whether a program is PIE or not can be checked with the file command. If it is supported, the following output is obtained:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file pause
&lt;span class="go"&gt;pause: ELF 64-bit LSB shared object, ...
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If it is not PIE, the following output is obtained:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file pause
&lt;span class="go"&gt;pause: ELF 64-bit LSB executable, ...
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For reference, let's run the pause program built without the &lt;code&gt;-no-pie&lt;/code&gt; option twice and check where the code section is mapped to memory each time.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cc &lt;span class="nt"&gt;-o&lt;/span&gt; pause pause.c
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./pause &amp;amp;
&lt;span class="go"&gt;[5] 15406
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/15406/maps
&lt;span class="go"&gt;559c5778f000-559c57790000 r-xp 00000000 08:02 788372                     .../pause
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./pause &amp;amp;
&lt;span class="go"&gt;[6] 15536
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/15536/maps
&lt;span class="go"&gt;5568d2506000-5568d2507000 r-xp 00000000 08:02 788372                     .../pause
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;kill &lt;/span&gt;15406 15536
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, it is mapped to different locations on the first and second runs.&lt;/p&gt;

&lt;p&gt;Actually, programs distributed as part of Ubuntu 20.04 are PIE as much as possible. It's wonderful that security is enhanced automatically without users or programmers being particularly aware of it. However, there are also security attacks to bypass ASLR, so the history of security technology is a game of cat and mouse.&lt;/p&gt;

&lt;h1&gt;
  
  
  Column: Process Generation Methods Other Than &lt;code&gt;fork()&lt;/code&gt; and &lt;code&gt;execve()&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Using &lt;code&gt;fork()&lt;/code&gt; and &lt;code&gt;execve()&lt;/code&gt; functions in sequence to create a program from within a process may seem redundant. In such cases, the &lt;code&gt;posix_spawn()&lt;/code&gt; function defined in the C language interface specification for UNIX-based operating systems, POSIX, can simplify the process.&lt;/p&gt;

&lt;p&gt;Below is a program named &lt;code&gt;spawn.py&lt;/code&gt; that generates an echo command as a child process using the &lt;code&gt;posix_spawn()&lt;/code&gt; function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="c1"&gt;#!/usr/bin/python3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;posix_spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/bin/echo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;echo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;echo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created by posix_spawn()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created echo command&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./spawn.py
&lt;span class="go"&gt;created echo command
created by posix_spawn()


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is achieved using &lt;code&gt;fork()&lt;/code&gt; and &lt;code&gt;execve()&lt;/code&gt; functions in &lt;code&gt;spawn-by-fork-and-exec.py&lt;/code&gt; program , as shown below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="c1"&gt;#!/usr/bin/python3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/bin/echo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;echo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created by fork() and execve()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created echo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./spawn-by-fork-and-exec.py
&lt;span class="go"&gt;created echo
created by fork() and execve()


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, the spawn program has better source code readability.&lt;/p&gt;

&lt;p&gt;Although process generation using &lt;code&gt;posix_spawn()&lt;/code&gt; is intuitive, it may become unnecessarily complex if more sophisticated operations such as shell implementations are desired, compared to using the &lt;code&gt;fork()&lt;/code&gt; and &lt;code&gt;execve()&lt;/code&gt; functions. For reference, I uses the &lt;code&gt;posix_spawn()&lt;/code&gt; function only when calling the &lt;code&gt;execve()&lt;/code&gt; function immediately after the &lt;code&gt;fork()&lt;/code&gt; function without performing any other operations. Otherwise, I uses &lt;code&gt;fork()&lt;/code&gt; and &lt;code&gt;execve()&lt;/code&gt; functions for all cases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter1-linux-overview-part2-i0o"&gt;previous part&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part2-5816"&gt;next part&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  NOTE
&lt;/h1&gt;

&lt;p&gt;This article is based on &lt;a href="https://amzn.to/3K9q9Ke" rel="noopener noreferrer"&gt;my book&lt;/a&gt; written in Japanese. Please contact me via &lt;a href="mailto:satoru.takeuchi@gmail.com"&gt;satoru.takeuchi@gmail.com&lt;/a&gt; if you're interested in publishing this book's English version.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;If you run &lt;code&gt;man 3 exec&lt;/code&gt;, you will find many variations of the &lt;code&gt;execve()&lt;/code&gt; function. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;For reference, to disable ASLR in the kernel, set the &lt;code&gt;kernel.randomize_va_space&lt;/code&gt; parameter of sysctl to 0.  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>linux</category>
      <category>process</category>
      <category>management</category>
    </item>
    <item>
      <title>ATARI is still alive: Atari Partition of Fear</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Tue, 28 Mar 2023 00:26:32 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/atari-is-still-alive-atari-partition-of-fear-1ebj</link>
      <guid>https://dev.to/satorutakeuchi/atari-is-still-alive-atari-partition-of-fear-1ebj</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;This article explains the &lt;a href="https://github.com/rook/rook/issues/7940" rel="noopener noreferrer"&gt;data corruption issue&lt;/a&gt; happened in &lt;a href="https://github.com/rook/rook" rel="noopener noreferrer"&gt;Rook&lt;/a&gt; in 2021. The root cause lies in an unexpected place and can also occurs in all Ceph environment. It's interesting that Rook had started to encounter this problem recently even though this problem has existed for a long time. It's due to a series of coincidences. I wrote this article  because the word "Atari" used in a non-historical context in 2021.&lt;/p&gt;

&lt;p&gt;This article is a restructured version of the information written in &lt;a href="https://github.com/rook/rook/blob/master/Documentation/ceph-common-issues.md#unexpected-partitions-created" rel="noopener noreferrer"&gt;Rook's official documentation&lt;/a&gt;, with additional information for those who are not familiar with Rook.&lt;/p&gt;

&lt;h1&gt;
  
  
  Glossary
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ceph/ceph" rel="noopener noreferrer"&gt;Ceph&lt;/a&gt;: A open source distributed storage system&lt;/li&gt;
&lt;li&gt;Rook: An irchestration of Ceph running on Kubernetes. This is also open source&lt;/li&gt;
&lt;li&gt;OSD: Data structure existing on disks that usually corresponds to a disk in Ceph cluster&lt;/li&gt;
&lt;li&gt;OSD on disk: One of the methods to create OSDs on Rook. The device path is directly written in the Rook configuration. Details will be discussed later&lt;/li&gt;
&lt;li&gt;Atari partition: The partition format used in the once-existing &lt;a href="https://en.wikipedia.org/wiki/Atari_ST" rel="noopener noreferrer"&gt;Atari ST&lt;/a&gt; computer&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Problem Summary
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;The problem:

&lt;ul&gt;
&lt;li&gt;OSD data gets corrupted&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Root Cause Summary

&lt;ul&gt;
&lt;li&gt;The disk containing the OSD is mistakenly recognized as having an Atari partition, and Rook creates an OSD on that (non-existent) partition&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Occurrence Conditions:

&lt;ul&gt;
&lt;li&gt;Using Rook v1.6.0 to v1.6.7&lt;/li&gt;
&lt;li&gt;Creating OSD on disk on a disk without partitioning&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Mitigation:

&lt;ul&gt;
&lt;li&gt;Update to Rook v1.6.8 or higher, or Rook v1.7&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Recovery from Data Corruption:

&lt;ul&gt;
&lt;li&gt;Impossible. The only option is to recreate the OSD on the disk holding the corrupted OSD using &lt;a href="https://github.com/rook/rook/blob/master/Documentation/ceph-common-issues.md#recover-from-corruption-v160-v167" rel="noopener noreferrer"&gt;this procedure&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Mechanism
&lt;/h1&gt;

&lt;p&gt;Let's assume that Rook tries to create an OSD on a disk called /dev/sdb&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rook creates an OSD on /dev/sdb.&lt;/li&gt;
&lt;li&gt;Linux Kernel recognizes that there is an Atari Partition Table, not an OSD, on /dev/sdb by mistake.&lt;/li&gt;
&lt;li&gt;Rook found there are some "phantom" empty Atari Partitions that can be used to create OSDs.&lt;/li&gt;
&lt;li&gt;Rook creates an OSD on the empty partitions mentioned in step 3, resulting in data corruption of the OSD on /dev/sdb.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Details
&lt;/h1&gt;

&lt;p&gt;To understand the problem in detail, some knowledge about Rook, Ceph, and Atari Partition is required. I will first explain some prerequisite knowledge, and then describe the actual flow leading up to the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring OSD on device in Rook
&lt;/h2&gt;

&lt;p&gt;When creating an OSD in Rook, you write settings such as "I want to create an OSD under these conditions" in a CephCluster Custom Resource (CR). To create an OSD on device, you specify the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The path of the device where you want to create the OSD ("/dev/sdb", etc.)&lt;/li&gt;
&lt;li&gt;A regular expression to match the device ("/dev/sd.*", etc.)&lt;/li&gt;
&lt;li&gt;The specification "create on all unused devices, useAllDevice: true"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please refer to the &lt;a href="https://github.com/rook/rook/blob/master/Documentation/ceph-cluster-crd.md#storage-selection-settings" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;When Rook operates, it creates OSDs on each device according to the Ceph Cluster CR as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rook on the node composing the Rook cluster executes a command called ceph-volume provided by Ceph.&lt;/li&gt;
&lt;li&gt;The ceph-volume command lists the devices present in the system and displays whether they are empty and can be used to create OSDs.&lt;/li&gt;
&lt;li&gt;Rook creates OSDs on devices that are empty and match the settings in the Ceph Cluster CR.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  OSD Formats in Ceph
&lt;/h2&gt;

&lt;p&gt;When Ceph creates an OSD on a device, it writes OSD metadata to the device. There are two formats of OSD in Ceph, each with different locations for writing metadata.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lvm mode OSD: Create a Volume Group (VG) in LVM on the device, then create a Logical Volume (LV) within it, and write the OSD metadata to the beginning of the LV.&lt;/li&gt;
&lt;li&gt;raw mode OSD: Write the OSD metadata to the beginning of the device.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ceph only have lvm mode at first and introduced the simpler and easier-to-manage raw mode OSD later. In Rook, starting from v1.6.0, raw mode OSDs are created for OSD on device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atari Partition Recognition Method in the Linux Kernel
&lt;/h2&gt;

&lt;p&gt;The recognition method for Atari Partition in the Linux kernel is much more lenient compared to other partitions. To determine whether the fundamental problem lies in the Linux kernel or in the Atari partition specification itself, it is necessary to look at the Atari partition specification, but since it could not be found, the investigation was limited to the source code.&lt;/p&gt;

&lt;p&gt;The determination of whether a disk is an Atari Partition or not is based on the presence of one or more partition information in the beginning area of the disk. There can be up to 4 partitions&lt;sup id="fnref1"&gt;1&lt;/sup&gt;, and the method of checking this is the &lt;code&gt;VALID_PARTITION()&lt;/code&gt; macro.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/3a93e40326c8f470e71d20b4c42d36767450f38f/block/partitions/atari.c#L53-L70" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/3a93e40326c8f470e71d20b4c42d36767450f38f/block/partitions/atari.c#L53-L70&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;    &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_part_sector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sect&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/* Verify this is an Atari rootsector: */&lt;/span&gt;
    &lt;span class="n"&gt;hd_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;VALID_PARTITION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;hd_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;VALID_PARTITION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;hd_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;VALID_PARTITION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;hd_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;VALID_PARTITION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;hd_size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/*
         * if there's no valid primary partition, assume that no Atari
         * format partition table (there's no reliable magic or the like
             * :-()
         */&lt;/span&gt;
        &lt;span class="n"&gt;put_dev_sector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sect&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the comments, it seems that there is no magic number-like element that naturally exists in other partition tables.&lt;/p&gt;

&lt;p&gt;The definition of &lt;code&gt;VALID_PARTITION()&lt;/code&gt; is as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/3a93e40326c8f470e71d20b4c42d36767450f38f/block/partitions/atari.c#L19-L25" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/3a93e40326c8f470e71d20b4c42d36767450f38f/block/partitions/atari.c#L19-L25&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* check if a partition entry looks valid -- Atari format is assumed if at
   least one of the primary entries is ok this way */
#define VALID_PARTITION(pi,hdsiz)                        \
    (((pi)-&amp;gt;flg &amp;amp; 1) &amp;amp;&amp;amp;                              \
     isalnum((pi)-&amp;gt;id[0]) &amp;amp;&amp;amp; isalnum((pi)-&amp;gt;id[1]) &amp;amp;&amp;amp; isalnum((pi)-&amp;gt;id[2]) &amp;amp;&amp;amp; \
     be32_to_cpu((pi)-&amp;gt;st) &amp;lt;= (hdsiz) &amp;amp;&amp;amp;                     \
     be32_to_cpu((pi)-&amp;gt;st) + be32_to_cpu((pi)-&amp;gt;siz) &amp;lt;= (hdsiz))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is quite frightening that a disk can be mistakenly recognized as a partition just by meeting such loose conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The process leading to the problem
&lt;/h2&gt;

&lt;p&gt;Let's consider the case of trying to create an OSD on /dev/sdb again. For simplicity, let's assume that the Rook configuration is set to create OSDs on all available devices.&lt;/p&gt;

&lt;p&gt;First, Rook operates and creates an OSD on /dev/sdb. So far, so good. From v1.6.0 to v1.6.7, the OSD metadata is written to the beginning of the disk to create a raw mode OSD. Unfortunately, this OSD metadata has a bit pattern that is easily mistaken for an Atari Partition Table&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;You can check the devices where the misrecognition occurred from the results of the lsblk command as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;vdb    252:16   0    3T  0 disk 
&lt;/span&gt;&lt;span class="gp"&gt;├─vdb2 252:18   0   48G  0 part #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;phantom Atari Partition 
&lt;span class="gp"&gt;└─vdb3 252:19   0  6.1M  0 part #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;same as above
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interestingly, tools like lsblk, blkid, udevadm, and parted have been confusing users and developers by not recognizing Atari Partitions, making it appear as if vdb2 and vdb3 do not exist, or setting the partition table type to unknown. This is why the misrecognized partitions are called "phantom."&lt;/p&gt;

&lt;p&gt;After this, for some reason, when Rook operates next time, the ceph-volume command is executed, and it mistakenly recognizes that there is an Atari Partition Table on /dev/vdb instead of an OSD, along with some phantom Partitions. Let's assume that /dev/vdb2 is the phantom partition here. As a result of this misrecognition, /dev/vdb is reported to be in use, but /dev/vdb2 is empty and can have an OSD created on it.&lt;/p&gt;

&lt;p&gt;Finally, Rook receives instructions from the user to create OSDs on free devices, so it creates a new OSD on /dev/vdb2. This results in the partial destruction of the data on the original OSD on /dev/vdb.&lt;/p&gt;

&lt;h1&gt;
  
  
  History of Handling the Issue
&lt;/h1&gt;

&lt;p&gt;There are three parties involved in this issue: Rook, Ceph, and the Linux Kernel. In fixing such issues, it is important to consider "which layer can fix it" and "which layer should fix it."&lt;/p&gt;

&lt;p&gt;Various workarounds have been proposed after twists and turns, but it has been determined that there is not much that can be done at a superficial level. Currently, in Rook, a &lt;a href="https://github.com/rook/rook/pull/8319" rel="noopener noreferrer"&gt;fix to create lvm mode OSDs when creating OSDs on disk&lt;/a&gt; has been incorporated.&lt;/p&gt;

&lt;p&gt;In addition, a &lt;a href="https://github.com/ceph/ceph/pull/42469" rel="noopener noreferrer"&gt;fix for ceph-volume to ignore phantom Atari partitions&lt;/a&gt; has already been made to Ceph, and it has fixed in the v16.2.6 rel. Once v16.2.6 was released, raw mode started to use again for OSD on disk in Rook when using that version.&lt;/p&gt;

&lt;p&gt;As for the Linux kernel, a &lt;a href="https://bugs.launchpad.net/ubuntu/+source/linux-aws/+bug/1908264" rel="noopener noreferrer"&gt;fix to disable Atari Partition support in the kernel for major cloud vendor environments in Ubuntu&lt;/a&gt; has been made. It is not written what problem prompted the fix, so it may have come up in a context unrelated to Rook or Ceph.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;It was quite a dramatic issue, but I think it's a good example to learn how to fix software and make announcements in such cases. If you want to learn more, I recommend digging deeper by following related issues.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;This may be a limitation of Linux, but it is unclear. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Fortunately, there have been no reports of OSDs being mistaken for Atari Partitions when using lvm mode OSDs. However, this is simply because the metadata of the VG is at the beginning of the disk in the case of lvm mode, and the pattern just happens to not be recognized as an Atari Partition. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>linux</category>
      <category>partition</category>
      <category>atari</category>
    </item>
    <item>
      <title>How Linux Works: Chapter1 Linux Overview (Part2)</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Sun, 26 Mar 2023 07:26:33 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/how-linux-works-chapter1-linux-overview-part2-i0o</link>
      <guid>https://dev.to/satorutakeuchi/how-linux-works-chapter1-linux-overview-part2-i0o</guid>
      <description>&lt;h1&gt;
  
  
  Libraries
&lt;/h1&gt;

&lt;p&gt;In this section, we will discuss libraries provided by the operating system. Many programming languages offer the ability to bundle commonly used functions across multiple programs into libraries. This allows programmers to efficiently develop programs by choosing from a vast array of libraries created by their predecessors. Some libraries, which are expected to be used by a large number of programs, may be provided by the operating system.&lt;/p&gt;

&lt;p&gt;The following figure shows the software hierarchy when a process is using a library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnljv7vjn45oje3f53rjr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnljv7vjn45oje3f53rjr.jpg" alt="Image description" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;C language has a standard library defined by the International Organization for Standardization (ISO). Linux also provides this standard C library. Typically, the glibc provided by the GNU project GNU is used as the standard C library. In this book, we will refer to glibc as libc.&lt;/p&gt;

&lt;p&gt;Almost all C programs written in C language are linked with libc.&lt;/p&gt;

&lt;p&gt;You can use the &lt;code&gt;ldd&lt;/code&gt; command to check which libraries a program is linked with. Let's take a look at the &lt;code&gt;ldd&lt;/code&gt; output for the &lt;code&gt;echo&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ldd /bin/echo
&lt;span class="go"&gt;        linux-vdso.so.1 (0x00007ffef73a9000)
&lt;/span&gt;&lt;span class="gp"&gt;        libc.so.6 =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/lib/x86_64-linux-gnu/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f2925ebd000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;        /lib64/ld-linux-x86-64.so.2 (0x00007f29260d1000)
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, &lt;code&gt;libc.so.6&lt;/code&gt; refers to the standard C library. Also, &lt;code&gt;ld-linux-x86-64.so.2&lt;/code&gt; is a special library for loading shared libraries, which is also one of the libraries provided by the OS.&lt;/p&gt;

&lt;p&gt;Let's also check the &lt;code&gt;cat&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ldd /bin/cat
&lt;span class="go"&gt;        linux-vdso.so.1 (0x00007ffc3b155000)
&lt;/span&gt;&lt;span class="gp"&gt;        libc.so.6 =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/lib/x86_64-linux-gnu/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007fabd1194000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;        /lib64/ld-linux-x86-64.so.2 (0x00007fabd13a9000)
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also links to libc. Let's also look at the &lt;code&gt;python3&lt;/code&gt; command, which is the Python3 interpreter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ldd /usr/bin/python3
&lt;span class="go"&gt;        linux-vdso.so.1 (0x00007ffc91126000)
&lt;/span&gt;&lt;span class="gp"&gt;        libc.so.6 =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/lib/x86_64-linux-gnu/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f5fb7206000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c"&gt; ...
&lt;/span&gt;&lt;span class="go"&gt;        /lib64/ld-linux-x86-64.so.2 (0x00007f5fb740f000)
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, libc is linked. In other words, when executing Python programs, the standard C library is used internally. Although few people may use C language directly nowadays, it can be seen that it remains an important language as the backbone of the OS level.&lt;/p&gt;

&lt;p&gt;If you run the &lt;code&gt;ldd&lt;/code&gt; command for various programs existing in the system, you will see that many of them are linked with libc. Please give it a try.&lt;/p&gt;

&lt;p&gt;In Linux, in addition to this, standard libraries for various programming languages, such as C++, are provided. It also offers libraries that, while not standard, many programmers are likely to use. In Ubuntu, library files often begin with the string "lib". When I ran &lt;code&gt;dpkg-query -W | grep lib&lt;/code&gt; in my environment, over 1000 packages were displayed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapper Functions for System Calls
&lt;/h3&gt;

&lt;p&gt;libc not only provides the standard C library but also offers something called "wrapper functions" for system calls. System calls cannot be directly called from high-level languages such as C, unlike regular function calls. They must be invoked using architecture-dependent assembly code.&lt;/p&gt;

&lt;p&gt;For example, in the x86_64 CPU architecture, the &lt;code&gt;getppid()&lt;/code&gt; system call is issued at the assembly code level as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov    $0x6e,%eax
syscall
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first line, the system call number "0x6e" for &lt;code&gt;getppid()&lt;/code&gt; is assigned to the eax register. This is determined by the Linux system call calling convention. The second line issues the system call and transitions to kernel mode via the syscall instruction. After this, the kernel code that processes &lt;code&gt;getppid()&lt;/code&gt; is executed. If you don't usually write assembly language, you don't need to understand the detailed meaning of this source here. Just get a feel for the atmosphere that it's obviously different from the source code you normally see.&lt;/p&gt;

&lt;p&gt;In the arm64 architecture, which is mainly used in smartphones and tablets, the &lt;code&gt;getppid()&lt;/code&gt; system call is issued at the assembly code level as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov     x8,  &amp;lt;system call number&amp;gt;
svc     #0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quite different, isn't it? Without the help of libc, every time you issue a system call, you would have to write architecture-dependent assembly source code and call it from a high-level language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3sgn2paid8pl6qnhj7ek.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3sgn2paid8pl6qnhj7ek.jpg" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This would make program creation more time-consuming and not portable to other architectures.&lt;/p&gt;

&lt;p&gt;To solve such problems, libc provides a series of functions called "wrapper functions" for system calls, which internally just call the system calls. Wrapper functions exist for each architecture. From user programs written in high-level languages, you only need to call the system call wrapper functions prepared for each language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F553b5xflagjoloyyt4io.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F553b5xflagjoloyyt4io.jpg" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Libraries and Shared Libraries
&lt;/h2&gt;

&lt;p&gt;Libraries can be classified into two types: static libraries and shared (or dynamic) libraries. Both provide the same functionality, but the way they are incorporated into a program is different.&lt;/p&gt;

&lt;p&gt;When creating a program, first, you compile the source code to create a file called an object file. Then, you link the library used by the object file to create the executable file. At link time, static libraries incorporate the functions within the library into the program. In contrast, shared libraries only embed information such as "call this function of this library" in the executable file at link time. Then, at program startup or during execution, the library is loaded into memory, and the program calls the functions within it.&lt;/p&gt;

&lt;p&gt;The following figure shows the difference between the two in the case of a &lt;code&gt;pause&lt;/code&gt; program that only calls the &lt;code&gt;pause()&lt;/code&gt; system call and does nothing else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2w76gix0nroliyrpyonk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2w76gix0nroliyrpyonk.jpg" alt="Image description" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is the source code of &lt;code&gt;pause&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's verify if my explanation is correct with the following perspectives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The size of &lt;code&gt;pause&lt;/code&gt; program&lt;/li&gt;
&lt;li&gt;Link status with shared libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an example, let's consider linking the libc library to the program. First, let's check the case of using the static library "libc.a"&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cc &lt;span class="nt"&gt;-static&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; pause pause.c
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; pause
&lt;span class="go"&gt;-rwxrwxr-x 1 sat sat 871688  Feb 27 10:29 pause  ... (1)
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ldd pause
&lt;span class="go"&gt;        not a dynamic executable   ... (2)
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution results show the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(1) The program size is just under 900KB&lt;/li&gt;
&lt;li&gt;(2) No shared libraries are linked&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since this program already incorporates libc, it will still work if "libc.a" is deleted. However, doing so would be very dangerous because other programs would no longer be able to statically link with libc, so please do not do this.&lt;/p&gt;

&lt;p&gt;Next, let's consider the case of using the shared library "libc.so"&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cc &lt;span class="nt"&gt;-o&lt;/span&gt; pause pause.c
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; pause
&lt;span class="go"&gt;-rwxrwxr-x 1 sat sat 16696  Feb 27 10:43 pause
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ldd pause
&lt;span class="go"&gt;        linux-vdso.so.1 (0x00007ffc18a75000)
&lt;/span&gt;&lt;span class="gp"&gt;        libc.so.6 =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/lib/x86_64-linux-gnu/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f64ad4e9000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;        /lib64/ld-linux-x86-64.so.2 (0x00007f64ad6f7000)
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From these results, we can see the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The size is about 16KB, which is a fraction of the size when libc is statically linked.&lt;/li&gt;
&lt;li&gt;libc ("/lib/x86_64-linux-gnu/libc.so.6") is dynamically linked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;pause&lt;/code&gt; command with dynamically linked libc will not execute if &lt;code&gt;libc.so&lt;/code&gt; is deleted. In fact, doing so is even more dangerous than deleting &lt;code&gt;libc.a&lt;/code&gt;, as it would render all programs that link to &lt;code&gt;libc.so&lt;/code&gt; inoperable. If this happens, you'll need to use complex methods to recover or reinstall the entire OS. Please do not do this under any circumstances.&lt;/p&gt;

&lt;p&gt;The reason for the small size is that libc is not embedded in the program itself but is loaded into memory at runtime. Instead of using separate copies of libc code for each program, all programs using libc share the same instance.&lt;/p&gt;

&lt;p&gt;Both static and shared libraries have their pros and cons, so it's hard to say which is better overall. However, shared libraries have been mainly used for the following reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They keep the overall storage consumption low.&lt;/li&gt;
&lt;li&gt;If there's an issue with the library, replacing the new shared library will resolve the problem for all programs using that library.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It might be interesting to run the &lt;code&gt;ldd&lt;/code&gt; command on the executable files of the programs you use to see which shared libraries are linked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Column: The Revival of Static Linking
&lt;/h3&gt;

&lt;p&gt;In this article, I mentioned that shared libraries have been preferred, but the situation has changed slightly in recent years. For example, the popular Go language, which has gained popularity in the past few years, statically links most libraries by default. As a result, most Go program does not depend on any shared libraries.&lt;/p&gt;

&lt;p&gt;Let's run &lt;code&gt;ldd&lt;/code&gt; on the &lt;code&gt;hello&lt;/code&gt; program, which is written in Go, to verify this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ldd hello
&lt;span class="go"&gt;        not a dynamic executable
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are various reasons for this, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The size issue has become relatively smaller thanks to the large capacity of memory and storage in modern computers.&lt;/li&gt;
&lt;li&gt;If a program can run with just a single executable file, it is easier to handle since you can simply copy the file to run in another environment.&lt;/li&gt;
&lt;li&gt;Faster startup as there is no need to link shared libraries at runtime.&lt;/li&gt;
&lt;li&gt;Shared libraries have issues, such as some programs not working due to library version upgrades, because the behavior of different versions of libraries that should originally work the same can be subtly different (so called "DLL Hell").&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are various ways of thinking, and the appropriate method changes over time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter1-linux-overview-part1-3g61"&gt;previous part&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter2-process-management-part1-3n71"&gt;next part&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  NOTE
&lt;/h1&gt;

&lt;p&gt;This article is based on &lt;a href="https://amzn.to/3K9q9Ke" rel="noopener noreferrer"&gt;my book&lt;/a&gt; written in Japanese. Please contact me via &lt;a href="mailto:satoru.takeuchi@gmail.com"&gt;satoru.takeuchi@gmail.com&lt;/a&gt; if you're interested in publishing this book's English version.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;In Ubuntu 20.04, this is provided by the &lt;code&gt;libc6-dev&lt;/code&gt; package. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;In Ubuntu 20.04, this is provided by the &lt;code&gt;libc6&lt;/code&gt; package. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>Should we always use quicksort than insertion sort?</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Sun, 26 Mar 2023 06:28:13 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/fast-algorithms-in-the-real-world-524h</link>
      <guid>https://dev.to/satorutakeuchi/fast-algorithms-in-the-real-world-524h</guid>
      <description>&lt;p&gt;It's often said that "Use always O(n*log(n)) algorhithms". However, depending on the situation, it might not always be right. In this article, I will compare quicksort and insertion sort.&lt;/p&gt;

&lt;p&gt;When written in Big O notation, the computational complexity of quicksort is &lt;code&gt;O(n*log(n))&lt;/code&gt;, while that of insertion sort is &lt;code&gt;O(n^2)&lt;/code&gt;. So, it seems like the former would be faster at a glance. However, this notation only describes the behavior when &lt;code&gt;n&lt;/code&gt; approaches infinity, so in real-world programs, quicksort is not always faster.&lt;/p&gt;

&lt;p&gt;Let's compare the speeds of both algorithms in a program with the following specifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sort an array with a given number of integer elements and output the time it takes to do so.&lt;/li&gt;
&lt;li&gt;First argument (&lt;code&gt;len&lt;/code&gt;): Number of elements.&lt;/li&gt;
&lt;li&gt;Second argument (&lt;code&gt;type&lt;/code&gt;): Type of algorithm. 'i' for insertion sort, 'q' for quicksort.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following sort program implements these specifications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;time.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define NSECS_PER_MSEC 1000000UL
#define NSECS_PER_SEC 1000000000UL
&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;insertion_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;quick_sort_inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;quick_sort_inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;quick_sort_inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;quick_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;quick_sort_inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nf"&gt;diff_nsec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;timespec&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;timespec&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_sec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;NSECS_PER_SEC&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_nsec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_sec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;NSECS_PER_SEC&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_nsec&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;prepare_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;progname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;progname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"usage: %s &amp;lt;len&amp;gt; &amp;lt;i|q&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;progname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'i'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'q'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%s: type should be 'i or q'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;progname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;prepare_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;timespec&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'i'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLOCK_MONOTONIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;insertion_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLOCK_MONOTONIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLOCK_MONOTONIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;qsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLOCK_MONOTONIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%lu&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;diff_nsec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's build this progam.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-O3&lt;/span&gt; make &lt;span class="nb"&gt;sort&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ran this program with the following parameters.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First argument (&lt;code&gt;len&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;2^(0, 1, 2, ..., 15)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second argument (&lt;code&gt;type&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;"i", "q"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I plotted the results on the following graph. Note that the x-axis is &lt;code&gt;2^(len)&lt;/code&gt; and the y-axis is &lt;code&gt;log(elapsed time)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6haibl8hlfvkingc9m1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6haibl8hlfvkingc9m1.png" alt="Image description" width="600" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As &lt;code&gt;len&lt;/code&gt; gets larger, quicksort indeed becomes faster, and the difference only grows. However, when &lt;code&gt;len&lt;/code&gt; is small, it can be seen that insertion sort is faster up to around 2^8 (=128). This is because quicksort performs more complex processing compared to insertion sort. Therefore, using quicksort is generally not a bad choice, but if you want to fine-tune your program and know that len will not be that large, trying to speed up using insertion sort is one option. However, as the saying goes, "premature optimization", there is no need to start with this kind of fine-tuning.&lt;/p&gt;

&lt;p&gt;One last point. For the reasons mentioned above, the &lt;code&gt;qsort()&lt;/code&gt; function in glibc, &lt;a href="https://github.com/lattera/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/stdlib/qsort.c#L78-L81" rel="noopener noreferrer"&gt;internally uses insertion sort for a somewhat small len (&amp;lt;=MAX_THRESH)&lt;/a&gt;. There are many other implementations that work this way. If you're interested, it's a good idea to take a look at various quicksort implementations.&lt;/p&gt;

</description>
      <category>sort</category>
      <category>complexity</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>How Linux Works: Chapter1 Linux Overview (Part1)</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Sat, 25 Mar 2023 17:20:00 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/how-linux-works-chapter1-linux-overview-part1-3g61</link>
      <guid>https://dev.to/satorutakeuchi/how-linux-works-chapter1-linux-overview-part1-3g61</guid>
      <description>&lt;p&gt;In this chapter, we will discuss what Linux and its component, the kernel, are, as well as the differences between Linux and other systems within the context of the entire system. We will also explain the meanings of words like programs and processes, which tend to be used in the same context.&lt;/p&gt;

&lt;h1&gt;
  
  
  Programs and Processes
&lt;/h1&gt;

&lt;p&gt;Various programs are running on Linux. A program is a set of instructions and data that work together on a computer. In compiled languages like Go, the executable file after building the source code is considered a program. In script languages like Python, the source code itself is considered an executable file. The kernel is also a type of program.&lt;/p&gt;

&lt;p&gt;When you turn on the machine, the kernel starts first&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. All other programs start after the kernel.&lt;/p&gt;

&lt;p&gt;There are various types of programs running on Linux, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web browsers: Chrome, Firefox, etc.&lt;/li&gt;
&lt;li&gt;Office suites: Libre Office, etc.&lt;/li&gt;
&lt;li&gt;Web servers: Apache, Nginx, etc.&lt;/li&gt;
&lt;li&gt;Text editors: Vim, Emacs, etc.&lt;/li&gt;
&lt;li&gt;Programming language processors: C compiler, Go compiler, Python interpreter, etc.&lt;/li&gt;
&lt;li&gt;Shells: bash, zsh, etc.&lt;/li&gt;
&lt;li&gt;System-wide management software: systemd, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A program that is running after startup is called a process. Since the term "program" is sometimes used to refer to a running process, it can be said that "program" has a broader meaning than "process."&lt;/p&gt;

&lt;h1&gt;
  
  
  Kernel
&lt;/h1&gt;

&lt;p&gt;In this section, we will explain what a kernel is and why it is necessary, using the example of accessing storage devices like HDDs and SSDs connected to the system.&lt;/p&gt;

&lt;p&gt;First, let's consider a system where processes can directly access storage devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6cqimytonz5ys4d8l3l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6cqimytonz5ys4d8l3l.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, problems arise when multiple processes try to operate on the device simultaneously.&lt;/p&gt;

&lt;p&gt;To read and write data from storage devices, suppose you need to issue the following two commands:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Specify the location to read or write data.&lt;/li&gt;
&lt;li&gt;Read or write data from the location specified in command 1.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If two processes, A and B, are writing data and reading data from another location simultaneously, the commands might be issued in the following order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Process A specifies the location to write data.&lt;/li&gt;
&lt;li&gt;Process B specifies the location to read data.&lt;/li&gt;
&lt;li&gt;Process A writes data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In command 3, the location to write data is not the one specified in command 1 but the one specified in command 2 causing the data at the location specified in command 2 to be corrupted. As you can see, accessing storage devices is very dangerous if the order of command execution is not properly controlled&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In addition to this, there are problems where programs that should not have access to the device can access it.&lt;/p&gt;

&lt;p&gt;To avoid these problems, the kernel, with the help of hardware, prevents processes from directly accessing devices. Specifically, it uses a feature called mode built into the CPU.&lt;/p&gt;

&lt;p&gt;General-purpose CPUs used in personal computers and servers have two modes: kernel mode and user mode. More precisely, there are more than three modes depending on the CPU architecture, but we will omit them here&lt;sup id="fnref3"&gt;3&lt;/sup&gt;. When a process is running in user mode, it is said to be running in userland (or user space).&lt;/p&gt;

&lt;p&gt;While there are no restrictions in kernel mode, certain instructions cannot be executed when running in user mode.&lt;/p&gt;

&lt;p&gt;In Linux, only the kernel operates in kernel mode and can access devices. In contrast, processes operate in user mode and cannot access devices. Therefore, processes access devices indirectly through the kernel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7lsvw376yvi0dznxhwz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7lsvw376yvi0dznxhwz.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The functionality of accessing devices, including storage devices, through the kernel is described in detail in Chapter 6.&lt;/p&gt;

&lt;p&gt;In addition to the device control mentioned above, the kernel centrally manages resources shared by all processes in the system and allocates them to processes running on the system. The program that operates in kernel mode for this purpose is the kernel itself.&lt;/p&gt;

&lt;h1&gt;
  
  
  System Calls
&lt;/h1&gt;

&lt;p&gt;System calls are a method for processes to request the kernel to perform tasks. They are used when the kernel's help is needed, such as creating new processes or operating hardware.&lt;/p&gt;

&lt;p&gt;Examples of system calls include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating and deleting processes&lt;/li&gt;
&lt;li&gt;Allocating and deallocating memory&lt;/li&gt;
&lt;li&gt;Communication processing&lt;/li&gt;
&lt;li&gt;File system operations&lt;/li&gt;
&lt;li&gt;Device operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;System calls are implemented by executing special instructions on the CPU. As previously mentioned, processes run in user mode, but when a system call is issued to request the kernel for processing, an event called an exception occurs on the CPU (exceptions are explained in the "Page Tables" section of Chapter 4). Triggered by this event, the CPU transitions from user mode to kernel mode, and the kernel processing corresponding to the request begins. Once the system call processing within the kernel is complete, the CPU returns to user mode and the process continues its operation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxd7mx81zzop7lcbh350d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxd7mx81zzop7lcbh350d.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the beginning of the system call processing, the kernel checks whether the request from the process is legitimate (e.g., whether it is not requesting an amount of memory that does not exist in the system). If the request is illegitimate, the system call fails.&lt;/p&gt;

&lt;p&gt;There is no way for a process to change the CPU mode directly without going through a system call. If there were, there would be no point in having a kernel. For example, if a malicious user were to change the CPU to kernel mode from a process and directly operate a device, they could eavesdrop on or destroy other users' data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing System Call Invocations
&lt;/h2&gt;

&lt;p&gt;You can check what system calls a process issues using the &lt;code&gt;strace&lt;/code&gt; command. Let's try running a simple &lt;code&gt;hello&lt;/code&gt; program that only outputs the string "hello world" through &lt;code&gt;strace&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

package main

import (
    "fmt"
)

func main() {
    fmt.Println("hello world")
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;First, build and run the program without &lt;code&gt;strace&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;go build hello.go
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./hello
&lt;span class="go"&gt;hello world


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As expected, it displayed "hello world". Now let's see what system calls this program issues using &lt;code&gt;strace&lt;/code&gt;. You can specify the output destination of &lt;code&gt;strace&lt;/code&gt; with the "-o" option.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;strace &lt;span class="nt"&gt;-o&lt;/span&gt; hello.log ./hello
&lt;span class="go"&gt;hello world


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The program terminated with the same output as before. Now let's take a look at the contents of "hello.log", which contains the output of &lt;code&gt;strace&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;hello.log
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;write(1, "hello world\n", 12)           = 12 ... (1)
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output of &lt;code&gt;strace&lt;/code&gt; corresponds to one system call per line. You can ignore the detailed numerical values and just look at the string at the beginning of each line. From line (1), you can see that the program is using the &lt;code&gt;write()&lt;/code&gt; system call to output the string "hello world\n" (where \n represents a newline character) to the screen or a file.&lt;/p&gt;

&lt;p&gt;In my environment, totally 150 system calls were issued. Most of these were issued by the program's startup and shutdown processes (which are also provided by the operating system) and are not something you need to worry about.&lt;/p&gt;

&lt;p&gt;Regardless of the programming language used, when a program requests processing from the kernel, it issues a system call. Let's confirm this by examining the &lt;code&gt;hello.py&lt;/code&gt; program shown below, which is a program that performs the same thing as the &lt;code&gt;hello&lt;/code&gt; program written in Python.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

#!/usr/bin/python3

print("hello world")


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's run this &lt;code&gt;hello.py&lt;/code&gt; program through &lt;code&gt;strace&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;strace &lt;span class="nt"&gt;-o&lt;/span&gt; hello.py.log ./hello.py
&lt;span class="go"&gt;hello world


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's take a look at the trace information.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;hello.py.log
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;write(1, "hello world\n", 12)           = 12   ... (2)
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Looking at (2), you can see that, just like the &lt;code&gt;hello&lt;/code&gt; program, the &lt;code&gt;write()&lt;/code&gt; system call is issued. Try writing a &lt;code&gt;hello&lt;/code&gt; program equivalent in your favorite language and experiment with various things. Also, it might be interesting to run more complex programs through &lt;code&gt;strace&lt;/code&gt;. However, be aware that the output of &lt;code&gt;strace&lt;/code&gt; tends to be large, so be careful not to exhaust your file system capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proportion of time spent processing system calls
&lt;/h2&gt;

&lt;p&gt;You can find out the proportion of instructions executed by the logical CPUs&lt;sup id="fnref4"&gt;4&lt;/sup&gt; installed in the system using the &lt;code&gt;sar&lt;/code&gt; command. First, let's try to collect information on what kind of processing CPU core 0 is executing using the &lt;code&gt;sar -P 0 1 1&lt;/code&gt; command. The "-P 0" option means to collect data for logical CPU 0, the next "1" means to collect every second, and the last "1" means to collect data only once.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sar &lt;span class="nt"&gt;-P&lt;/span&gt; 0 1 1
&lt;span class="go"&gt;Linux 5.4.0-66-generic (coffee)         3/26/23  _x86_64_        (8 CPU)

09:51:03     CPU     %user     %nice   %system   %iowait    %steal     %idle ... (1)
09:51:04       0      0.00      0.00      0.00      0.00      0.00    100.00
Average:          0      0.00      0.00      0.00      0.00      0.00    100.00


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let me explain how to read this output. (1) is the header line, and the next line outputs information on how the logical CPU indicated in the second field was used for the purpose from the first field of the header line ("09:51:03") to the first field of the next line ("09:51:04").&lt;/p&gt;

&lt;p&gt;There are six types of purpose of CPU usage, from the third field ("%user") to the eighth field ("%idle"), each expressed as a percentage, and their sum equals 100. The proportion of time spent executing processes in user mode is obtained by the sum of "%user" and "%nice" (the difference between "%user" and "%nice" is described in the "Time slice mechanism" column in Chapter 3). "%system" is the proportion of time spent processing system calls by the kernel, and "%idle" shows the proportion of time spent in idle state when nothing is done. We will omit the others here.&lt;/p&gt;

&lt;p&gt;In the output above, "%idle" was "100.00". This means that the CPU was doing almost nothing.&lt;/p&gt;

&lt;p&gt;Now, let's look at the output of &lt;code&gt;sar&lt;/code&gt; while running the &lt;code&gt;inf-loop.py&lt;/code&gt; program, which only does an infinite loop, in the background.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

#!/usr/bin/python3

while True:
    pass


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We will use the &lt;code&gt;taskset&lt;/code&gt; command provided by the OS to run the &lt;code&gt;inf-loop.py&lt;/code&gt; program on CPU0. By executing &lt;code&gt;taskset -c&lt;/code&gt; , you can run the command on a specific CPU specified by the "-c" argument. While running this command in the background, let's collect statistical information using the &lt;code&gt;sar -P 0 1 1&lt;/code&gt; command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;taskset &lt;span class="nt"&gt;-c&lt;/span&gt; 0 ./inf-loop.py &amp;amp;
&lt;span class="go"&gt;[1] 1911
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sar &lt;span class="nt"&gt;-P&lt;/span&gt; 0 1 1
&lt;span class="go"&gt;Linux 5.4.0-66-generic (coffee)         2021年02月27日  _x86_64_        (8 CPU)

09時59分57秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
09時59分58秒       0    100.00      0.00      0.00      0.00      0.00      0.00  ... (1)
Average:          0    100.00      0.00      0.00      0.00      0.00      0.00


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;From (1), we can see that "%user" was "10"0 because the &lt;code&gt;inf-loop.py&lt;/code&gt; program was constantly running on logical CPU0. The state of logical CPU0 at this time is shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrxqt5pzy6x8yi67wmt5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrxqt5pzy6x8yi67wmt5.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the experiment is over, terminate the &lt;code&gt;inf-loop.py&lt;/code&gt; program with &lt;code&gt;kill&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;kill &lt;/span&gt;1911
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, let's do the same thing with the &lt;code&gt;syscall-inf-loop.py&lt;/code&gt; program, which continuously issues the simple system call &lt;code&gt;getppid()&lt;/code&gt; to get the parent process's process ID.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

#!/usr/bin/python3

import os

while True:
    os.getppid()


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;taskset &lt;span class="nt"&gt;-c&lt;/span&gt; 0 ./syscall-inf-loop.py &amp;amp;
&lt;span class="go"&gt;[1] 2005
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sar &lt;span class="nt"&gt;-P&lt;/span&gt; 0 1 1
&lt;span class="go"&gt;Linux 5.4.0-66-generic (coffee)         2021年02月27日  _x86_64_        (8 CPU)

10時03分58秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
10時03分59秒       0     35.00      0.00     65.00      0.00      0.00      0.00  ... (1)
Average:          0     35.00      0.00     65.00      0.00      0.00      0.00


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This time, because the system call is constantly being issued, "%system" has increased. The state of the CPU at this time is as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdq99o7vdsnrftsd7atnn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdq99o7vdsnrftsd7atnn.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that the experiment is over, please terminate the &lt;code&gt;syscall-inf-loop&lt;/code&gt; afterwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Column: Monitoring, Alerting, and Dashboards
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, collecting system statistical information using tools like the &lt;code&gt;sar&lt;/code&gt; command is crucial for ensuring that the system is functioning as expected. In business systems, it is common to continuously collect such statistical information. This kind of mechanism is called monitoring. Nowadays, for example, &lt;a href="https://github.com/prometheus/prometheus" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt; is one of the attractive options of monitoring tool.&lt;/p&gt;

&lt;p&gt;It's difficult for humans to visually monitor statistical information, so it's common to use an alerting function along with monitoring tools. This function allows humans to define in advance what constitutes a normal state and notifies administrators or operators when an anomaly occurs. Alerting tools may be integrated with monitoring tools, but they can also be standalone software, such as &lt;a href="https://github.com/prometheus/alertmanager" rel="noopener noreferrer"&gt;Alert Manager&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ultimately, humans will troubleshoot when the system enters an abnormal state, but examining a list of numbers alone is inefficient for investigation. Therefore, a dashboard feature that visualizes the collected data is also commonly used. This feature can also be integrated with monitoring or alerting tools or used as standalone software, such as &lt;a href="https://github.com/grafana/grafana" rel="noopener noreferrer"&gt;Grafana Dashboards&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Duration of System Calls
&lt;/h2&gt;

&lt;p&gt;By adding the "-T" option to &lt;code&gt;strace&lt;/code&gt;, you can know how much time was consumed for system calls with microsecond precision. This feature is useful for determining which system calls are taking time when the "%system" is high. The following is the result of running &lt;code&gt;strace -T&lt;/code&gt; on the &lt;code&gt;hello&lt;/code&gt; program.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;strace &lt;span class="nt"&gt;-T&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; hello.log ./hello
&lt;span class="go"&gt;hello world
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;hello.log
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="gp"&gt;write(1, "hello world\n", 12)           = 12 &amp;lt;0.000017&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this case, for example, it took 17 microseconds for the process to output the string "hello world\n".&lt;/p&gt;

&lt;p&gt;strace also has other options, such as the "-tt" option, which displays the issuance time of system calls in microseconds. Use them as needed, depending on your requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/how-linux-works-chapter1-linux-overview-part2-i0o"&gt;next part&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  NOTE
&lt;/h1&gt;

&lt;p&gt;This article is based on &lt;a href="https://amzn.to/3K9q9Ke" rel="noopener noreferrer"&gt;my book&lt;/a&gt; written in Japanese. Please contact me via &lt;a href="mailto:satoru.takeuchi@gmail.com"&gt;satoru.takeuchi@gmail.com&lt;/a&gt; if you're interested in publishing this book's English version.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;To be precise, programs like firmware and boot loaders run before that. This will be explained in Chapter 2's "Parent-Child Relationship of Processes" section. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;In the worst case, the device may be broken and become unusable. Such a device is commonly called "brick". ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;For example, there are four CPU modes in the x86_64 architecture, but the Linux kernel only uses two of them. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;Kernel recognizes a unit as a logical CPU. If there is one core, it corresponds to one CPU; if there is a multicore CPU, it corresponds to one core; and in a system that enables SMT (refer to the "Simultaneous Multi-Threading (SMT)" section in Chapter 8), it indicates a thread within a CPU core. For simplicity in this book, we will use the term "logical CPU". ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>Various Things About Command-line Arguments for Linux Processes</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Sat, 25 Mar 2023 08:42:40 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/various-things-about-command-line-arguments-for-linux-processes-522b</link>
      <guid>https://dev.to/satorutakeuchi/various-things-about-command-line-arguments-for-linux-processes-522b</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;When you execute a command like "foo bar baz", the command-line arguments are typically "foo", "bar", and "baz". Although you might think that the arguments are only "bar" and "baz", this is the definition anyway.&lt;/p&gt;

&lt;p&gt;In C and C++, command-line arguments can be referenced from the &lt;code&gt;argv&lt;/code&gt; array argument of the &lt;code&gt;main&lt;/code&gt; function in the program. In the example above, the executable name is stored in &lt;code&gt;argv[0]&lt;/code&gt;. The "bar" after that is in &lt;code&gt;argv[1]&lt;/code&gt;, and "baz" is in &lt;code&gt;argv[2]&lt;/code&gt;. The variable equivalent to argv is "$0","$1","$2"... in shell scripts, &lt;code&gt;sys.argv&lt;/code&gt; in Python, and &lt;code&gt;os.Args&lt;/code&gt; in Go, etc. However, scripts such as shell scripts and Python scripts do not directly expose command-line arguments like C, but show slightly modified ones. This will be discussed later.&lt;/p&gt;

&lt;h1&gt;
  
  
  About the first element of command-line arguments
&lt;/h1&gt;

&lt;p&gt;The first element of command-line arguments (hereafter referred to as &lt;code&gt;argv[0]&lt;/code&gt;) conventionally contains the name of the executable. When executing a program, regardless of the language in which the program is written, the &lt;code&gt;execve()&lt;/code&gt; system call shown below is eventually called, specifying the program's executable name in the pathname argument and the command-line arguments in the &lt;code&gt;argv&lt;/code&gt; argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;execve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;envp&lt;/span&gt;&lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this time, following the convention, the same value is specified for pathname and &lt;code&gt;argv[0]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When would you set &lt;code&gt;argv[0]&lt;/code&gt; to something other than the name of the executable? For example, when bash is a login shell, &lt;code&gt;argv[0]&lt;/code&gt; is not bash but rather "-bash" with a "-" at the beginning. This allows bash to know whether it is a login shell at the time of execution, and to branch its processing accordingly (such as changing the configuration file to be loaded). We will actually verify the value of &lt;code&gt;argv[0]&lt;/code&gt; for bash in the next section.&lt;/p&gt;

&lt;p&gt;When executing a program, if the executable is run through an interpreter like a bash script, the interpreter's executable name, not the script name, is stored in &lt;code&gt;argv[0]&lt;/code&gt;. For example, if there is a bash script called "test.sh", when executing "./test.sh", &lt;code&gt;argv[0]&lt;/code&gt; is the executable name of bash, and "./test.sh" is stored in &lt;code&gt;argv[1]&lt;/code&gt;. However, this is hard to handle for programmers. So in bash, you can access &lt;code&gt;argv[0]&lt;/code&gt; with "$0" and &lt;code&gt;argv[1]&lt;/code&gt; with "$1". We will actually verify this in a later section as well.&lt;/p&gt;

&lt;h1&gt;
  
  
  Verifying the values of a process's command-line arguments using procfs
&lt;/h1&gt;

&lt;p&gt;The command-line arguments of each process can be referenced from &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/cmdline&lt;/code&gt;. For example, on the Linux machine where the author is currently logged in via ssh, the command-line arguments for &lt;code&gt;rsyslogd&lt;/code&gt;, which collects system logs, were as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;sat@tea:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pgrep rsyslogd
&lt;span class="go"&gt;568
&lt;/span&gt;&lt;span class="gp"&gt;sat@tea:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/568/cmdline
&lt;span class="go"&gt;/usr/sbin/rsyslogd-n-iNONEsat@tea:~
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output looks a bit odd. A command-option-like string is connected after the executable-name-like string "/usr/sbin/rsyslogd". Moreover, there is no newline before the next prompt. This is not because the &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/cmdline&lt;/code&gt; outputs all arguments without any delimiters such as " " by design. In fact, each argument is separated by a null character (a byte with a value of 0, or "\0" in C) and bash does not display the null character on the screen. We can use binary dump tools like &lt;code&gt;hexdump&lt;/code&gt; to confirm this behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;hexdump &lt;span class="nt"&gt;-c&lt;/span&gt; /proc/568/cmdline
&lt;span class="go"&gt;0000000   /   u   s   r   /   s   b   i   n   /   r   s   y   s   l   o
0000010   g   d  \0   -   n  \0   -   i   N   O   N   E  \0           
000001d
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at the &lt;code&gt;argv[0]&lt;/code&gt; of bash instances on the system. The last field of the &lt;code&gt;ps ax&lt;/code&gt; output shows the command-line arguments separated by spaces, so we'll use this to list the existing bash instances on the system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;sat@tea:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ps ax | &lt;span class="nb"&gt;grep &lt;/span&gt;bash
&lt;span class="go"&gt;   5239 pts/3    Ss+    0:00 /usr/bin/bash --init-file /home/sat/.vscode-server/bin/74b1f979648cc44d385a2286793c226e611f59e7/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh
   8725 pts/4    Ss     0:00 -bash
   8907 pts/4    S      0:00 /bin/bash ./test.sh
   8909 pts/4    S      0:00 /bin/bash ./test.sh
   8929 pts/4    S+     0:00 grep --color=auto bash
for p ax 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the processes with pid 5239, 8725, 8907, and 8909 are bash instances. Among them, the process with pid=8725, where the first character of &lt;code&gt;argv[0]&lt;/code&gt; is "-", is the login shell where the author is running the above commands.&lt;/p&gt;

&lt;p&gt;Thus, in reality, &lt;code&gt;argv[0]&lt;/code&gt; is "/usr/sbin/rsyslogd", &lt;code&gt;argv[1]&lt;/code&gt; is "-n", and &lt;code&gt;argv[2]&lt;/code&gt; is "-iNONE".&lt;/p&gt;

&lt;p&gt;Let's also take a look at an example of a bash script. The script we'll use here outputs "$0" and then sleeps indefinitely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;sat@tea:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;test.sh
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;/bin/bash
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;echo $&lt;/span&gt;0
&lt;span class="go"&gt;
sleep infinity
&lt;/span&gt;&lt;span class="gp"&gt;sat@tea:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./test.sh
&lt;span class="go"&gt;fg
&lt;/span&gt;&lt;span class="gp"&gt;./test.sh #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Output of &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="go"&gt;^Z
[2]+  Stopped                 ./test.sh
&lt;/span&gt;&lt;span class="gp"&gt;sat@tea:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bg&lt;/span&gt;
&lt;span class="go"&gt;[2]+ ./test.sh &amp;amp;
&lt;/span&gt;&lt;span class="gp"&gt;sat@tea:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;hexdump &lt;span class="nt"&gt;-c&lt;/span&gt; /proc/8909/cmdline
&lt;span class="go"&gt;0000000   /   b   i   n   /   b   a   s   h  \0   .   /   t   e   s   t
0000010   .   s   h  \0                                               
0000014
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the value of "$0" is the script name "./test.sh", the value of &lt;code&gt;argv[0]&lt;/code&gt; is "/bin/bash", and the script name is in &lt;code&gt;argv[1]&lt;/code&gt;. This means that although it appears to the user as if they are directly executing the "./test.sh" file, the actual program running is bash. Bash interprets and executes the script, mapping &lt;code&gt;argv[1]&lt;/code&gt; and beyond to $0 and later variables within the program.&lt;/p&gt;

&lt;h1&gt;
  
  
  Differences between the command name and command line arguments held by the kernel
&lt;/h1&gt;

&lt;p&gt;Please note that the &lt;code&gt;argv[0]&lt;/code&gt; mentioned in this article, which "usually contains the executable file name," is different from the command name seen by the kernel, which is displayed by commands like &lt;code&gt;ps&lt;/code&gt;. For more information on the command name from the kernel's perspective, please refer to the following article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/satorutakeuchi/command-name-from-the-perspective-of-the-linux-kernel-257l"&gt;https://dev.to/satorutakeuchi/command-name-from-the-perspective-of-the-linux-kernel-257l&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The command name seen by the kernel is the "first 15 bytes of the basename of the executable file name" and is different from &lt;code&gt;argv[0]&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I hope this article will reduce confusion about command names, executable file names, command line arguments, and the command line arguments that can be referenced from within the program's source code.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>command</category>
      <category>arguent</category>
    </item>
    <item>
      <title>"Command name" from the perspective of the Linux kernel.</title>
      <dc:creator>Satoru Takeuchi</dc:creator>
      <pubDate>Fri, 24 Mar 2023 00:28:57 +0000</pubDate>
      <link>https://dev.to/satorutakeuchi/command-name-from-the-perspective-of-the-linux-kernel-257l</link>
      <guid>https://dev.to/satorutakeuchi/command-name-from-the-perspective-of-the-linux-kernel-257l</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Those of you who use Linux probably execute various commands on Linux on a daily basis. You might use the term "command name" to identify these, but depending on the context, the meaning of this term can vary. This article explains what the Linux kernel considers a command name.&lt;/p&gt;

&lt;p&gt;First, I will present a brief conclusion, followed by a detailed explanation, and finally, I will describe the motivation for this investigation and the subsequent research process.&lt;/p&gt;

&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;From the Linux kernel's perspective, the command name is the first 15 bytes of the basename of the executable file name (the file name without the directory part).&lt;br&gt;
It is stored as a NULL-terminated string in a 16-byte field called &lt;code&gt;comm&lt;/code&gt; within a structure called &lt;code&gt;task_struct&lt;/code&gt;, which exists for each process in the kernel's memory (more precisely, for each kernel-level thread).&lt;br&gt;
This enables the kernel to identify processes with low cost and higher readability than using a pid.&lt;br&gt;
This command name is used in kernel logs, by commands such as &lt;code&gt;ps&lt;/code&gt; and &lt;code&gt;pgrep&lt;/code&gt;, and in packages like &lt;code&gt;procps&lt;/code&gt;. Longer command names are truncated due to the 15-byte limit mentioned above.&lt;/p&gt;
&lt;h1&gt;
  
  
  Investigation Process
&lt;/h1&gt;

&lt;p&gt;Software versions used for the investigation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux kernel: v5.15&lt;/li&gt;
&lt;li&gt;Procps: 3.3.17&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;The motivation for investigating what was mentioned in the "TL;DR" section came from the fact that the &lt;code&gt;pgrep&lt;/code&gt; command I used in my custom program did not work correctly. The &lt;code&gt;pgrep&lt;/code&gt; command takes a string specified as an argument as a regular expression and retrieves a list of pids of running processes that match it. For example, below is an example of running an infinitely sleeping script called "foo.sh" and then using &lt;code&gt;pgrep&lt;/code&gt; to display its pid.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;foo.sh
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;/bin/bash
&lt;span class="go"&gt;
sleep infinity
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./foo.sh &amp;amp;
&lt;span class="go"&gt;[2] 1086408
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pgrep &lt;span class="s2"&gt;"foo&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;sh"&lt;/span&gt;
&lt;span class="go"&gt;1086408
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, when I tried the same thing with a script called "foo-bar-baz-hoge-huga.sh" that does exactly the same thing as "foo.sh", grep did not display anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;foo-bar-baz-hoge-huga.sh
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;/bin/bash
&lt;span class="go"&gt;
sleep infinity
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./foo-bar-baz-hoge-huga.sh &amp;amp;
&lt;span class="go"&gt;[2] 1086868
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pgrep &lt;span class="s2"&gt;"foo-bar-baz-hoge-huga&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;sh"&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I thought it was odd, so I looked at man &lt;code&gt;pgrep&lt;/code&gt; and found the following description.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The process name used for matching is limited to the 15 characters present in the output of /proc/pid/stat.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In fact, when I looked at the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file for "foo-bar-baz-hoge-huga.sh", I got the following output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/601235/stat
&lt;span class="go"&gt;601235 (foo-bar-baz-hog) S 593786 601235 593786 34817 601419 4194304 224 0 0 0 0 0 0 0 20 0 1 0 5735606 8617984 900 18446744073709551615 94266299658240 94266300571405 140732967030208 0 0 0 65536 4 65538 1 0 0 17 1 0 0 0 0 0 94266300816048 94266300864080 94266304847872 140732967036675 140732967036712 140732967036712 140732967038941 0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The string displayed inside the parentheses in the second field, which shows the command name, did indeed match only the first 15 characters of the script name, not the entire name.&lt;/p&gt;

&lt;p&gt;Although I understood the specification itself and realized that my usage of pgrep was incorrect, I decided to verify where this 15-character limit came from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the procfs Manual
&lt;/h2&gt;

&lt;p&gt;The files under the &lt;code&gt;/proc/&lt;/code&gt; directory are provided by a file system called &lt;code&gt;procfs&lt;/code&gt;. Unlike file systems such as &lt;code&gt;ext4&lt;/code&gt; or &lt;code&gt;XFS&lt;/code&gt; that manage data on disk, &lt;code&gt;procfs&lt;/code&gt; exists for users to obtain kernel information and modify the kernel state through files. We will not go into the details of &lt;code&gt;procfs here&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, let's check the specifications of the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file. The specifications of files under procfs are described in man procfs. The following is an excerpt of the relevant part:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/proc/[pid]/stat&lt;br&gt;
              Status information about the process.  This is used by ps(1).  It is defined in the kernel source file fs/proc/array.c.&lt;br&gt;
...&lt;br&gt;
              (2) comm  %s&lt;br&gt;
                     The  filename  of the executable, in parentheses.  Strings longer than TASK_COMM_LEN (16) characters (including the terminating null byte) are silently truncated.  This is visible&lt;br&gt;
                     whether or not the executable is swapped out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can see that the second field of the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file contains the name of the executable file in parentheses, and that any part exceeding 16 bytes, including the NULL terminating string, is ignored. Subtracting 1 byte for the NULL character from 16 bytes gives us 15 bytes, which matches the information written in the &lt;code&gt;pgrep&lt;/code&gt; manual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying the handler for the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file
&lt;/h2&gt;

&lt;p&gt;Next, I looked at the kernel source to see where this string is actually being output and where the data is stored. The &lt;code&gt;procfs&lt;/code&gt; manual states that the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file is defined in the &lt;code&gt;fs/proc/array.c&lt;/code&gt; file in the kernel source, so I first looked at this file.&lt;/p&gt;

&lt;p&gt;The relevant code seems to be in the following part of the &lt;code&gt;do_task_stat()&lt;/code&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/v5.15/fs/proc/array.c#L562-L564" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/v5.15/fs/proc/array.c#L562-L564&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the &lt;code&gt;seq_puts()&lt;/code&gt; function is called, it outputs the specified string to a file. In the code above, lines 562 and 564 output "(" and ")", and it can be inferred that the command name is probably being output to a file by the &lt;code&gt;proc_task_name()&lt;/code&gt; function on line 563.&lt;/p&gt;

&lt;p&gt;Before looking at the contents of &lt;code&gt;proc_task_name()&lt;/code&gt;, I decided to first check if the &lt;code&gt;do_task_stat()&lt;/code&gt; function is actually called when the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file is read. I traced the call stack of the &lt;code&gt;do_task_stat()&lt;/code&gt; function and found that it is called in sequence from two functions, &lt;code&gt;proc_tid_stat()&lt;/code&gt; and &lt;code&gt;proc_tgid_stat()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/v5.15/fs/proc/array.c#L646-L656" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/v5.15/fs/proc/array.c#L646-L656&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the kernel, &lt;code&gt;tid&lt;/code&gt; refers to the thread ID, and &lt;code&gt;tgid&lt;/code&gt; refers to the process name, so we can guess that the &lt;code&gt;proc_tgid_stat()&lt;/code&gt; function is probably the caller. There are functions that display the state of threads under the &lt;code&gt;/proc/pid/task&lt;/code&gt; directory in procfs, so the &lt;code&gt;proc_tid_stat()&lt;/code&gt; function is probably the handler for the &lt;code&gt;/proc/pid/task/tid&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Tracing further back the call stack of these functions, I found that in the &lt;code&gt;proc/pid/base.c&lt;/code&gt; file, which registers handlers to be called when users read and write files in &lt;code&gt;procfs&lt;/code&gt;, the &lt;code&gt;proc_tgid_stat()&lt;/code&gt; function is registered to be called when accessing the &lt;code&gt;/proc/tgid/stat&lt;/code&gt; file, or in other words, the &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/stat&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/v5.15/fs/proc/base.c#L3168-L3202" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/v5.15/fs/proc/base.c#L3168-L3202&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In summary, I found the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user reads the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;proc_tgid_stat()&lt;/code&gt; function is called&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;do_task_stat()&lt;/code&gt; function is called&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;proc_task_name()&lt;/code&gt; function is called to output the command name to the file&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Identifying the source of the command name information
&lt;/h2&gt;

&lt;p&gt;Upon examining the implementation of the &lt;code&gt;proc_task_name()&lt;/code&gt; function, it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/v5.15/fs/proc/array.c#L99-L112" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/v5.15/fs/proc/array.c#L99-L112&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will omit the details, but when the process indicated by the pid is a regular program, the evaluation result of the if statement on line 103 is false. This evaluation result is true only in the case of special processes created within the kernel.&lt;/p&gt;

&lt;p&gt;Furthermore, since the escape argument of the &lt;code&gt;proc_task_name()&lt;/code&gt; function is true when called via the &lt;code&gt;proc_tgid_stat()&lt;/code&gt; function, the evaluation result of the if statement on line 108 is true. Therefore, we can see that the data obtained by the &lt;code&gt;__get_task_comm()&lt;/code&gt; function (probably a NULL-terminated string) is being used as the output for the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file on line 109 within the &lt;code&gt;proc_task_name()&lt;/code&gt; function. The &lt;code&gt;seq_escape_str()&lt;/code&gt; function on line 109 escapes special characters and spaces, but I will not explain the details here as it is not important for this article.&lt;/p&gt;

&lt;p&gt;Now, let's look at the contents of the &lt;code&gt;__get_task_comm()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/v5.15/fs/exec.c#L1209-L1215" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/v5.15/fs/exec.c#L1209-L1215&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that the value of &lt;code&gt;tsk-&amp;gt;comm&lt;/code&gt;, or more precisely, the value of the comm field of a structure named &lt;code&gt;task_struct&lt;/code&gt;, is the source of the command name information. The &lt;code&gt;task_struct&lt;/code&gt; structure exists for each thread. Let's take a look at the definition of the &lt;code&gt;task_struct&lt;/code&gt; structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L727-L1063" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L727-L1063&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L276-L282" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L276-L282&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that the &lt;code&gt;comm&lt;/code&gt; field is an array of char with a length of 16. The &lt;code&gt;procfs&lt;/code&gt; manual also mentioned that the length of &lt;code&gt;TASK_COMM_LEN&lt;/code&gt;is 16 bytes.&lt;/p&gt;

&lt;p&gt;Confirming where the value of &lt;code&gt;task_struct-&amp;gt;comm&lt;/code&gt; is set&lt;br&gt;
The &lt;code&gt;__set_task_struct()&lt;/code&gt; function sets the value of &lt;code&gt;task_struct-&amp;gt;comm&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/v5.15/fs/exec.c#L1223-L1230" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/v5.15/fs/exec.c#L1223-L1230&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The caller of the &lt;code&gt;__set_task_struct()&lt;/code&gt; function is the &lt;code&gt;begin_new_exec()&lt;/code&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/blob/v5.15/fs/exec.c#L1238-L1357" rel="noopener noreferrer"&gt;https://github.com/torvalds/linux/blob/v5.15/fs/exec.c#L1238-L1357&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This function is called when the &lt;code&gt;execve()&lt;/code&gt; system call, which creates a new process, is invoked. &lt;code&gt;The bprm-&amp;gt;filename&lt;/code&gt; contains the name of the executable file corresponding to the process as a NULL-terminated string. Here, we can see that the name of the executable file is processed using the &lt;code&gt;kbasename()&lt;/code&gt; function and then saved in &lt;code&gt;task-&amp;gt;comm&lt;/code&gt;. The &lt;code&gt;kbasename()&lt;/code&gt; function, similar to the &lt;code&gt;basename()&lt;/code&gt; function in the standard C library, returns a string with the directory part of the file name removed. Therefore, if the executable file name is "./foo.sh", "foo.sh" will be stored in &lt;code&gt;task_struct-&amp;gt;comm&lt;/code&gt;, and if it's "./foo-bar-baz-hoge-huga.sh", "foo-bar-baz-hog" will be stored. Finally, I understood the definition of the "command name" in the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file, or, in other words, as referred to by the Linux kernel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examining the procps source code
&lt;/h2&gt;

&lt;p&gt;Lastly, by reading the procps source code, I found out that the string output by &lt;code&gt;pgrep&lt;/code&gt; is, as described in the man page, the longest 15 characters excluding the "(" and ")" from the second field of the &lt;code&gt;/proc/pid/stat&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Since there is nothing particularly interesting going on.&lt;/p&gt;

&lt;h1&gt;
  
  
  Column: Considering the Definition of Command Names
&lt;/h1&gt;

&lt;p&gt;We now understand that the command name, as referred to by the Linux kernel, is the first 15 bytes of the basename of the executable file. However, why is it processed with the basename, and why is it truncated to a maximum of 15 bytes? The reasons are probably as follows:&lt;/p&gt;

&lt;p&gt;To identify processes through kernel logs and other means, it is convenient to have easily accessible information in the form of a string, separate from the process ID (pid). The name of the executable file can be used for this purpose. However, storing the full executable file name in the &lt;code&gt;task_struct&lt;/code&gt; structure may consume a large amount of kernel memory and could potentially create a security vulnerability if a malicious user executed a program with an excessively long file name. Therefore, storing the entire file name is not feasible.&lt;/p&gt;

&lt;p&gt;One might think that it would be sufficient to look at the value of the executable file name stored in the process memory. However, this is not necessarily true. When accessing the process memory from the kernel, if the relevant memory might be swapped out, it is necessary to swap it back in before reading, which can be cumbersome. Moreover, this approach cannot be used in situations where the system is running out of memory, for instance, when the kernel needs to log the lack of memory. It is not possible to increase memory usage when there is already a shortage.&lt;/p&gt;

&lt;p&gt;The reason for using the basename, such as "foo.sh" instead of the file name or full path specified at runtime like "./foo.sh", is likely due to the decision that the basename still provides sufficiently high visibility. In most cases, the basename is enough to recognize and identify the process without using the full path.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this article, I desceived why the command name specification in the Linux kernel is as it is. Additionally, I wrote about the process of finding answers to small questions that arise while using a computer by reading source code, allowing readers to relive the experience of source code reading. Neither of these provide immediately useful knowledge, but I hope they can serve as tidbits of information.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>command</category>
    </item>
  </channel>
</rss>
