Notes
main
main
  • Introduction
  • linuxKernel
    • tips
    • make_help
    • old linux
      • compile_linux0.11
      • TestEnvironment
      • load_setup
      • get_hard_data
    • list
    • plist
    • fifo
    • idr
    • xarray
    • rbtree
    • maple_tree
    • syscall
    • bitmap
    • page
    • page_flags
    • page_size
    • page mapcount
    • page refcount
    • folio
    • slub
      • proc_slabinfo
      • slub_theory
      • kmalloc_kfree
      • kmem_cache
      • slab_alloc
      • slab_free
      • proc_meminfo_SReclaimable_SReclaimable
    • vmalloc
    • brk
    • mmap
    • mremap
    • mprotect
    • madvise
    • read
    • write
    • shmem
    • huge_page
    • page_fault
    • rmap
    • lru
    • multi-gen-LRU
    • page_reclaim
    • page_cache
    • page_table
    • rcu
    • kvm
    • aarch64_boot
    • tracing_system
    • cache_coherence_and_memory_consistency
    • cpu_speculates
    • mmap_lock
    • per-vma_lock
    • cgroup
    • symbol
    • campact
    • page_ext
    • mempool
    • kernelstack
    • filesystem
    • io_stack
    • workingset
    • ioremap
    • sched_period
  • linuxDebug
    • openocd_openjtag
    • i2c_tools
    • objdump
    • addr2line
    • gdb_useage
    • debug_linux_kernel_via_gdb
    • debug_linux_module_via_gdb
    • early_boot
    • sequentially_execute
    • dynamic_debug
    • research_linuxKernel_by_patch
    • tracefs
    • ebpf
    • bpftrace
    • perf
    • flame_graph
    • crash
    • ASAN_HWASAN_MTE_check_mem_bug
    • page_owner
    • vmtouch
    • fio
    • benchmark
  • linuxSystem
    • common
      • system_version
      • procfs
      • proc_sys_vm
      • cmd_ps
      • makefile
      • file_descriptor
      • psi
      • ulimit
      • top
      • delay_accounting
    • ubuntu
      • custom_kernel
      • get_cmd_src
      • record_ssh_info
      • log
      • run_custom_script
      • repo
      • cockpit
      • nfs
      • tftp
      • misc
    • fedora
      • system_upgrade
      • custom_kernel
      • lvextend
      • yt-dlp
      • jellyfin
  • linuxDriver
    • i2c_peripherals_driver
    • spi_peripherals_driver
    • gpio_subsystem
    • IRQ_driver
    • blockIO_unblockIO_async
    • linux_own_driver
    • misc_device
    • input_device
    • timer
    • atomic_spinlock_semaphore_mutex
    • lcd
    • touch_screen
    • debugfs
    • v4l2
    • mmap
  • hardware
    • paging_mmu_pt
    • iommu
  • process_thread_scheduler
    • scheduler01
    • scheduler02
    • scheduler03
    • scheduler04
    • scheduler05
    • scheduler06
  • memory_management
    • mm1
    • mm2
    • mm3
    • mm4
    • mm5
  • input_output_filesystem
    • io_fs_01
    • io_fs_02
    • io_fs_03
    • io_fs_04
  • lock_and_lockup_detector
    • general_lock
    • hung_task
    • softLockup_hardLockup
    • crash_experiment
  • MIT_6.S081
    • 6.S081_Operating_System_Engineering
    • Schedule.md
    • Class
      • Overview
      • Administrivia
    • Labs
      • Tools
      • Guidance
      • startup
      • syscall
      • page_table
      • Calling_Convention
      • traps
    • xv6
      • xv6
    • References.md
  • qemu
    • qemu_buildroot
    • qemu_busybox.md
    • Serial.md
    • demo_mini2440
      • 0_compilation_error_summary
      • 1_compilation_steps
      • 2_operation_mode
      • 3_transplant_tools_libraries
      • 4_tools_use
      • reference_website
  • tools
    • getKernelSourceCodeList
    • nat
    • shell
    • translating
    • YouCompleteMe
    • cscope
    • global
    • vscode
    • vim
    • binary
    • markdown
    • draw
    • git
    • tig
    • tmux
    • mail_client
    • download_patchset_from_LKML
    • minicom
    • clash
  • other
    • interview
    • interview_c_base
    • know_dontknow
    • Stop-Ask-Questions-The-Stupid-Ways
    • How-To-Ask-Questions-The-Smart-Way
    • docker
    • buildroot
    • rv32_to_rv64
