diff options
Diffstat (limited to 'Documentation')
25 files changed, 1358 insertions, 138 deletions
diff --git a/Documentation/admin-guide/blockdev/drbd/figures.rst b/Documentation/admin-guide/blockdev/drbd/figures.rst index bd9a4901fe46..9f73253ea353 100644 --- a/Documentation/admin-guide/blockdev/drbd/figures.rst +++ b/Documentation/admin-guide/blockdev/drbd/figures.rst @@ -25,6 +25,6 @@ Sub graphs of DRBD's state transitions :alt: disk-states-8.dot :align: center -.. kernel-figure:: node-states-8.dot - :alt: node-states-8.dot +.. kernel-figure:: peer-states-8.dot + :alt: peer-states-8.dot :align: center diff --git a/Documentation/admin-guide/blockdev/drbd/node-states-8.dot b/Documentation/admin-guide/blockdev/drbd/peer-states-8.dot index bfa54e1f8016..6dc3954954d6 100644 --- a/Documentation/admin-guide/blockdev/drbd/node-states-8.dot +++ b/Documentation/admin-guide/blockdev/drbd/peer-states-8.dot @@ -1,8 +1,3 @@ -digraph node_states { - Secondary -> Primary [ label = "ioctl_set_state()" ] - Primary -> Secondary [ label = "ioctl_set_state()" ] -} - digraph peer_states { Secondary -> Primary [ label = "recv state packet" ] Primary -> Secondary [ label = "recv state packet" ] diff --git a/Documentation/arc/arc.rst b/Documentation/arc/arc.rst new file mode 100644 index 000000000000..249d03c6be8e --- /dev/null +++ b/Documentation/arc/arc.rst @@ -0,0 +1,81 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Linux kernel for ARC processors +******************************* + +Other sources of information +############################ + +Below are some resources where more information can be found on +ARC processors and relevant open source projects. + +1. `<https://embarc.org/>`_ - Community portal for open source on ARC. +Good place to start to find relevant FOSS projects, toolchain releases, +news items and more. + +2. `<https://github.com/foss-for-synopsys-dwc-arc-processors>`_ - +Home for all development activities regarding open source projects for +ARC processors. Some of the projects are forks of various upstream projects, +where "work in progress" is hosted prior to submission to upstream projects. +Other projects are developed by Synopsys and made available to community +as open source for use on ARC Processors. + +3. `<https://www.synopsys.com/designware-ip/processor-solutions.html>`_ - +Official Synopsys ARC Processors website location, with access to some IP +documentation (Programmer's Reference Manuals, AKA "PRM's", see +`<https://www.synopsys.com/dw/doc.php/ds/cc/programmers-reference-manual-ARC-HS.pdf>`_) +and commercial tools (Free nSIM, +`<https://www.synopsys.com/cgi-bin/dwarcnsim/req1.cgi>`_ and +MetaWare Light Edition, `<https://www.synopsys.com/cgi-bin/arcmwtk_lite/reg1.cgi>`_) + +Important note on ARC processors configurability +################################################ + +ARC processors are highly configurable and several configurable options +are supported in Linux. Some options are transparent to software +(i.e cache geometries, some can be detected at runtime and configured +and used accordingly, while some need to be explicitly selected or configured +in the kernel's configuration utility (AKA "make menuconfig"). + +However not all configurable options are supported when an ARC processor +is to run Linux. SoC design teams should refer to "Appendix E: +Configuration for ARC Linux" in the ARC HS Databook for configurability +guidelines. + +Following these guidelines and selecting valid configuration options +up front is critical to help prevent any unwanted issues during +SoC bringup and software development in general. + +Building the Linux kernel for ARC processors +############################################ + +The process of kernel building for ARC processors is the same as for any other +architecture and could be done in 2 ways: + +1. cross-compilation: process of compiling for ARC targets on a development +host with a different processor architecture (generally x86_64/amd64). + +2. native compilation: process of compiling for ARC on a ARC platform +(hardware board or a simulator like QEMU) with complete development environment +(GNU toolchain, dtc, make etc) installed on the platform. + +In both cases, up-to-date GNU toolchain for ARC for the host is needed. +Synopsys offers prebuilt toolchain releases which can be used for this purpose, +available from: + +1. Synopsys GNU toolchain releases: +`<https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases>`_ +2. Linux kernel compilers collection: +`<https://mirrors.edge.kernel.org/pub/tools/crosstool/>`_ +3. Bootlin's toolchain collection: `<https://toolchains.bootlin.com/>`_ + +Once the toolchain is installed in the system, make sure its "bin" folder +is added in your ``PATH`` environment variable. Then set ``ARCH=arc`` & +``CROSS_COMPILE=arc-linux`` (or whatever matches installed ARC toolchain prefix) +and then as usual ``make defconfig && make``. + +This will produce "vmlinux" file in the root of the kernel source tree +usable for loading on the target system via JTAG. +If you need to get an image usable with U-Boot bootloader, +type ``make uImage`` and ``uImage`` will be produced in ``arch/arc/boot`` +folder. diff --git a/Documentation/arc/features.rst b/Documentation/arc/features.rst new file mode 100644 index 000000000000..b793583d688a --- /dev/null +++ b/Documentation/arc/features.rst @@ -0,0 +1,3 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. kernel-feat:: $srctree/Documentation/features arc diff --git a/Documentation/arc/index.rst b/Documentation/arc/index.rst new file mode 100644 index 000000000000..7b098d4a5e3e --- /dev/null +++ b/Documentation/arc/index.rst @@ -0,0 +1,17 @@ +=================== +ARC architecture +=================== + +.. toctree:: + :maxdepth: 1 + + arc + + features + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/arch.rst b/Documentation/arch.rst index f10bd32a5972..14bcd8294b93 100644 --- a/Documentation/arch.rst +++ b/Documentation/arch.rst @@ -9,6 +9,7 @@ implementation. .. toctree:: :maxdepth: 2 + arc/index arm/index arm64/index ia64/index diff --git a/Documentation/conf.py b/Documentation/conf.py index 17f7cee56987..76e5eb5cb62b 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -249,11 +249,16 @@ except ImportError: html_static_path = ['sphinx-static'] -html_context = { - 'css_files': [ - '_static/theme_overrides.css', - ], -} +html_css_files = [ + 'theme_overrides.css', +] + +if major <= 1 and minor < 8: + html_context = { + 'css_files': [ + '_static/theme_overrides.css', + ], + } # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied diff --git a/Documentation/networking/rds.rst b/Documentation/networking/rds.rst index 44936c27ab3a..498395f5fbcb 100644 --- a/Documentation/networking/rds.rst +++ b/Documentation/networking/rds.rst @@ -1,6 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 -== +=== RDS === diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index b398b8576417..cf908d79666e 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -35,6 +35,7 @@ GNU make 3.81 make --version binutils 2.23 ld -v flex 2.5.35 flex --version bison 2.0 bison --version +pahole 1.16 pahole --version util-linux 2.10o fdformat --version kmod 13 depmod -V e2fsprogs 1.41.4 e2fsck -V @@ -108,6 +109,16 @@ Bison Since Linux 4.16, the build system generates parsers during build. This requires bison 2.0 or later. +pahole: +------- + +Since Linux 5.2, if CONFIG_DEBUG_INFO_BTF is selected, the build system +generates BTF (BPF Type Format) from DWARF in vmlinux, a bit later from kernel +modules as well. This requires pahole v1.16 or later. + +It is found in the 'dwarves' or 'pahole' distro packages or from +https://fedorapeople.org/~acme/dwarves/. + Perl ---- diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst index da085d63af9b..6b3aaed66fba 100644 --- a/Documentation/process/submitting-patches.rst +++ b/Documentation/process/submitting-patches.rst @@ -14,7 +14,8 @@ works, see Documentation/process/development-process.rst. Also, read Documentation/process/submit-checklist.rst for a list of items to check before submitting code. If you are submitting a driver, also read Documentation/process/submitting-drivers.rst; for device -tree binding patches, read Documentation/process/submitting-patches.rst. +tree binding patches, read +Documentation/devicetree/bindings/submitting-patches.rst. This documentation assumes that you're using ``git`` to prepare your patches. If you're unfamiliar with ``git``, you would be well-advised to learn how to diff --git a/Documentation/scheduler/sched-bwc.rst b/Documentation/scheduler/sched-bwc.rst index 173c14110c85..f166b182ff95 100644 --- a/Documentation/scheduler/sched-bwc.rst +++ b/Documentation/scheduler/sched-bwc.rst @@ -74,7 +74,6 @@ Quota, period and burst are managed within the cpu subsystem via cgroupfs. to cgroup v1. For cgroup v2, see :ref:`Documentation/admin-guide/cgroup-v2.rst <cgroup-v2-cpu>`. -- cpu.cfs_quota_us: the total available run-time within a period (in - cpu.cfs_quota_us: run-time replenished within a period (in microseconds) - cpu.cfs_period_us: the length of a period (in microseconds) - cpu.stat: exports throttling statistics [explained further below] @@ -135,7 +134,7 @@ cpu.stat: of the group have been throttled. - nr_bursts: Number of periods burst occurs. - burst_time: Cumulative wall-time (in nanoseconds) that any CPUs has used - above quota in respective periods + above quota in respective periods. This interface is read-only. @@ -238,7 +237,7 @@ Examples additionally, in case accumulation has been done. With 50ms period, 20ms quota will be equivalent to 40% of 1 CPU. - And 10ms burst will be equivalent to 20% of 1 CPU. + And 10ms burst will be equivalent to 20% of 1 CPU:: # echo 20000 > cpu.cfs_quota_us /* quota = 20ms */ # echo 50000 > cpu.cfs_period_us /* period = 50ms */ diff --git a/Documentation/translations/zh_CN/PCI/index.rst b/Documentation/translations/zh_CN/PCI/index.rst index 5c96017e9f41..67860b7e5ac7 100644 --- a/Documentation/translations/zh_CN/PCI/index.rst +++ b/Documentation/translations/zh_CN/PCI/index.rst @@ -22,11 +22,12 @@ Linux PCI总线子系统 :numbered: pci + pciebus-howto + pci-iov-howto Todolist: - pciebus-howto - pci-iov-howto + msi-howto sysfs-pci acpi-info diff --git a/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst b/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst new file mode 100644 index 000000000000..fbc83dfdcead --- /dev/null +++ b/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst @@ -0,0 +1,170 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: <isonum.txt> +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/PCI/pci-iov-howto.rst + +:翻译: + + 司延腾 Yanteng Si <siyanteng@loongson.cn> + +:校译: + + + +.. _cn_pci-iov-howto: + +========================== +PCI Express I/O 虚拟化指南 +========================== + +:版权: |copy| 2009 Intel Corporation +:作者: - Yu Zhao <yu.zhao@intel.com> + - Donald Dutile <ddutile@redhat.com> + +概述 +==== + +什么是SR-IOV +------------ + +单根I/O虚拟化(SR-IOV)是一种PCI Express扩展功能,它使一个物理设备显示为多个 +虚拟设备。物理设备被称为物理功能(PF),而虚拟设备被称为虚拟功能(VF)。VF的分 +配可以由PF通过封装在该功能中的寄存器动态控制。默认情况下,该功能未被启用,PF表 +现为传统的PCIe设备。一旦开启,每个VF的PCI配置空间都可以通过自己的总线、设备和 +功能编号(路由ID)来访问。而且每个VF也有PCI内存空间,用于映射其寄存器集。VF设 +备驱动程序对寄存器集进行操作,这样它就可以发挥功能,并作为一个真正的现有PCI设备 +出现。 + +使用指南 +======== + +我怎样才能启用SR-IOV功能 +------------------------ + +有多种方法可用于SR-IOV的启用。在第一种方法中,设备驱动(PF驱动)将通过SR-IOV +核心提供的API控制功能的启用和禁用。如果硬件具有SR-IOV能力,加载其PF驱动器将启 +用它和与PF相关的所有VF。一些PF驱动需要设置一个模块参数,以确定要启用的VF的数量。 +在第二种方法中,对sysfs文件sriov_numvfs的写入将启用和禁用与PCIe PF相关的VF。 +这种方法实现了每个PF的VF启用/禁用值,而第一种方法则适用于同一设备的所有PF。此外, +PCI SRIOV核心支持确保启用/禁用操作是有效的,以减少同一检查在多个驱动程序中的重 +复,例如,如果启用VF,检查numvfs == 0,确保numvfs <= totalvfs。 +第二种方法是对新的/未来的VF设备的推荐方法。 + +我怎样才能使用虚拟功能 +---------------------- + +在内核中,VF被视为热插拔的PCI设备,所以它们应该能够以与真正的PCI设备相同的方式 +工作。VF需要的设备驱动与普通PCI设备的驱动相同。 + +开发者指南 +========== + +SR-IOV API +---------- + +用来开启SR-IOV功能: + +(a) 对于第一种方法,在驱动程序中:: + + int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn); + +nr_virtfn'是要启用的VF的编号。 + +(b) 对于第二种方法,从sysfs:: + + echo 'nr_virtfn' > \ + /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs + +用来关闭SR-IOV功能: + +(a) 对于第一种方法,在驱动程序中:: + + void pci_disable_sriov(struct pci_dev *dev); + +(b) 对于第二种方法,从sysfs:: + + echo 0 > \ + /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs + +要想通过主机上的兼容驱动启用自动探测VF,在启用SR-IOV功能之前运行下面的命令。这 +是默认的行为。 +:: + + echo 1 > \ + /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe + +要禁止主机上的兼容驱动自动探测VF,请在启用SR-IOV功能之前运行以下命令。更新这个 +入口不会影响已经被探测的VF。 +:: + + echo 0 > \ + /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe + +用例 +---- + +下面的代码演示了SR-IOV API的用法 +:: + + static int dev_probe(struct pci_dev *dev, const struct pci_device_id *id) + { + pci_enable_sriov(dev, NR_VIRTFN); + + ... + + return 0; + } + + static void dev_remove(struct pci_dev *dev) + { + pci_disable_sriov(dev); + + ... + } + + static int dev_suspend(struct pci_dev *dev, pm_message_t state) + { + ... + + return 0; + } + + static int dev_resume(struct pci_dev *dev) + { + ... + + return 0; + } + + static void dev_shutdown(struct pci_dev *dev) + { + ... + } + + static int dev_sriov_configure(struct pci_dev *dev, int numvfs) + { + if (numvfs > 0) { + ... + pci_enable_sriov(dev, numvfs); + ... + return numvfs; + } + if (numvfs == 0) { + .... + pci_disable_sriov(dev); + ... + return 0; + } + } + + static struct pci_driver dev_driver = { + .name = "SR-IOV Physical Function driver", + .id_table = dev_id_table, + .probe = dev_probe, + .remove = dev_remove, + .suspend = dev_suspend, + .resume = dev_resume, + .shutdown = dev_shutdown, + .sriov_configure = dev_sriov_configure, + }; diff --git a/Documentation/translations/zh_CN/PCI/pciebus-howto.rst b/Documentation/translations/zh_CN/PCI/pciebus-howto.rst new file mode 100644 index 000000000000..65c4301f12cd --- /dev/null +++ b/Documentation/translations/zh_CN/PCI/pciebus-howto.rst @@ -0,0 +1,192 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: <isonum.txt> +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/PCI/pciebus-howto.rst + +:翻译: + + 司延腾 Yanteng Si <siyanteng@loongson.cn> + +:校译: + + + +.. _cn_pciebus-howto: + +=========================== +PCI Express端口总线驱动指南 +=========================== + +:作者: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004 +:版权: |copy| 2004 Intel Corporation + +关于本指南 +========== + +本指南介绍了PCI Express端口总线驱动程序的基本知识,并提供了如何使服务驱 +动程序在PCI Express端口总线驱动程序中注册/取消注册的介绍。 + + +什么是PCI Express端口总线驱动程序 +================================= + +一个PCI Express端口是一个逻辑的PCI-PCI桥结构。有两种类型的PCI Express端 +口:根端口和交换端口。根端口从PCI Express根综合体发起一个PCI Express链接, +交换端口将PCI Express链接连接到内部逻辑PCI总线。交换机端口,其二级总线代表 +交换机的内部路由逻辑,被称为交换机的上行端口。交换机的下行端口是从交换机的内部 +路由总线桥接到代表来自PCI Express交换机的下游PCI Express链接的总线。 + +一个PCI Express端口可以提供多达四个不同的功能,在本文中被称为服务,这取决于 +其端口类型。PCI Express端口的服务包括本地热拔插支持(HP)、电源管理事件支持(PME)、 +高级错误报告支持(AER)和虚拟通道支持(VC)。这些服务可以由一个复杂的驱动程序 +处理,也可以单独分布并由相应的服务驱动程序处理。 + +为什么要使用PCI Express端口总线驱动程序? +========================================= + +在现有的Linux内核中,Linux设备驱动模型允许一个物理设备只由一个驱动处理。 +PCI Express端口是一个具有多个不同服务的PCI-PCI桥设备。为了保持一个干净和简 +单的解决方案,每个服务都可以有自己的软件服务驱动。在这种情况下,几个服务驱动将 +竞争一个PCI-PCI桥设备。例如,如果PCI Express根端口的本机热拔插服务驱动程序 +首先被加载,它就会要求一个PCI-PCI桥根端口。因此,内核不会为该根端口加载其他服 +务驱动。换句话说,使用当前的驱动模型,不可能让多个服务驱动同时加载并运行在 +PCI-PCI桥设备上。 + +为了使多个服务驱动程序同时运行,需要有一个PCI Express端口总线驱动程序,它管 +理所有填充的PCI Express端口,并根据需要将所有提供的服务请求分配给相应的服务 +驱动程序。下面列出了使用PCI Express端口总线驱动程序的一些关键优势: + + - 允许在一个PCI-PCI桥接端口设备上同时运行多个服务驱动。 + + - 允许以独立的分阶段方式实施服务驱动程序。 + + - 允许一个服务驱动程序在多个PCI-PCI桥接端口设备上运行。 + + - 管理和分配PCI-PCI桥接端口设备的资源给要求的服务驱动程序。 + +配置PCI Express端口总线驱动程序与服务驱动程序 +============================================= + +将PCI Express端口总线驱动支持纳入内核 +------------------------------------- + +包括PCI Express端口总线驱动程序取决于内核配置中是否包含PCI Express支持。当内核 +中的PCI Express支持被启用时,内核将自动包含PCI Express端口总线驱动程序作为内核 +驱动程序。 + +启用服务驱动支持 +---------------- + +PCI设备驱动是基于Linux设备驱动模型实现的。所有的服务驱动都是PCI设备驱动。如上所述, +一旦内核加载了PCI Express端口总线驱动程序,就不可能再加载任何服务驱动程序。为了满 +足PCI Express端口总线驱动程序模型,需要对现有的服务驱动程序进行一些最小的改变,其 +对现有的服务驱动程序的功能没有影响。 + +服务驱动程序需要使用下面所示的两个API,将其服务注册到PCI Express端口总线驱动程 +序中(见第5.2.1和5.2.2节)。在调用这些API之前,服务驱动程序必须初始化头文件 +/include/linux/pcieport_if.h中的pcie_port_service_driver数据结构。如果不这 +样做,将导致身份不匹配,从而使PCI Express端口总线驱动程序无法加载服务驱动程序。 + +pcie_port_service_register +~~~~~~~~~~~~~~~~~~~~~~~~~~ +:: + + int pcie_port_service_register(struct pcie_port_service_driver *new) + +这个API取代了Linux驱动模型的 pci_register_driver API。一个服务驱动应该总是在模 +块启动时调用 pcie_port_service_register。请注意,在服务驱动被加载后,诸如 +pci_enable_device(dev) 和 pci_set_master(dev) 的调用不再需要,因为这些调用由 +PCI端口总线驱动执行。 + +pcie_port_service_unregister +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:: + + void pcie_port_service_unregister(struct pcie_port_service_driver *new) + +pcie_port_service_unregister取代了Linux驱动模型的pci_unregister_driver。当一 +个模块退出时,它总是被服务驱动调用。 + +示例代码 +~~~~~~~~ + +下面是服务驱动代码示例,用于初始化端口服务的驱动程序数据结构。 +:: + + static struct pcie_port_service_id service_id[] = { { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .port_type = PCIE_RC_PORT, + .service_type = PCIE_PORT_SERVICE_AER, + }, { /* end: all zeroes */ } + }; + + static struct pcie_port_service_driver root_aerdrv = { + .name = (char *)device_name, + .id_table = &service_id[0], + + .probe = aerdrv_load, + .remove = aerdrv_unload, + + .suspend = aerdrv_suspend, + .resume = aerdrv_resume, + }; + +下面是一个注册/取消注册服务驱动的示例代码。 +:: + + static int __init aerdrv_service_init(void) + { + int retval = 0; + + retval = pcie_port_service_register(&root_aerdrv); + if (!retval) { + /* + * FIX ME + */ + } + return retval; + } + + static void __exit aerdrv_service_exit(void) + { + pcie_port_service_unregister(&root_aerdrv); + } + + module_init(aerdrv_service_init); + module_exit(aerdrv_service_exit); + +可能的资源冲突 +============== + +由于PCI-PCI桥接端口设备的所有服务驱动被允许同时运行,下面列出了一些可能的资源冲突和 +建议的解决方案。 + +MSI 和 MSI-X 向量资源 +--------------------- + +一旦设备上的MSI或MSI-X中断被启用,它就会一直保持这种模式,直到它们再次被禁用。由于同 +一个PCI-PCI桥接端口的服务驱动程序共享同一个物理设备,如果一个单独的服务驱动程序启用或 +禁用MSI/MSI-X模式,可能会导致不可预知的行为。 + +为了避免这种情况,所有的服务驱动程序都不允许在其设备上切换中断模式。PCI Express端口 +总线驱动程序负责确定中断模式,这对服务驱动程序来说应该是透明的。服务驱动程序只需要知道 +分配给结构体pcie_device的字段irq的向量IRQ,当PCI Express端口总线驱动程序探测每 +个服务驱动程序时,它被传入。服务驱动应该使用(struct pcie_device*)dev->irq来调用 +request_irq/free_irq。此外,中断模式被存储在struct pcie_device的interrupt_mode +字段中。 + +PCI内存/IO映射的区域 +-------------------- + +PCI Express电源管理(PME)、高级错误报告(AER)、热插拔(HP)和虚拟通道(VC)的服务 +驱动程序访问PCI Express端口的PCI配置空间。在所有情况下,访问的寄存器是相互独立的。这 +个补丁假定所有的服务驱动程序都会表现良好,不会覆盖其他服务驱动程序的配置设置。 + +PCI配置寄存器 +------------- + +每个服务驱动都在自己的功能结构体上运行PCI配置操作,除了PCI Express功能结构体,其中根控制 +寄存器和设备控制寄存器是在PME和AER之间共享。这个补丁假定所有的服务驱动都会表现良好,不会 +覆盖其他服务驱动的配置设置。 diff --git a/Documentation/translations/zh_CN/accounting/index.rst b/Documentation/translations/zh_CN/accounting/index.rst index 362e907b41f9..124b590fb01b 100644 --- a/Documentation/translations/zh_CN/accounting/index.rst +++ b/Documentation/translations/zh_CN/accounting/index.rst @@ -16,10 +16,10 @@ :maxdepth: 1 psi + taskstats Todolist: cgroupstats delay-accounting - taskstats taskstats-struct diff --git a/Documentation/translations/zh_CN/accounting/taskstats.rst b/Documentation/translations/zh_CN/accounting/taskstats.rst new file mode 100644 index 000000000000..307ac5ce0e4b --- /dev/null +++ b/Documentation/translations/zh_CN/accounting/taskstats.rst @@ -0,0 +1,145 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/accounting/taskstats.rst + +:Translator: Yang Yang <yang.yang29@zte.com.cn> + +================ +每任务的统计接口 +================ + +Taskstats是一个基于netlink的接口,用于从内核向用户空间发送每任务及每进程的 +统计信息。 + +Taskstats设计目的: + +- 在任务生命周期内和退出时高效的提供统计信息 +- 统一不同计数子系统的接口 +- 支持未来计数系统的扩展 + +术语 +---- + +“pid”、“tid”、“任务”互换使用,用于描述由struct task_struct定义的标准 +Linux任务。“每pid的统计数据”等价于“每任务的统计数据”。 + +“tgid”、“进程”、“线程组”互换使用,用于描述共享mm_struct的任务集, +也就是传统的Unix进程。尽管使用了tgid这个词,即使一个任务是线程组组长, +对它的处理也没有什么不同。只要一个进程还有任何归属它的任务,它就被认为 +活着。 + +用法 +---- + +为了在任务生命周期内获得统计信息,用户空间需打开一个单播的netlink套接字 +(NETLINK_GENERIC族)然后发送指定pid或tgid的命令。响应消息中包含单个 +任务的统计信息(若指定了pid)或进程所有任务汇总的统计信息(若指定了tgid)。 + +为了在任务退出时获取统计信息,用户空间的监听者发送一个指定cpu掩码的注册命令。 +cpu掩码内的cpu上有任务退出时,每pid的统计信息将发送给注册成功的监听者。使用 +cpu掩码可以限制一个监听者收到的数据,并有助于对netlink接口进行流量控制,后文 +将进行更详细的解释。 + +如果正在退出的任务是线程组中最后一个退出的线程,额外一条包含每tgid统计信息的 +记录也将发送给用户空间。后者包含线程组中所有线程(包括过去和现在)的每pid统计 +信息总和。 + +getdelays.c是一个简单的示例,用以演示如何使用taskstats接口获取延迟统计信息。 +用户可注册cpu掩码、发送命令和处理响应、监听每tid/tgid退出数据、将收到的数据 +写入文件、通过增大接收缓冲区进行基本的流量控制。 + +接口 +---- + +内核用户接口封装在include/linux/taskstats.h。 + +为避免本文档随着接口的演进而过期,本文仅给出当前版本的概要。当本文与taskstats.h +不一致时,以taskstats.h为准。 + +struct taskstats是每pid和每tgid数据共用的计数结构体。它是版本化的,可在内核新增 +计数子系统时进行扩展。taskstats.h中定义了各字段及语义。 + +用户、内核空间的数据交换是属于NETLINK_GENERIC族的netlink消息,使用netlink属性 +接口。消息格式如下:: + + +----------+- - -+-------------+-------------------+ + | nlmsghdr | Pad | genlmsghdr | taskstats payload | + +----------+- - -+-------------+-------------------+ + +Taskstats载荷有三种类型: + +1. 命令:由用户发送给内核。获取指定pid/tgid数据的命令包含一个类型为 +TASKSTATS_CMD_ATTR_PID/TGID的属性,该属性包含u32的pid或tgid载荷。 +pid/tgid指示用户空间要统计的任务/进程。 + +注册/注销获取指定cpu集上退出数据的命令包含一个类型为 +TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK的属性,该属性包含cpu掩码载荷。 +cpu掩码是以ascii码表示,用逗号分隔的cpu范围。例如若需监听1,2,3,5,7,8号cpu的 +退出数据,cpu掩码表示为"1-3,5,7-8"。若用户空间在关闭监听套接字前忘了注销监听 +的cpu集,随着时间的推移,内核会清理此监听集。但是,出于提效的目的,建议明确 +执行注销。 + +2. 命令的应答:内核发出应答用户空间的命令。载荷有三类属性: + +a) TASKSTATS_TYPE_AGGR_PID/TGID: 本属性不包含载荷,用以指示其后为被统计对象 +的pig/tgid。 + +b) TASKSTATS_TYPE_PID/TGID:本属性的载荷为pig/tgid,其统计信息将被返回。 + +c) TASKSTATS_TYPE_STATS:本属性的载荷为一个struct taskstats实例。每pid和 +每tgid统计信息共用该结构体。 + +3. 内核会在任务退出时发送新消息。其载荷包含一系列以下类型的属性: + +a) TASKSTATS_TYPE_AGGR_PID:指示其后两个属性为pid+stats。 +b) TASKSTATS_TYPE_PID:包含退出任务的pid。 +c) TASKSTATS_TYPE_STATS:包含退出任务的每pid统计信息 +d) TASKSTATS_TYPE_AGGR_TGID:指示其后两个属性为tgid+stats。 +e) TASKSTATS_TYPE_TGID:包含任务所属进程的tgid +f) TASKSTATS_TYPE_STATS:包含退出任务所属进程的每tgid统计信息 + +每tgid的统计 +------------ + +除了每任务的统计信息,taskstats还提供每进程的统计信息,因为资源管理通常以进程 +粒度完成,并且仅在用户空间聚合任务统计信息效率低下且可能不准确(缺乏原子性)。 + +然而,除了每任务统计信息,在内核中维护每进程统计信息存在额外的时间和空间开销。 +为解决此问题,taskstats代码将退出任务的统计信息累积到进程范围的数据结构中。 +当进程最后一个任务退出时,累积的进程级数据也会发送到用户空间(与每任务数据一起)。 + +当用户查询每tgid数据时,内核将指定线程组中所有活动线程的统计信息相加,并添加到 +该线程组的累积总数(含之前退出的线程)。 + +扩展taskstats +------------- + +有两种方法可在未来修改内核扩展taskstats接口,以导出更多的每任务/进程统计信息: + +1. 在现有struct taskstats末尾增加字段。该结构体中的版本号确保了向后兼容性。 +用户空间将仅使用与其版本对应的结构体字段。 + +2. 定义单独的统计结构体并使用netlink属性接口返回对应的数据。由于用户空间独立 +处理每个netlink属性,所以总是可以忽略其不理解类型的属性(因为使用了旧版本接口)。 + +在1.和2.之间进行选择,属于权衡灵活性和开销的问题。若仅需增加少数字段,那么1.是 +首选方法,因为内核和用户空间无需承担处理新netlink属性的开销。但若新字段过多的 +扩展现有结构体,导致不同的用户空间计数程序不必要的接收大型结构体,而对结构体 +字段并不感兴趣,那么2.是值得的。 + +Taskstats的流量控制 +------------------- + +当退出任务数速率变大,监听者可能跟不上内核发送每tid/tgid退出数据的速率,而导致 +数据丢失。taskstats结构体变大、cpu数量上升,都会导致这种可能性增加。 + +为避免统计信息丢失,用户空间应执行以下操作中至少一项: + +- 增大监听者用于接收退出数据的netlink套接字接收缓存区。 + +- 创建更多的监听者,减少每个监听者监听的cpu数量。极端情况下可为每个cpu创建 + 一个监听者。用户还可考虑将监听者的cpu亲和性设置为监听cpu的子集,特别是当他们 + 仅监听一个cpu。 + +尽管采取了这些措施,若用户空间仍收到指示接收缓存区溢出的ENOBUFS错误消息, +则应采取其他措施处理数据丢失。 diff --git a/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst index 0fc5d1495789..87a36044f828 100644 --- a/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst +++ b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst @@ -8,7 +8,9 @@ 司延腾 Yanteng Si <siyanteng@loongson.cn> -.. _cn_cpu-drivers.rst: +:校译: + + 唐艺舟 Tang Yizhou <tangyeechou@gmail.com> ======================================= 如何实现一个新的CPUFreq处理器驱动程序? @@ -38,14 +40,14 @@ 1. 怎么做? =========== -如此,你刚刚得到了一个全新的CPU/芯片组及其数据手册,并希望为这个CPU/芯片组添加cpufreq +如果,你刚刚得到了一个全新的CPU/芯片组及其数据手册,并希望为这个CPU/芯片组添加cpufreq 支持?很好,这里有一些至关重要的提示: 1.1 初始化 ---------- -首先,在__initcall_level_7 (module_init())或更靠后的函数中检查这个内核是否 +首先,在 __initcall level 7 (module_init())或更靠后的函数中检查这个内核是否 运行在正确的CPU和正确的芯片组上。如果是,则使用cpufreq_register_driver()向 CPUfreq核心层注册一个cpufreq_driver结构体。 @@ -60,11 +62,11 @@ CPUfreq核心层注册一个cpufreq_driver结构体。 .setpolicy 或 .fast_switch 或 .target 或 .target_index - 差异见 下文。 -并且可选择 +其它可选成员 - .flags - cpufreq核的提示。 + .flags - 给cpufreq核心的提示。 - .driver_data - cpufreq驱动程序的特定数据。 + .driver_data - cpufreq驱动程序的特有数据。 .get_intermediate 和 target_intermediate - 用于在改变CPU频率时切换到稳定 的频率。 @@ -73,16 +75,16 @@ CPUfreq核心层注册一个cpufreq_driver结构体。 .bios_limit - 返回HW/BIOS对CPU的最大频率限制值。 - .exit - 一个指向per-policy清理函数的指针,该函数在cpu热插拔过程的CPU_POST_DEAD + .exit - 一个指向per-policy清理函数的指针,该函数在CPU热插拔过程的CPU_POST_DEAD 阶段被调用。 .suspend - 一个指向per-policy暂停函数的指针,该函数在关中断且在该策略的调节器停止 后被调用。 - .resume - 一个指向per-policy恢复函数的指针,该函数在关中断且在调节器再一次开始前被 + .resume - 一个指向per-policy恢复函数的指针,该函数在关中断且在调节器再一次启动前被 调用。 - .attr - 一个指向NULL结尾的"struct freq_attr"列表的指针,该函数允许导出值到 + .attr - 一个指向NULL结尾的"struct freq_attr"列表的指针,该列表允许导出值到 sysfs。 .boost_enabled - 如果设置,则启用提升(boost)频率。 @@ -93,95 +95,93 @@ CPUfreq核心层注册一个cpufreq_driver结构体。 1.2 Per-CPU 初始化 ------------------ -每当一个新的CPU被注册到设备模型中,或者在cpufreq驱动注册自己之后,如果此CPU的cpufreq策 -略不存在,则会调用per-policy的初始化函数cpufreq_driver.init。请注意,.init()和.exit()程序 -只对策略调用一次,而不是对策略管理的每个CPU调用一次。它需要一个 ``struct cpufreq_policy +每当一个新的CPU被注册到设备模型中,或者当cpufreq驱动注册自身之后,如果此CPU的cpufreq策 +略不存在,则会调用per-policy的初始化函数cpufreq_driver.init。请注意,.init()和.exit()例程 +只为某个策略调用一次,而不是对该策略管理的每个CPU调用一次。它需要一个 ``struct cpufreq_policy *policy`` 作为参数。现在该怎么做呢? 如果有必要,请在你的CPU上激活CPUfreq功能支持。 -然后,驱动程序必须填写以下数值: +然后,驱动程序必须填写以下值: +-----------------------------------+--------------------------------------+ -|policy->cpuinfo.min_freq 和 | | -|policy->cpuinfo.max_freq | 该CPU支持的最低和最高频率(kHz) | -| | | -| | | +|policy->cpuinfo.min_freq和 | 该CPU支持的最低和最高频率(kHz) | +|policy->cpuinfo.max_freq | | +| | | +-----------------------------------+--------------------------------------+ -|policy->cpuinfo.transition_latency | | -| | CPU在两个频率之间切换所需的时间,以 | -| | 纳秒为单位(如适用,否则指定 | -| | CPUFREQ_ETERNAL) | +|policy->cpuinfo.transition_latency | CPU在两个频率之间切换所需的时间,以 | +| | 纳秒为单位(如不适用,设定为 | +| | CPUFREQ_ETERNAL) | +| | | +-----------------------------------+--------------------------------------+ -|policy->cur | 该CPU当前的工作频率(如适用) | -| | | +|policy->cur | 该CPU当前的工作频率(如适用) | +| | | +-----------------------------------+--------------------------------------+ -|policy->min, | | -|policy->max, | | -|policy->policy and, if necessary, | | -|policy->governor | 必须包含该cpu的 “默认策略”。稍后 | -| | 会用这些值调用 | -| | cpufreq_driver.verify and either | -| | cpufreq_driver.setpolicy or | -| | cpufreq_driver.target/target_index | -| | | +|policy->min, | 必须包含该CPU的"默认策略"。稍后 | +|policy->max, | 会用这些值调用 | +|policy->policy and, if necessary, | cpufreq_driver.verify和下面函数 | +|policy->governor | 之一:cpufreq_driver.setpolicy或 | +| | cpufreq_driver.target/target_index | +| | | +-----------------------------------+--------------------------------------+ -|policy->cpus | 用与这个CPU一起做DVFS的(在线+离线) | -| | CPU(即与它共享时钟/电压轨)的掩码更新 | -| | 这个 | -| | | +|policy->cpus | 该policy通过DVFS框架影响的全部CPU | +| | (即与本CPU共享"时钟/电压"对)构成 | +| | 掩码(同时包含在线和离线CPU),用掩码 | +| | 更新本字段 | +| | | +-----------------------------------+--------------------------------------+ -对于设置其中的一些值(cpuinfo.min[max]_freq, policy->min[max]),频率表助手可能会有帮 +对于设置其中的一些值(cpuinfo.min[max]_freq, policy->min[max]),频率表辅助函数可能会有帮 助。关于它们的更多信息,请参见第2节。 1.3 验证 -------- -当用户决定设置一个新的策略(由 “policy,governor,min,max组成”)时,必须对这个策略进行验证, +当用户决定设置一个新的策略(由"policy,governor,min,max组成")时,必须对这个策略进行验证, 以便纠正不兼容的值。为了验证这些值,cpufreq_verify_within_limits(``struct cpufreq_policy *policy``, ``unsigned int min_freq``, ``unsigned int max_freq``)函数可能会有帮助。 -关于频率表助手的详细内容请参见第2节。 +关于频率表辅助函数的详细内容请参见第2节。 您需要确保至少有一个有效频率(或工作范围)在 policy->min 和 policy->max 范围内。如果有必 -要,先增加policy->max,只有在没有办法的情况下,才减少policy->min。 +要,先增大policy->max,只有在没有解决方案的情况下,才减小policy->min。 1.4 target 或 target_index 或 setpolicy 或 fast_switch? ------------------------------------------------------- -大多数cpufreq驱动甚至大多数cpu频率升降算法只允许将CPU频率设置为预定义的固定值。对于这些,你 +大多数cpufreq驱动甚至大多数CPU频率升降算法只允许将CPU频率设置为预定义的固定值。对于这些,你 可以使用->target(),->target_index()或->fast_switch()回调。 -有些cpufreq功能的处理器可以自己在某些限制之间切换频率。这些应使用->setpolicy()回调。 +有些具有硬件调频能力的处理器可以自行依据某些限制来切换CPU频率。它们应使用->setpolicy()回调。 1.5. target/target_index ------------------------ -target_index调用有两个参数:``struct cpufreq_policy * policy``和``unsigned int`` -索引(于列出的频率表)。 +target_index调用有两个参数: ``struct cpufreq_policy * policy`` 和 ``unsigned int`` +索引(用于索引频率表项)。 当调用这里时,CPUfreq驱动必须设置新的频率。实际频率必须由freq_table[index].frequency决定。 -它应该总是在错误的情况下恢复到之前的频率(即policy->restore_freq),即使我们之前切换到中间频率。 +在发生错误的情况下总是应该恢复到之前的频率(即policy->restore_freq),即使我们已经切换到了 +中间频率。 已弃用 ---------- -目标调用有三个参数。``struct cpufreq_policy * policy``, unsigned int target_frequency, +target调用有三个参数。``struct cpufreq_policy * policy``, unsigned int target_frequency, unsigned int relation. CPUfreq驱动在调用这里时必须设置新的频率。实际的频率必须使用以下规则来确定。 -- 紧跟 "目标频率"。 +- 尽量贴近"目标频率"。 - policy->min <= new_freq <= policy->max (这必须是有效的!!!) - 如果 relation==CPUFREQ_REL_L,尝试选择一个高于或等于 target_freq 的 new_freq。("L代表 最低,但不能低于") - 如果 relation==CPUFREQ_REL_H,尝试选择一个低于或等于 target_freq 的 new_freq。("H代表 最高,但不能高于") -这里,频率表助手可能会帮助你--详见第2节。 +这里,频率表辅助函数可能会帮助你 -- 详见第2节。 1.6. fast_switch ---------------- @@ -195,42 +195,43 @@ CPUfreq驱动在调用这里时必须设置新的频率。实际的频率必须 1.7 setpolicy ------------- -setpolicy调用只需要一个``struct cpufreq_policy * policy``作为参数。需要将处理器内或芯片组内动态频 +setpolicy调用只需要一个 ``struct cpufreq_policy * policy`` 作为参数。需要将处理器内或芯片组内动态频 率切换的下限设置为policy->min,上限设置为policy->max,如果支持的话,当policy->policy为 -CPUFREQ_POLICY_PERFORMANCE时选择面向性能的设置,当CPUFREQ_POLICY_POWERSAVE时选择面向省电的设置。 +CPUFREQ_POLICY_PERFORMANCE时选择面向性能的设置,为CPUFREQ_POLICY_POWERSAVE时选择面向省电的设置。 也可以查看drivers/cpufreq/longrun.c中的参考实现。 1.8 get_intermediate 和 target_intermediate -------------------------------------------- -仅适用于 target_index() 和 CPUFREQ_ASYNC_NOTIFICATION 未设置的驱动。 +仅适用于未设置 target_index() 和 CPUFREQ_ASYNC_NOTIFICATION 的驱动。 get_intermediate应该返回一个平台想要切换到的稳定的中间频率,target_intermediate()应该将CPU设置为 -该频率,然后再跳转到'index'对应的频率。核心会负责发送通知,驱动不必在target_intermediate()或 -target_index()中处理。 +该频率,然后再跳转到'index'对应的频率。cpufreq核心会负责发送通知,驱动不必在 +target_intermediate()或target_index()中处理它们。 -在驱动程序不想因为某个目标频率切换到中间频率的情况下,它们可以从get_intermediate()中返回'0'。在这种情况 -下,核心将直接调用->target_index()。 +在驱动程序不想为某个目标频率切换到中间频率的情况下,它们可以让get_intermediate()返回'0'。 +在这种情况下,cpufreq核心将直接调用->target_index()。 -注意:->target_index()应该在失败的情况下恢复到policy->restore_freq,因为core会为此发送通知。 +注意:->target_index()应该在发生失败的情况下将频率恢复到policy->restore_freq, +因为cpufreq核心会为此发送通知。 -2. 频率表助手 -============= +2. 频率表辅助函数 +================= -由于大多数cpufreq处理器只允许被设置为几个特定的频率,因此,一个带有一些函数的 “频率表”可能会辅助处理器驱动 -程序的一些工作。这样的 "频率表" 由一个cpufreq_frequency_table条目构成的数组组成,"driver_data" 中包 -含了驱动程序的具体数值,"frequency" 中包含了相应的频率,并设置了标志。在表的最后,需要添加一个 -cpufreq_frequency_table条目,频率设置为CPUFREQ_TABLE_END。而如果想跳过表中的一个条目,则将频率设置为 -CPUFREQ_ENTRY_INVALID。这些条目不需要按照任何特定的顺序排序,但如果它们是cpufreq 核心会对它们进行快速的DVFS, +由于大多数支持cpufreq的处理器只允许被设置为几个特定的频率,因此,"频率表"和一些相关函数可能会辅助处理器驱动 +程序的一些工作。这样的"频率表"是一个由struct cpufreq_frequency_table的条目构成的数组,"driver_data"成员包 +含驱动程序的专用值,"frequency"成员包含了相应的频率,此外还有标志成员。在表的最后,需要添加一个 +cpufreq_frequency_table条目,频率设置为CPUFREQ_TABLE_END。如果想跳过表中的一个条目,则将频率设置为 +CPUFREQ_ENTRY_INVALID。这些条目不需要按照任何特定的顺序排序,如果排序了,cpufreq核心执行DVFS会更快一点, 因为搜索最佳匹配会更快。 -如果策略在其policy->freq_table字段中包含一个有效的指针,cpufreq表就会被核心自动验证。 +如果在policy->freq_table字段中包含一个有效的频率表指针,频率表就会被cpufreq核心自动验证。 cpufreq_frequency_table_verify()保证至少有一个有效的频率在policy->min和policy->max范围内,并且所有其他 -标准都被满足。这对->verify调用很有帮助。 +准则都被满足。这对->verify调用很有帮助。 -cpufreq_frequency_table_target()是对应于->target阶段的频率表助手。只要把数值传递给这个函数,这个函数就会返 +cpufreq_frequency_table_target()是对应于->target阶段的频率表辅助函数。只要把值传递给这个函数,这个函数就会返 回包含CPU要设置的频率的频率表条目。 以下宏可以作为cpufreq_frequency_table的迭代器。 @@ -238,8 +239,8 @@ cpufreq_frequency_table_target()是对应于->target阶段的频率表助手。 cpufreq_for_each_entry(pos, table) - 遍历频率表的所有条目。 cpufreq_for_each_valid_entry(pos, table) - 该函数遍历所有条目,不包括CPUFREQ_ENTRY_INVALID频率。 -使用参数 "pos"-一个``cpufreq_frequency_table * `` 作为循环变量,使用参数 "table"-作为你想迭代 -的``cpufreq_frequency_table * `` 。 +使用参数"pos" -- 一个 ``cpufreq_frequency_table *`` 作为循环指针,使用参数"table" -- 作为你想迭代 +的 ``cpufreq_frequency_table *`` 。 例如:: @@ -250,5 +251,5 @@ cpufreq_for_each_valid_entry(pos, table) - 该函数遍历所有条目,不包 pos->frequency = ... } -如果你需要在driver_freq_table中处理pos的位置,不要减去指针,因为它的代价相当高。相反,使用宏 +如果你需要在driver_freq_table中处理pos的位置,不要做指针减法,因为它的代价相当高。作为替代,使用宏 cpufreq_for_each_entry_idx() 和 cpufreq_for_each_valid_entry_idx() 。 diff --git a/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst index f14423099d4b..e8fdba923cd5 100644 --- a/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst +++ b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst @@ -8,13 +8,15 @@ 司延腾 Yanteng Si <siyanteng@loongson.cn> -.. _cn_cpufreq-stats.rst: +:校译: + + 唐艺舟 Tang Yizhou <tangyeechou@gmail.com> ========================================== sysfs CPUFreq Stats的一般说明 ========================================== -用户信息 +为使用者准备的信息 作者: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> @@ -29,17 +31,16 @@ sysfs CPUFreq Stats的一般说明 1. 简介 =============== -cpufreq-stats是一个为每个CPU提供CPU频率统计的驱动。 -这些统计数据在/sysfs中以一堆只读接口的形式提供。这个接口(在配置好后)将出现在 -/sysfs(<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq下的一个单 -独的目录中,提供给每个CPU。 -各种统计数据将在此目录下形成只读文件。 +cpufreq-stats是一种为每个CPU提供CPU频率统计的驱动。 +这些统计数据以/sysfs中一系列只读接口的形式呈现。cpufreq-stats接口(若已配置)将为每个CPU生成 +/sysfs(<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq目录下的stats目录。 +各项统计数据将在stats目录下形成对应的只读文件。 -此驱动是独立于任何可能运行在你所用CPU上的特定cpufreq_driver而设计的。因此,它将与所有 -cpufreq_driver一起工作。 +此驱动是以独立于任何可能运行在你所用CPU上的特定cpufreq_driver的方式设计的。因此,它将能和任何 +cpufreq_driver协同工作。 -2. 提供的统计数据(举例说明) +2. 已提供的统计数据(有例子) ===================================== cpufreq stats提供了以下统计数据(在下面详细解释)。 @@ -48,8 +49,8 @@ cpufreq stats提供了以下统计数据(在下面详细解释)。 - total_trans - trans_table -所有的统计数据将从统计驱动被载入的时间(或统计被重置的时间)开始,到某一统计数据被读取的时间为止。 -显然,统计驱动不会有任何关于统计驱动载入之前的频率转换信息。 +所有统计数据来自以下时间范围:从统计驱动被加载的时间(或统计数据被重置的时间)开始,到某一统计数据被读取的时间为止。 +显然,统计驱动不会保存它被加载之前的任何频率转换信息。 :: @@ -64,14 +65,14 @@ cpufreq stats提供了以下统计数据(在下面详细解释)。 - **reset** -只写属性,可用于重置统计计数器。这对于评估不同调节器下的系统行为非常有用,且无需重启。 +只写属性,可用于重置统计计数器。这对于评估不同调节器的系统行为非常有用,且无需重启。 - **time_in_state** -此项给出了这个CPU所支持的每个频率所花费的时间。cat输出的每一行都会有"<frequency> -<time>"对,表示这个CPU在<frequency>上花费了<time>个usertime单位的时间。这里的 -usertime单位是10mS(类似于/proc中输出的其他时间)。 +此文件给出了在本CPU支持的每个频率上分别花费的时间。cat输出的每一行都是一个"<frequency> +<time>"对,表示这个CPU在<frequency>上花费了<time>个usertime单位的时间。输出的每一行对应 +一个CPU支持的频率。这里usertime单位是10mS(类似于/proc导出的其它时间)。 :: @@ -85,7 +86,7 @@ usertime单位是10mS(类似于/proc中输出的其他时间)。 - **total_trans** -给出了这个CPU上频率转换的总次数。cat的输出将有一个单一的计数,这就是频率转换的总数。 +此文件给出了这个CPU频率转换的总次数。cat的输出是一个计数值,它就是频率转换的总次数。 :: @@ -94,10 +95,10 @@ usertime单位是10mS(类似于/proc中输出的其他时间)。 - **trans_table** -这将提供所有CPU频率转换的细粒度信息。这里的cat输出是一个二维矩阵,其中一个条目<i, j>(第 +本文件提供所有CPU频率转换的细粒度信息。这里的cat输出是一个二维矩阵,其中一个条目<i, j>(第 i行,第j列)代表从Freq_i到Freq_j的转换次数。Freq_i行和Freq_j列遵循驱动最初提供给cpufreq -核的频率表的排序顺序,因此可以排序(升序或降序)或不排序。 这里的输出也包含了每行每列的实际 -频率值,以便更好地阅读。 +核心的频率表的排列顺序,因此可以已排序(升序或降序)或未排序。这里的输出也包含了实际 +频率值,分别按行和按列显示,以便更好地阅读。 如果转换表大于PAGE_SIZE,读取时将返回一个-EFBIG错误。 @@ -115,7 +116,7 @@ i行,第j列)代表从Freq_i到Freq_j的转换次数。Freq_i行和Freq_j列 3. 配置cpufreq-stats ============================ -要在你的内核中配置cpufreq-stats:: +按以下方式在你的内核中配置cpufreq-stats:: Config Main Menu Power management options (ACPI, APM) ---> @@ -124,7 +125,7 @@ i行,第j列)代表从Freq_i到Freq_j的转换次数。Freq_i行和Freq_j列 [*] CPU frequency translation statistics -"CPU Frequency scaling" (CONFIG_CPU_FREQ) 应该被启用以配置cpufreq-stats。 +"CPU Frequency scaling" (CONFIG_CPU_FREQ) 应该被启用,以支持配置cpufreq-stats。 "CPU frequency translation statistics" (CONFIG_CPU_FREQ_STAT)提供了包括 time_in_state、total_trans和trans_table的统计数据。 diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst index 0f770b8664e9..77a8c44cdf49 100644 --- a/Documentation/translations/zh_CN/dev-tools/index.rst +++ b/Documentation/translations/zh_CN/dev-tools/index.rst @@ -22,13 +22,13 @@ Documentation/translations/zh_CN/dev-tools/testing-overview.rst :maxdepth: 2 testing-overview + sparse gcov kasan Todolist: - coccinelle - - sparse - kcov - ubsan - kmemleak diff --git a/Documentation/translations/zh_CN/sparse.txt b/Documentation/translations/zh_CN/dev-tools/sparse.rst index 0f444b83d639..556282437aad 100644 --- a/Documentation/translations/zh_CN/sparse.txt +++ b/Documentation/translations/zh_CN/dev-tools/sparse.rst @@ -1,34 +1,34 @@ -Chinese translated version of Documentation/dev-tools/sparse.rst +Copyright 2004 Linus Torvalds +Copyright 2004 Pavel Machek <pavel@ucw.cz> +Copyright 2006 Bob Copeland <me@bobcopeland.com> -If you have any comment or update to the content, please contact the -original document maintainer directly. However, if you have a problem -communicating in English you can also ask the Chinese maintainer for -help. Contact the Chinese maintainer if this translation is outdated -or if there is a problem with the translation. +.. include:: ../disclaimer-zh_CN.rst -Chinese maintainer: Li Yang <leoyang.li@nxp.com> ---------------------------------------------------------------------- -Documentation/dev-tools/sparse.rst 的中文翻译 +:Original: Documentation/dev-tools/sparse.rst -如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 -交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 -译存在问题,请联系中文版维护者。 +:翻译: -中文版维护者: 李阳 Li Yang <leoyang.li@nxp.com> -中文版翻译者: 李阳 Li Yang <leoyang.li@nxp.com> + Li Yang <leoyang.li@nxp.com> +:校译: -以下为正文 ---------------------------------------------------------------------- + 司延腾 Yanteng Si <siyanteng@loongson.cn> -Copyright 2004 Linus Torvalds -Copyright 2004 Pavel Machek <pavel@ucw.cz> -Copyright 2006 Bob Copeland <me@bobcopeland.com> +.. _cn_sparse: + +Sparse +====== + +Sparse是一个C程序的语义检查器;它可以用来发现内核代码的一些潜在问题。 关 +于sparse的概述,请参见https://lwn.net/Articles/689907/;本文档包含 +一些针对内核的sparse信息。 +关于sparse的更多信息,主要是关于它的内部结构,可以在它的官方网页上找到: +https://sparse.docs.kernel.org。 使用 sparse 工具做类型检查 ~~~~~~~~~~~~~~~~~~~~~~~~~~ -"__bitwise" 是一种类型属性,所以你应该这样使用它: +"__bitwise" 是一种类型属性,所以你应该这样使用它:: typedef int __bitwise pm_request_t; @@ -48,7 +48,7 @@ Copyright 2006 Bob Copeland <me@bobcopeland.com> 坦白来说,你并不需要使用枚举类型。上面那些实际都可以浓缩成一个特殊的"int __bitwise"类型。 -所以更简单的办法只要这样做: +所以更简单的办法只要这样做:: typedef int __bitwise pm_request_t; @@ -60,25 +60,42 @@ __bitwise"类型。 一个小提醒:常数整数"0"是特殊的。你可以直接把常数零当作位方式整数使用而 不用担心 sparse 会抱怨。这是因为"bitwise"(恰如其名)是用来确保不同位方 式类型不会被弄混(小尾模式,大尾模式,cpu尾模式,或者其他),对他们来说 -常数"0"确实是特殊的。 +常数"0"确实 **是** 特殊的。 + +使用sparse进行锁检查 +-------------------- + +下面的宏对于 gcc 来说是未定义的,在 sparse 运行时定义,以使用sparse的“上下文” +跟踪功能,应用于锁定。 这些注释告诉 sparse 什么时候有锁,以及注释的函数的进入和 +退出。 + +__must_hold - 指定的锁在函数进入和退出时被持有。 + +__acquires - 指定的锁在函数退出时被持有,但在进入时不被持有。 + +__releases - 指定的锁在函数进入时被持有,但在退出时不被持有。 + +如果函数在不持有锁的情况下进入和退出,在函数内部以平衡的方式获取和释放锁,则不 +需要注释。 +上面的三个注释是针对sparse否则会报告上下文不平衡的情况。 获取 sparse 工具 ~~~~~~~~~~~~~~~~ 你可以从 Sparse 的主页获取最新的发布版本: - http://www.kernel.org/pub/linux/kernel/people/josh/sparse/ + https://www.kernel.org/pub/software/devel/sparse/dist/ 或者,你也可以使用 git 克隆最新的 sparse 开发版本: - git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git + git://git.kernel.org/pub/scm/devel/sparse/sparse.git 一旦你下载了源码,只要以普通用户身份运行: make make install -它将会被自动安装到你的 ~/bin 目录下。 +如果是标准的用户,它将会被自动安装到你的~/bin目录下。 使用 sparse 工具 ~~~~~~~~~~~~~~~~ diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst index a34e58733ac8..aebe336ab538 100644 --- a/Documentation/translations/zh_CN/index.rst +++ b/Documentation/translations/zh_CN/index.rst @@ -106,6 +106,7 @@ TODOList: virt/index infiniband/index accounting/index + scheduler/index TODOList: @@ -140,7 +141,6 @@ TODOList: * PCI/index * scsi/index * misc-devices/index -* scheduler/index * mhi/index 体系结构无关文档 diff --git a/Documentation/translations/zh_CN/scheduler/completion.rst b/Documentation/translations/zh_CN/scheduler/completion.rst new file mode 100644 index 000000000000..bc8218514e0a --- /dev/null +++ b/Documentation/translations/zh_CN/scheduler/completion.rst @@ -0,0 +1,256 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/scheduler/completion.rst + +:翻译: + + 司延腾 Yanteng Si <siyanteng@loongson.cn> + +:校译: + + 唐艺舟 Tang Yizhou <tangyeechou@gmail.com> + +======================================= +完成 - "等待完成" 屏障应用程序接口(API) +======================================= + +简介: +----- + +如果你有一个或多个线程必须等待某些内核活动达到某个点或某个特定的状态,完成可以为这 +个问题提供一个无竞争的解决方案。从语义上讲,它们有点像pthread_barrier(),并且使 +用的案例类似 + +完成是一种代码同步机制,它比任何滥用锁/信号量和忙等待循环的行为都要好。当你想用yield() +或一些古怪的msleep(1)循环来允许其它代码继续运行时,你可能想用wait_for_completion*() +调用和completion()来代替。 + +使用“完成”的好处是,它们有一个良好定义、聚焦的目标,这不仅使得我们很容易理解代码的意图, +而且它们也会生成更高效的代码,因为所有线程都可以继续执行,直到真正需要结果的时刻。而且等 +待和信号都高效的使用了低层调度器的睡眠/唤醒设施。 + +完成是建立在Linux调度器的等待队列和唤醒基础设施之上的。等待队列中的线程所等待的 +事件被简化为 ``struct completion`` 中的一个简单标志,被恰如其名地称为‘done’。 + +由于完成与调度有关,代码可以在kernel/sched/completion.c中找到。 + + +用法: +----- + +使用完成需要三个主要部分: + + - 'struct completion' 同步对象的初始化 + - 通过调用wait_for_completion()的一个变体来实现等待部分。 + - 通过调用complete()或complete_all()实现发信端。 + +也有一些辅助函数用于检查完成的状态。请注意,虽然必须先做初始化,但等待和信号部分可以 +按任何时间顺序出现。也就是说,一个线程在另一个线程检查是否需要等待它之前,已经将一个 +完成标记为 "done",这是完全正常的。 + +要使用完成API,你需要#include <linux/completion.h>并创建一个静态或动态的 +``struct completion`` 类型的变量,它只有两个字段:: + + struct completion { + unsigned int done; + wait_queue_head_t wait; + }; + +结构体提供了->wait等待队列来放置任务进行等待(如果有的话),以及->done完成标志来表明它 +是否完成。 + +完成的命名应当与正在被同步的事件名一致。一个好的例子是:: + + wait_for_completion(&early_console_added); + + complete(&early_console_added); + +好的、直观的命名(一如既往地)有助于代码的可读性。将一个完成命名为 ``complete`` +是没有帮助的,除非其目的是超级明显的... + + +初始化完成: +----------- + +动态分配的完成对象最好被嵌入到数据结构中,以确保在函数/驱动的生命周期内存活,以防 +止与异步complete()调用发生竞争。 + +在使用wait_for_completion()的_timeout()或_killable()/_interruptible()变体 +时应特别小心,因为必须保证在所有相关活动(complete()或reinit_completion())发生 +之前不会发生内存解除分配,即使这些等待函数由于超时或信号触发而过早返回。 + +动态分配的完成对象的初始化是通过调用init_completion()来完成的:: + + init_completion(&dynamic_object->done); + +在这个调用中,我们初始化 waitqueue 并将 ->done 设置为 0,即“not completed”或 +“not done”。 + +重新初始化函数reinit_completion(),只是将->done字段重置为0(“not done”),而 +不触及等待队列。这个函数的调用者必须确保没有任何令人讨厌的wait_for_completion() +调用在并行进行。 + +在同一个完成对象上调用init_completion()两次很可能是一个bug,因为它将队列重新初始 +化为一个空队列,已排队的任务可能会“丢失”--在这种情况下使用reinit_completion(),但 +要注意其他竞争。 + +对于静态声明和初始化,可以使用宏。 + +对于文件范围内的静态(或全局)声明,你可以使用 DECLARE_COMPLETION():: + + static DECLARE_COMPLETION(setup_done); + DECLARE_COMPLETION(setup_done); + +注意,在这种情况下,完成在启动时(或模块加载时)被初始化为“not done”,不需要调用 +init_completion()。 + +当完成被声明为一个函数中的局部变量时,那么应该总是明确地使用 +DECLARE_COMPLETION_ONSTACK()来初始化,这不仅仅是为了让lockdep正确运行,也是明确表 +名它有限的使用范围是有意为之并被仔细考虑的:: + + DECLARE_COMPLETION_ONSTACK(setup_done) + +请注意,当使用完成对象作为局部变量时,你必须敏锐地意识到函数堆栈的短暂生命期:在所有 +活动(如等待的线程)停止并且完成对象完全未被使用之前,函数不得返回到调用上下文。 + +再次强调这一点:特别是在使用一些具有更复杂结果的等待API变体时,比如超时或信号 +(_timeout(), _killable()和_interruptible())变体,等待可能会提前完成,而对象可 +能仍在被其他线程使用 - 从wait_on_completion*()调用者函数的返回会取消分配函数栈,如 +果complete()在其它某线程中完成调用,会引起微小的数据损坏。简单的测试可能不会触发这 +些类型的竞争。 + +如果不确定的话,使用动态分配的完成对象, 最好是嵌入到其它一些生命周期长的对象中,长到 +超过使用完成对象的任何辅助线程的生命周期,或者有一个锁或其他同步机制来确保complete() +不会在一个被释放的对象中调用。 + +在堆栈上单纯地调用DECLARE_COMPLETION()会触发一个lockdep警告。 + +等待完成: +--------- + +对于一个线程来说,要等待一些并发活动的完成,它要在初始化的完成结构体上调用 +wait_for_completion():: + + void wait_for_completion(struct completion *done) + +一个典型的使用场景是:: + + CPU#1 CPU#2 + + struct completion setup_done; + + init_completion(&setup_done); + initialize_work(...,&setup_done,...); + + /* run non-dependent code */ /* do setup */ + + wait_for_completion(&setup_done); complete(setup_done); + +这并不意味着调用wait_for_completion()和complete()有任何特定的时间顺序--如果调 +用complete()发生在调用wait_for_completion()之前,那么等待方将立即继续执行,因为 +所有的依赖都得到了满足;如果没有,它将阻塞,直到complete()发出完成的信号。 + +注意,wait_for_completion()是在调用spin_lock_irq()/spin_unlock_irq(),所以 +只有当你知道中断被启用时才能安全地调用它。从IRQs-off的原子上下文中调用它将导致难以检 +测的错误的中断启用。 + +默认行为是不带超时的等待,并将任务标记为“UNINTERRUPTIBLE”状态。wait_for_completion() +及其变体只有在进程上下文中才是安全的(因为它们可以休眠),但在原子上下文、中断上下文、IRQ +被禁用或抢占被禁用的情况下是不安全的--关于在原子/中断上下文中处理完成的问题,还请看下面的 +try_wait_for_completion()。 + +由于wait_for_completion()的所有变体都可能(很明显)阻塞很长时间,这取决于它们所等 +待的活动的性质,所以在大多数情况下,你可能不想在持有mutex锁的情况下调用它。 + + +wait_for_completion*()可用的变体: +--------------------------------- + +下面的变体都会返回状态,在大多数(/所有)情况下都应该检查这个状态--在故意不检查状态的情 +况下,你可能要做一个说明(例如,见arch/arm/kernel/smp.c:__cpu_up())。 + +一个常见的问题是不准确的返回类型赋值,所以要注意将返回值赋值给适当类型的变量。 + +检查返回值的具体含义也可能被发现是相当不准确的,例如,像这样的构造:: + + if (!wait_for_completion_interruptible_timeout(...)) + +...会在成功完成和中断的情况下执行相同的代码路径--这可能不是你想要的结果:: + + int wait_for_completion_interruptible(struct completion *done) + +这个函数在任务等待时标记为TASK_INTERRUPTIBLE。如果在等待期间收到信号,它将返回 +-ERESTARTSYS;否则为0:: + + unsigned long wait_for_completion_timeout(struct completion *done, unsigned long timeout) + +该任务被标记为TASK_UNINTERRUPTIBLE,并将最多超时等待“timeout”个jiffies。如果超时发生,则 +返回0,否则返回剩余的时间(但至少是1)。 + +超时最好用msecs_to_jiffies()或usecs_to_jiffies()计算,以使代码在很大程度上不受 +HZ的影响。 + +如果返回的超时值被故意忽略,那么注释应该解释原因 +(例如,见drivers/mfd/wm8350-core.c wm8350_read_auxadc():: + + long wait_for_completion_interruptible_timeout(struct completion *done, unsigned long timeout) + +这个函数传递一个以jiffies为单位的超时,并将任务标记为TASK_INTERRUPTIBLE。如果收到 +信号,则返回-ERESTARTSYS;否则,如果完成超时,则返回0;如果完成了,则返回剩余的时间 +(jiffies)。 + +更多的变体包括_killable,它使用TASK_KILLABLE作为指定的任务状态,如果它被中断,将返 +回-ERESTARTSYS,如果完成了,则返回0。它也有一个_timeout变体:: + + long wait_for_completion_killable(struct completion *done) + long wait_for_completion_killable_timeout(struct completion *done, unsigned long timeout) + +wait_for_completion_io()的_io变体的行为与非_io变体相同,只是将等待时间计为“IO等待”, +这对任务在调度/IO统计中的计算方式有影响:: + + void wait_for_completion_io(struct completion *done) + unsigned long wait_for_completion_io_timeout(struct completion *done, unsigned long timeout) + + +对完成发信号: +------------- + +一个线程想要发出信号通知继续的条件已经达到,就会调用complete(),向其中一个等待者发出信 +号表明它可以继续:: + + void complete(struct completion *done) + +... or calls complete_all() to signal all current and future waiters:: + + void complete_all(struct completion *done) + +即使在线程开始等待之前就发出了完成的信号,信号传递也会继续进行。这是通过等待者 +“consuming”(递减)“struct completion” 的完成字段来实现的。等待的线程唤醒的顺序 +与它们被排队的顺序相同(FIFO顺序)。 + +如果多次调用complete(),那么这将允许该数量的等待者继续进行--每次调用complete()将 +简单地增加已完成的字段。但多次调用complete_all()是一个错误。complete()和 +complete_all()都可以在IRQ/atomic上下文中安全调用。 + +在任何时候,只能有一个线程在一个特定的 “struct completion”上调用 complete() 或 +complete_all() - 通过等待队列自旋锁进行序列化。任何对 complete() 或 +complete_all() 的并发调用都可能是一个设计错误。 + +从IRQ上下文中发出完成信号 是可行的,因为它将正确地用 +spin_lock_irqsave()/spin_unlock_irqrestore()执行锁操作 + + +try_wait_for_completion()/completion_done(): +-------------------------------------------- + +try_wait_for_completion()函数不会将线程放在等待队列中,而是在需要排队(阻塞)线 +程时返回false,否则会消耗一个已发布的完成并返回true:: + + bool try_wait_for_completion(struct completion *done) + +最后,为了在不以任何方式改变完成的情况下检查完成的状态,可以调用completion_done(), +如果没有发布的完成尚未被等待者消耗,则返回false(意味着存在等待者),否则返回true:: + + bool completion_done(struct completion *done) + +try_wait_for_completion()和completion_done()都可以在IRQ或原子上下文中安全调用。 diff --git a/Documentation/translations/zh_CN/scheduler/index.rst b/Documentation/translations/zh_CN/scheduler/index.rst new file mode 100644 index 000000000000..4c4deca4302a --- /dev/null +++ b/Documentation/translations/zh_CN/scheduler/index.rst @@ -0,0 +1,44 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/scheduler/index.rst + +:翻译: + + 司延腾 Yanteng Si <siyanteng@loongson.cn> + +:校译: + + + +=============== +Linux调度器 +=============== + +.. toctree:: + :maxdepth: 1 + + completion + sched-arch + sched-bwc + + +TODOList: + + sched-bwc + sched-deadline + sched-design-CFS + sched-domains + sched-capacity + sched-energy + sched-nice-design + sched-rt-group + sched-stats + + text_files + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/translations/zh_CN/scheduler/sched-arch.rst b/Documentation/translations/zh_CN/scheduler/sched-arch.rst new file mode 100644 index 000000000000..754a15c6b60f --- /dev/null +++ b/Documentation/translations/zh_CN/scheduler/sched-arch.rst @@ -0,0 +1,76 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/scheduler/sched-arch.rst + +:翻译: + + 司延腾 Yanteng Si <siyanteng@loongson.cn> + +:校译: + + + +=============================== +架构特定代码的CPU调度器实现提示 +=============================== + + Nick Piggin, 2005 + +上下文切换 +========== +1. 运行队列锁 +默认情况下,switch_to arch函数在调用时锁定了运行队列。这通常不是一个问题,除非 +switch_to可能需要获取运行队列锁。这通常是由于上下文切换中的唤醒操作造成的。见 +arch/ia64/include/asm/switch_to.h的例子。 + +为了要求调度器在运行队列解锁的情况下调用switch_to,你必须在头文件 +中`#define __ARCH_WANT_UNLOCKED_CTXSW`(通常是定义switch_to的那个文件)。 + +在CONFIG_SMP的情况下,解锁的上下文切换对核心调度器的实现只带来了非常小的性能损 +失。 + +CPU空转 +======= +你的cpu_idle程序需要遵守以下规则: + +1. 现在抢占应该在空闲的例程上禁用。应该只在调用schedule()时启用,然后再禁用。 + +2. need_resched/TIF_NEED_RESCHED 只会被设置,并且在运行任务调用 schedule() + 之前永远不会被清除。空闲线程只需要查询need_resched,并且永远不会设置或清除它。 + +3. 当cpu_idle发现(need_resched() == 'true'),它应该调用schedule()。否则 + 它不应该调用schedule()。 + +4. 在检查need_resched时,唯一需要禁用中断的情况是,我们要让处理器休眠到下一个中 + 断(这并不对need_resched提供任何保护,它可以防止丢失一个中断): + + 4a. 这种睡眠类型的常见问题似乎是:: + + local_irq_disable(); + if (!need_resched()) { + local_irq_enable(); + *** resched interrupt arrives here *** + __asm__("sleep until next interrupt"); + } + +5. 当need_resched变为高电平时,TIF_POLLING_NRFLAG可以由不需要中断来唤醒它们 + 的空闲程序设置。换句话说,它们必须定期轮询need_resched,尽管做一些后台工作或 + 进入低CPU优先级可能是合理的。 + + - 5a. 如果TIF_POLLING_NRFLAG被设置,而我们确实决定进入一个中断睡眠,那 + 么需要清除它,然后发出一个内存屏障(接着测试need_resched,禁用中断,如3中解释)。 + +arch/x86/kernel/process.c有轮询和睡眠空闲函数的例子。 + + +可能出现的arch/问题 +=================== + +我发现的可能的arch问题(并试图解决或没有解决)。: + +ia64 - safe_halt的调用与中断相比,是否很荒谬? (它睡眠了吗) (参考 #4a) + +sh64 - 睡眠与中断相比,是否很荒谬? (参考 #4a) + +sparc - 在这一点上,IRQ是开着的(?),把local_irq_save改为_disable。 + - 待办事项: 需要第二个CPU来禁用抢占 (参考 #1) diff --git a/Documentation/translations/zh_CN/scheduler/sched-bwc.rst b/Documentation/translations/zh_CN/scheduler/sched-bwc.rst new file mode 100644 index 000000000000..90e931f4ceed --- /dev/null +++ b/Documentation/translations/zh_CN/scheduler/sched-bwc.rst @@ -0,0 +1,204 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/scheduler/sched-bwc.rst + +:翻译: + + 司延腾 Yanteng Si <siyanteng@loongson.cn> + +:校译: + + + +============ +CFS 带宽控制 +============ + +.. note:: + 本文只讨论了SCHED_NORMAL的CPU带宽控制。 + SCHED_RT的情况在Documentation/scheduler/sched-rt-group.rst中有涉及。 + +CFS带宽控制是一个CONFIG_FAIR_GROUP_SCHED扩展,它允许指定一个组或层次的最大CPU带宽。 + +一个组允许的带宽是用配额和周期指定的。在每个给定的”周期“(微秒)内,一个任务组被分配多 +达“配额”微秒的CPU时间。当cgroup中的线程可运行时,该配额以时间片段的方式被分配到每个cpu +运行队列中。一旦所有的配额被分配,任何额外的配额请求将导致这些线程被限流。被限流的线程将不 +能再次运行,直到下一个时期的配额得到补充。 + +一个组的未分配配额是全局跟踪的,在每个周期边界被刷新为cfs_quota单元。当线程消耗这个带宽时, +它以需求为基础被转移到cpu-local“筒仓”,在每次更新中转移的数量是可调整的,被描述为“片“(时 +间片)。 + +突发特性 +-------- +现在这个功能借来的时间是用于防范我们对未来的低估,代价是对其他系统用户的干扰增加。所有这些都 +有很好的限制。 + +传统的(UP-EDF)带宽控制是这样的: + + (U = \Sum u_i) <= 1 + +这既保证了每个最后期限的实现,也保证了系统的稳定。毕竟,如果U>1,那么每一秒钟的壁钟时间,我 +们就必须运行超过一秒钟的程序时间,显然会错过我们的最后期限,但下一个最后期限会更远,永远没有 +时间赶上,无边无界的失败。 + +突发特性观察到工作负载并不总是执行全部配额;这使得人们可以将u_i描述为一个统计分布。 + +例如,让u_i = {x,e}_i,其中x是p(95)和x+e p(100)(传统的WCET)。这实际上允许u更小,提 +高了效率(我们可以在系统中打包更多的任务),但代价是当所有的概率都一致时,会错过最后期限。然 +而,它确实保持了稳定性,因为只要我们的x高于平均水平,每一次超限都必须与低估相匹配。 + +也就是说,假设我们有两个任务,都指定了一个p(95)值,那么我们有一个p(95)*p(95)=90.25%的机 +会,两个任务都在他们的配额内,一切都很好。同时,我们有一个p(5)p(5)=0.25%的机会,两个任务同 +时超过他们的配额(保证最后期限失败)。在这两者之间有一个阈值,其中一个超过了,而另一个没有不足, +无法补偿;这取决于具体的CDFs。 + +同时,我们可以说,最坏的情况下的截止日期失败,将是Sum e_i;也就是说,有一个有界的迟延(在假 +设x+e确实是WCET的情况下)。 + +使用突发时的干扰是由错过最后期限的可能性和平均WCET来评价的。测试结果表明,当有许多cgroup或 +CPU未被充分利用时,干扰是有限的。更多的细节显示在: +https://lore.kernel.org/lkml/5371BD36-55AE-4F71-B9D7-B86DC32E3D2B@linux.alibaba.com/ + +管理 +---- +配额、周期和突发是在cpu子系统内通过cgroupfs管理的。 + +.. note:: + 本节描述的cgroupfs文件只适用于cgroup v1.对于cgroup v2,请参阅Control Group v2。 + :ref:`Documentation/admin-guide/cgroup-v2.rst <cgroup-v2-cpu>`. + +- cpu.cfs_quota_us:在一个时期内补充的运行时间(微秒)。 +- cpu.cfs_period_us:一个周期的长度(微秒)。 +- cpu.stat: 输出节流统计数据[下面进一步解释] +- cpu.cfs_burst_us:最大累积运行时间(微秒)。 + +默认值是:: + + cpu.cfs_period_us=100ms + cpu.cfs_quota_us=-1 + cpu.cfs_burst_us=0 + +cpu.cfs_quota_us的值为-1表示该组没有任何带宽限制,这样的组被描述为无限制的带宽组。这代表 +了CFS的传统工作保护行为。 + +写入不小于cpu.cfs_burst_us的任何(有效的)正值将配发指定的带宽限制。该配额或周期允许的最 +小配额是1ms。周期长度也有一个1s的上限。当带宽限制以分层方式使用时,存在额外的限制,这些在下 +面有更详细的解释。 + +向cpu.cfs_quota_us写入任何负值都会移除带宽限制,并使组再次回到无限制的状态。 + +cpu.cfs_burst_us的值为0表示该组不能积累任何未使用的带宽。它使得CFS的传统带宽控制行为没有 +改变。将不大于 cpu.cfs_quota_us 的任何(有效的)正值写入 cpu.cfs_burst_us 将配发未使用 +带宽累积的上限。 + +如果一个组处于受限状态,对该组带宽规格的任何更新都将导致其成为无限流状态。 + +系统范围设置 +------------ +为了提高效率,运行时间在全局池和CPU本地“筒仓”之间以批处理方式转移。这大大减少了大型系统的全 +局核算压力。每次需要进行这种更新时,传输的数量被描述为 "片"。 + +这是可以通过procfs调整的:: + + /proc/sys/kernel/sched_cfs_bandwidth_slice_us (default=5ms) + +较大的时间片段值将减少传输开销,而较小的值则允许更精细的消费。 + +统计 +---- +一个组的带宽统计数据通过cpu.stat的5个字段导出。 + +cpu.stat: + +- nr_periods:已经过去的执行间隔的数量。 +- nr_throttled: 该组已被节流/限制的次数。 +- throttled_time: 该组的实体被限流的总时间长度(纳秒)。 +- nr_bursts:突发发生的周期数。 +- burst_time: 任何CPU在各个时期使用超过配额的累计壁钟时间(纳秒)。 + +这个接口是只读的。 + +分层考虑 +-------- +该接口强制要求单个实体的带宽总是可以达到的,即:max(c_i) <= C。然而,在总体情况下,是明确 +允许过度订阅的,以便在一个层次结构中实现工作保护语义: + + 例如,Sum (c_i)可能超过C + +[ 其中C是父方的带宽,c_i是其子方的带宽。 ] + +.. note:: + 译文中的父亲/孩子指的是cgroup parent, cgroup children。 + +有两种方式可以使一个组变得限流: + + a. 它在一段时期内完全消耗自己的配额 + b. 父方的配额在其期间内全部用完 + +在上述b)情况下,即使孩子可能有剩余的运行时间,它也不会被允许,直到父亲的运行时间被刷新。 + +CFS带宽配额的注意事项 +--------------------- +一旦一个片断被分配给一个cpu,它就不会过期。然而,如果该cpu上的所有线程都无法运行,那么除了 +1ms以外的所有时间片都可以返回到全局池中。这是在编译时由min_cfs_rq_runtime变量配置的。这 +是一个性能调整,有助于防止对全局锁的额外争夺。 + +cpu-local分片不会过期的事实导致了一些有趣的罕见案例,应该被理解。 + +对于cgroup cpu限制的应用程序来说,这是一个相对有意义的问题,因为他们自然会消耗他们的全部配 +额,以及每个cpu-本地片在每个时期的全部。因此,预计nr_periods大致等于nr_throttled,并且 +cpuacct.用量的增加大致等于cfs_quota_us在每个周期的增加。 + +对于高线程、非cpu绑定的应用程序,这种非过期的细微差别允许应用程序短暂地突破他们的配额限制, +即任务组正在运行的每个cpu上未使用的片断量(通常每个cpu最多1ms或由min_cfs_rq_runtime定 +义)。这种轻微的突发只适用于配额已经分配给cpu,然后没有完全使用或在以前的时期返回。这个突发 +量不会在核心之间转移。因此,这种机制仍然严格限制任务组的配额平均使用量,尽管是在比单一时期更 +长的时间窗口。这也限制了突发能力,每个cpu不超过1ms。这为在高核数机器上有小配额限制的高线程 +应用提供了更好的更可预测的用户体验。它还消除了在使用低于配额的cpu时对这些应用进行节流的倾向。 +另一种说法是,通过允许一个片断的未使用部分在不同时期保持有效,我们减少了在不需要整个片断的cpu +时间的cpu-local 筒仓上浪费配额的可能性。 + +绑定cpu和非绑定cpu的交互式应用之间的互动也应该被考虑,特别是当单核使用率达到100%时。如果你 +给了这些应用程序一半的cpu-core,并且它们都被安排在同一个CPU上,理论上非cpu绑定的应用程序有 +可能在某些时期使用多达1ms的额外配额,从而阻止cpu绑定的应用程序完全使用其配额,这也是同样的数 +量。在这些情况下,将由CFS算法(见CFS调度器)来决定选择哪个应用程序来运行,因为它们都是可运行 +的,并且有剩余的配额。这个运行时间的差异将在接下来的交互式应用程序空闲期间得到弥补。 + +例子 +---- +1. 限制一个组的运行时间为1个CPU的价值:: + + 如果周期是250ms,配额也是250ms,那么该组将每250ms获得价值1个CPU的运行时间。 + + # echo 250000 > cpu.cfs_quota_us /* quota = 250ms */ + # echo 250000 > cpu.cfs_period_us /* period = 250ms */ + +2. 在多CPU机器上,将一个组的运行时间限制为2个CPU的价值 + + 在500ms周期和1000ms配额的情况下,该组每500ms可以获得2个CPU的运行时间:: + + # echo 1000000 > cpu.cfs_quota_us /* quota = 1000ms */ + # echo 500000 > cpu.cfs_period_us /* period = 500ms */ + + 这里较大的周期允许增加突发能力。 + +3. 将一个组限制在1个CPU的20%。 + + 在50ms周期内,10ms配额将相当于1个CPU的20%。:: + + # echo 10000 > cpu.cfs_quota_us /* quota = 10ms */ + # echo 50000 > cpu.cfs_period_us /* period = 50ms */ + + 通过在这里使用一个小的周期,我们以牺牲突发容量为代价来确保稳定的延迟响应。 + +4. 将一个组限制在1个CPU的40%,并允许累积到1个CPU的20%,如果已经累积了的话。 + + 在50ms周期内,20ms配额将相当于1个CPU的40%。而10毫秒的突发将相当于1个 + CPU的20%:: + + # echo 20000 > cpu.cfs_quota_us /* quota = 20ms */ + # echo 50000 > cpu.cfs_period_us /* period = 50ms */ + # echo 10000 > cpu.cfs_burst_us /* burst = 10ms */ + + 较大的缓冲区设置(不大于配额)允许更大的突发容量。 |