Powered by GitBook
On this page
  • 吞吐率 vs. 响应
  • CPU消耗型 vs IO消耗型
  • 优先级数组和bitmaps
  • 实时进程调度
  • (非实时)普通进程的调度和动态优先级
  • 调度相关的系统调用
  • 实例

Was this helpful?

  1. process_thread_scheduler

scheduler03

吞吐率 vs. 响应

  • 响应:最小化某个任务的响应时间,那怕牺牲其他的任务为代价

  • 吞吐:全局视野,整个系统的workload被最大化处理

因为响应与吞吐率是一个完全相反的步骤,吞吐率好--响应差,吞吐率差--响应好,不存在完美的解决方法,所以存在server ubuntu、desktop ubuntu。其中主要通过linux kernel指定响应与吞吐策略,如下:

# linux-linux2.6.34
$ make x86_64_defconfig
$ make menuconfig
Processor type and features  --->
    Preemption Model ()  --->
        ( ) No Forced Preemption (Server)
        (X) Voluntary Kernel Preemption (Desktop)
        ( ) Preemptible Kernel (Low-Latency Desktop)

CPU消耗型 vs IO消耗型

  • IO bound : CPU利用率低,进程的运行效率主要受限于I/O速度

  • CPU bound : 多数时间花在CPU上面(做运算)

  • IO消耗型进程对CPU性能 不敏感,但是对及时抢到CPU 敏感。

比如:一个IO消耗型进程执行一次操作,用时100ms,其中CPU只占1ms,99ms用在IO读写操作。

当CPU性能降低一半,CPU执行时间从原来1ms变成2ms而已,全部时间是101ms。

当进程不能及时抢到CPU时,需要等待40ms,全部时间是140ms。

因为IO消耗型进程对及时抢到CPU 敏感,所以 IO消耗型优先级 > CPU消耗型优先级。这样做的好处,IO消耗型进程能够及时抢到CPU。

因为IO消耗型进程对CPU性能 不敏感, 所以目前 ARM 一般采用big.little core模式,让IO消耗型进程在little core工作,这样做的好处,可以降低CPU功耗。

优先级数组和bitmaps

  • 优先级

总范围:[0, 139]。值越小,优先级越高;值越大,优先级越小;

范围:[0, 99]是实时进程的优先级

范围:[100, 139]是(非实时)普通进程的优先级

  • 如果某个优先级有TASK_RUNNING进程,对应的bit设置为1

  • 调度第一个bitmap设置为1的进程

实时进程调度

  • SCHED_FIFO :不同优先级,高优先级先跑到睡眠,低优先级再跑;同等优先级 先进先出

  • SCHED_RR :不同优先级,高优先级先跑到睡眠,低优先级再跑;同等优先级 轮转

  • RT门限

    在sched_rt_period_us时间内,实时进程最多只能跑sched_rt_runtime_us时间,剩下sched_rt_period_us-sched_rt_runtime_us时间给(非实时)普通进程运行。

    $ cd /proc/sys/kernel/
    $ cat sched_rt_period_us 
    1000000
    $ cat sched_rt_runtime_us 
    950000

(非实时)普通进程的调度和动态优先级

  • SCHED_NORMAL:不同优先级 轮转

  • nice范围:[-20, +19],对应优先级[100, 139]。nice值越小,优先级越高;nice值越大,优先级越小;

  • 2.6早期调度算法(已废弃):根据睡眠情况,动态奖励和惩罚

    如果分配100ms时间片给进程A,进程A立刻将时间片用光,说明进程A是CPU消耗型进程,即 将进程A nice值升高,同时再分配新100ms时间片给进程A。

    如果分配100ms时间片给进程B,进程B一直没有用,说明进程B是IO消耗型进程,即 将进程B nice值降低。

    这样动态调节nice值,让IO消耗型进程优先级高, 一旦被唤醒后,可以立刻抢占CPU。

  • 现在的调度算法:CFS(完全公平调度)

    采用红黑树把所有可执行进程组织而成,红黑树的左边节点vruntime小于右边节点的vruntime,CFS会运行最小vruntime对应的进程

    # dela        : 进程实际运行时间
    # NICE_0_LOAD : 1024
    # se.weight   : 不同nice值,对应的weight,在sched_prio_to_weight[40]中查找
    vruntime += dela * NICE_0_LOAD / se.weight;
    
    const int sched_prio_to_weight[40] = {
     /* -20 */     88761,     71755,     56483,     46273,     36291,
     /* -15 */     29154,     23254,     18705,     14949,     11916,
     /* -10 */      9548,      7620,      6100,      4904,      3906,
     /*  -5 */      3121,      2501,      1991,      1586,      1277,
     /*   0 */      1024,       820,       655,       526,       423,
     /*   5 */       335,       272,       215,       172,       137,
     /*  10 */       110,        87,        70,        56,        45,
     /*  15 */        36,        29,        23,        18,        15,
    };

调度相关的系统调用

System Call

Description

nice()

Sets a process's nice value

sched_setscheduler()

Sets a process's scheduling policy

sched_getscheduler()

Gets a process's scheduling policy

sched_setparam()

Sets a process's real-time priority

sched_getparam()

Gets a process's real-time priority

sched_get_priority_max()

Gets the maximum real-time priority

sched_get_priority_min()

Gets the minimum real-time priority

sched_rr_get_interval()

Gets a process's timeslice value

sched_setaffinity()

Sets a process's processor affinity

sched_getaffinity()

Gets a process's processor affinity

sched_yield()

Temporarily yields the processor

  1. 代码例子:

# 将进程设置为SCHED_FIFO,RT优先级为50
struct sched_param the_priority;

the_priority.sched_priority = 50;
pthread_setschedparam(pthread_self(), SCHED_FIFO, &the_priority);
  1. 命令行工具:

$ chrt -f -a -p 50 10576 # 将pid=10576进程中所有线程,设置为SCHED_FIFO,RT优先级为50

$ renice -n -5 -g 9394   # 将pid=9394进程中所有线程,对应nice值设置为 -5
or
$ nice -n -5 ./a.out     # 运行./a.out时,同时将对应nice值设置为 -5

实例

  1. 源码

$ cat two-loops.c 
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>

void *thread_fun(void *param)
{
    printf("thread pid:%d, tid:%lu\n", getpid(), pthread_self());
    while (1) ;
    return NULL;
}

int main(void)
{
    pthread_t tid1, tid2;
    int ret;

    printf("main pid:%d, tid:%lu\n", getpid(), pthread_self());

    ret = pthread_create(&tid1, NULL, thread_fun, NULL);
    if (ret == -1) {
        perror("cannot create new thread");
        return 1;
    }

    ret = pthread_create(&tid2, NULL, thread_fun, NULL);
    if (ret == -1) {
        perror("cannot create new thread");
        return 1;
    }

    if (pthread_join(tid1, NULL) != 0) {
        perror("call pthread_join function fail");
        return 1;
    }

    if (pthread_join(tid2, NULL) != 0) {
        perror("call pthread_join function fail");
        return 1;
    }

    return 0;
}
$ gcc two-loops.c -pthread
  1. 运行2个高CPU利用率程序,调整他们的nice

前提:测试电脑是2个CPU核,所以最大%CPU是200%

$ ./a.out &
main pid:2856, tid:139933770024704
thread pid:2856, tid:139933753579280
thread pid:2856, tid:139933761971984
$ ./a.out &
main pid:2859, tid:140378753423104
thread pid:2859, tid:140378745370384
thread pid:2859, tid:140378736977680
$ top
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 2856 vernon    20   0 22544  580  460 S  102  0.0   0:56.17 a.out
 2859 vernon    20   0 22544  584  460 S   98  0.0   0:52.89 a.out
$ sudo renice -n -5 -g 2856 # 将pid=2856进程中所有线程,对应nice值设置为 -5
$ top
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 2856 vernon    15  -5 22544  580  460 S  151  0.0   3:20.69 a.out
 2859 vernon    20   0 22544  584  460 S   49  0.0   2:41.34 a.out

$ killall a.out
  1. 用chrt把一个死循环程序调整为SCHED_FIFO

$ ./a.out &
$ top
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
3283 vernon    20   0 22544  584  460 S  200  0.0   0:10.28 a.out
$ sudo su - root
$ chrt -f -p 50 3283 # 将pid=3283进程,设置为SCHED_FIFO,RT优先级为50
$ top
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 3283 vernon   -51   0 22544  584  460 S  197  0.0  19:15.88 a.out
Previousscheduler02Nextscheduler04

Last updated 4 years ago

Was this helpful?