sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextEnglish}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/core-api/workqueuemodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/zh_TW/core-api/workqueuemodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/it_IT/core-api/workqueuemodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/ja_JP/core-api/workqueuemodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/ko_KR/core-api/workqueuemodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/sp_SP/core-api/workqueuemodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageChinese (Simplified)uh1h hh _documenthsourceNlineNubhcomment)}(h SPDX-License-Identifier: GPL-2.0h]h SPDX-License-Identifier: GPL-2.0}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhhS/var/lib/git/docbuild/linux/Documentation/translations/zh_CN/core-api/workqueue.rsthKubhnote)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]h paragraph)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hh5Documentation/translations/zh_CN/disclaimer-zh_CN.rsthKhhubah}(h]h ]h"]h$]h&]uh1hhhhhhhhNubh field_list)}(hhh](hfield)}(hhh](h field_name)}(hOriginalh]hOriginal}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh field_body)}(h%Documentation/core-api/workqueue.rst h]h)}(h$Documentation/core-api/workqueue.rsth]h$Documentation/core-api/workqueue.rst}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(h翻译h]h翻译}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hhhKubh)}(h司延腾 Yanteng Si 周彬彬 Binbin Zhou 陈兴友 Xingyou Chen h]h)}(h司延腾 Yanteng Si 周彬彬 Binbin Zhou 陈兴友 Xingyou Chen h](h司延腾 Yanteng Si <}(hj hhhNhNubh reference)}(hsiyanteng@loongson.cnh]hsiyanteng@loongson.cn}(hj*hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:siyanteng@loongson.cnuh1j(hj ubh> 周彬彬 Binbin Zhou <}(hj hhhNhNubj))}(hzhoubinbin@loongson.cnh]hzhoubinbin@loongson.cn}(hj>hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:zhoubinbin@loongson.cnuh1j(hj ubh> 陈兴友 Xingyou Chen <}(hj hhhNhNubj))}(hrockrush@rockwork.orgh]hrockrush@rockwork.org}(hjRhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:rockrush@rockwork.orguh1j(hj ubh>}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhj ubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubhtarget)}(h.. _cn_workqueue.rst:h]h}(h]h ]h"]h$]h&]refidcn-workqueue-rstuh1j~hKhhhhhhubhsection)}(hhh](htitle)}(h 工作队列h]h 工作队列}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhKubh)}(hhh](h)}(hhh](h)}(h日期h]h日期}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubh)}(hSeptember, 2010h]h)}(hjh]hSeptember, 2010}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hhh](h)}(h作者h]h作者}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubh)}(hTejun Heo h]h)}(hjh](h Tejun Heo <}(hjhhhNhNubj))}(h tj@kernel.orgh]h tj@kernel.org}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:tj@kernel.orguh1j(hjubh>}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hhh](h)}(h作者h]h作者}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubh)}(h'Florian Mickler h]h)}(h%Florian Mickler h](hFlorian Mickler <}(hj)hhhNhNubj))}(hflorian@mickler.orgh]hflorian@mickler.org}(hj1hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:florian@mickler.orguh1j(hj)ubh>}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj%ubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]h ]h"]h$]h&]uh1hhjhhhhhKubj)}(hhh](j)}(h简介h]h简介}(hj`hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj]hhhhhKubh)}(h~在很多情况下,需要一个异步的程序执行环境,工作队列(wq)API是这种情况下 最常用的机制。h]h~在很多情况下,需要一个异步的程序执行环境,工作队列(wq)API是这种情况下 最常用的机制。}(hjnhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj]hhubh)}(hX2当需要这样一个异步执行上下文时,一个描述将要执行的函数的工作项(work, 即一个待执行的任务)被放在队列中。一个独立的线程作为异步执行环境。该队 列被称为workqueue,线程被称为工作者(worker,即执行这一队列的线程)。h]hX2当需要这样一个异步执行上下文时,一个描述将要执行的函数的工作项(work, 即一个待执行的任务)被放在队列中。一个独立的线程作为异步执行环境。该队 列被称为workqueue,线程被称为工作者(worker,即执行这一队列的线程)。}(hj|hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj]hhubh)}(h当工作队列上有工作项时,工作者会一个接一个地执行与工作项相关的函数。当 工作队列中没有任何工作项时,工作者就会变得空闲。当一个新的工作项被排入 队列时,工作者又开始执行。h]h当工作队列上有工作项时,工作者会一个接一个地执行与工作项相关的函数。当 工作队列中没有任何工作项时,工作者就会变得空闲。当一个新的工作项被排入 队列时,工作者又开始执行。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK!hj]hhubeh}(h]id2ah ]h"]简介ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h(为什么要有并发管理工作队列?h]h(为什么要有并发管理工作队列?}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhK'ubh)}(hXt在最初的wq实现中,多线程(MT)wq在每个CPU上有一个工作者线程,而单线程 (ST)wq在全系统有一个工作者线程。一个MT wq需要保持与CPU数量相同的工 作者数量。这些年来,内核增加了很多MT wq的用户,随着CPU核心数量的不断 增加,一些系统刚启动就达到了默认的32k PID的饱和空间。h]hXt在最初的wq实现中,多线程(MT)wq在每个CPU上有一个工作者线程,而单线程 (ST)wq在全系统有一个工作者线程。一个MT wq需要保持与CPU数量相同的工 作者数量。这些年来,内核增加了很多MT wq的用户,随着CPU核心数量的不断 增加,一些系统刚启动就达到了默认的32k PID的饱和空间。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK)hjhhubh)}(hX尽管MT wq浪费了大量的资源,但所提供的并发性水平却不能令人满意。这个限 制在ST和MT wq中都有,只是在MT中没有那么严重。每个wq都保持着自己独立的 工作者池。一个MT wq只能为每个CPU提供一个执行环境,而一个ST wq则为整个 系统提供一个。工作项必须竞争这些非常有限的执行上下文,从而导致各种问题, 包括在单一执行上下文周围容易发生死锁。h]hX尽管MT wq浪费了大量的资源,但所提供的并发性水平却不能令人满意。这个限 制在ST和MT wq中都有,只是在MT中没有那么严重。每个wq都保持着自己独立的 工作者池。一个MT wq只能为每个CPU提供一个执行环境,而一个ST wq则为整个 系统提供一个。工作项必须竞争这些非常有限的执行上下文,从而导致各种问题, 包括在单一执行上下文周围容易发生死锁。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK.hjhhubh)}(hX(MT wq)所提供的并发性水平和资源使用之间的矛盾也迫使其用户做出不必要的权衡,比 如libata选择使用ST wq来轮询PIO,并接受一个不必要的限制,即没有两个轮 询PIO可以同时进行。由于MT wq并没有提供更好的并发性,需要更高层次的并 发性的用户,如async或fscache,不得不实现他们自己的线程池。h]hX(MT wq)所提供的并发性水平和资源使用之间的矛盾也迫使其用户做出不必要的权衡,比 如libata选择使用ST wq来轮询PIO,并接受一个不必要的限制,即没有两个轮 询PIO可以同时进行。由于MT wq并没有提供更好的并发性,需要更高层次的并 发性的用户,如async或fscache,不得不实现他们自己的线程池。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK4hjhhubh)}(hT并发管理工作队列(cmwq)是对wq的重新实现,重点是以下目标。h]hT并发管理工作队列(cmwq)是对wq的重新实现,重点是以下目标。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK9hjhhubh bullet_list)}(hhh](h list_item)}(h.保持与原始工作队列API的兼容性。 h]h)}(h-保持与原始工作队列API的兼容性。h]h-保持与原始工作队列API的兼容性。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK;hjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h_使用由所有wq共享的每CPU统一的工作者池,在不浪费大量资源的情况下按h]h)}(hj h]h_使用由所有wq共享的每CPU统一的工作者池,在不浪费大量资源的情况下按}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK=hjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h"需提供灵活的并发水平。 h]h)}(h!需提供灵活的并发水平。h]h!需提供灵活的并发水平。}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK>hjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(hV自动调节工作者池和并发水平,使API用户不需要担心这些细节。 h]h)}(hT自动调节工作者池和并发水平,使API用户不需要担心这些细节。h]hT自动调节工作者池和并发水平,使API用户不需要担心这些细节。}(hj;hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK@hj7ubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubeh}(h]h ]h"]h$]h&]bullet*uh1jhhhK;hjhhubeh}(h]id3ah ]h"](为什么要有并发管理工作队列?ah$]h&]uh1jhjhhhhhK'ubj)}(hhh](j)}(h设计h]h设计}(hjbhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj_hhhhhKDubh)}(hW为了简化函数的异步执行,引入了一个新的抽象概念,即工作项。h]hW为了简化函数的异步执行,引入了一个新的抽象概念,即工作项。}(hjphhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKFhj_hhubh)}(hXA一个工作项是一个简单的结构,它持有一个指向将被异步执行的函数的指针。 每当一个驱动程序或子系统希望一个函数被异步执行时,它必须建立一个指 向该函数的工作项,并在工作队列中排队等待该工作项。(就是挂到workqueue 队列里面去)h]hXA一个工作项是一个简单的结构,它持有一个指向将被异步执行的函数的指针。 每当一个驱动程序或子系统希望一个函数被异步执行时,它必须建立一个指 向该函数的工作项,并在工作队列中排队等待该工作项。(就是挂到workqueue 队列里面去)}(hj~hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKHhj_hhubh)}(h=工作项可以在线程或BH(软中断)上下文中执行。h]h=工作项可以在线程或BH(软中断)上下文中执行。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKMhj_hhubh)}(h对于由线程执行的工作队列,被称为(内核)工作者([k]worker)的特殊 线程会依次执行其中的函数。如果没有工作项排队,工作者线程就会闲置。 这些工作者线程被管理在所谓的工作者池中。h]h对于由线程执行的工作队列,被称为(内核)工作者([k]worker)的特殊 线程会依次执行其中的函数。如果没有工作项排队,工作者线程就会闲置。 这些工作者线程被管理在所谓的工作者池中。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKOhj_hhubh)}(hcmwq设计区分了面向用户的工作队列,子系统和驱动程序在上面排队工作, 以及管理工作者池和处理排队工作项的后端机制。h]hcmwq设计区分了面向用户的工作队列,子系统和驱动程序在上面排队工作, 以及管理工作者池和处理排队工作项的后端机制。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKShj_hhubh)}(h每个可能的CPU都有两个工作者池,一个用于正常的工作项,另一个用于高 优先级的工作项,还有一些额外的工作者池,用于服务未绑定工作队列的工 作项目——这些后备池的数量是动态的。h]h每个可能的CPU都有两个工作者池,一个用于正常的工作项,另一个用于高 优先级的工作项,还有一些额外的工作者池,用于服务未绑定工作队列的工 作项目——这些后备池的数量是动态的。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKVhj_hhubh)}(hXBH工作队列使用相同的结构。然而,由于同一时间只可能有一个执行上下文, 不需要担心并发问题。每个CPU上的BH工作者池只包含一个用于表示BH执行 上下文的虚拟工作者。BH工作队列可以被看作软中断的便捷接口。h]hXBH工作队列使用相同的结构。然而,由于同一时间只可能有一个执行上下文, 不需要担心并发问题。每个CPU上的BH工作者池只包含一个用于表示BH执行 上下文的虚拟工作者。BH工作队列可以被看作软中断的便捷接口。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKZhj_hhubh)}(hX当他们认为合适的时候,子系统和驱动程序可以通过特殊的 ``workqueue API`` 函数创建和排队工作项。他们可以通过在工作队列上 设置标志来影响工作项执行方式的某些方面,他们把工作项放在那里。这些 标志包括诸如CPU定位、并发限制、优先级等等。要获得详细的概述,请参 考下面的 ``alloc_workqueue()`` 的 API 描述。h](hO当他们认为合适的时候,子系统和驱动程序可以通过特殊的 }(hjhhhNhNubhliteral)}(h``workqueue API``h]h workqueue API}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhX 函数创建和排队工作项。他们可以通过在工作队列上 设置标志来影响工作项执行方式的某些方面,他们把工作项放在那里。这些 标志包括诸如CPU定位、并发限制、优先级等等。要获得详细的概述,请参 考下面的 }(hjhhhNhNubj)}(h``alloc_workqueue()``h]halloc_workqueue()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 的 API 描述。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK^hj_hhubh)}(hX_当一个工作项被排入一个工作队列时,目标工作池将根据队列参数和工作队 列属性确定,并被附加到工作池的共享工作列表上。例如,除非特别重写, 否则一个绑定的工作队列的工作项将被排在与发起线程运行的CPU相关的普 通或高级工作工作者池的工作项列表中。h]hX_当一个工作项被排入一个工作队列时,目标工作池将根据队列参数和工作队 列属性确定,并被附加到工作池的共享工作列表上。例如,除非特别重写, 否则一个绑定的工作队列的工作项将被排在与发起线程运行的CPU相关的普 通或高级工作工作者池的工作项列表中。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKdhj_hhubh)}(hX对于任何线程池的实施,管理并发水平(有多少执行上下文处于活动状 态)是一个重要问题。cmwq试图将并发保持在一个尽可能低且充足的 水平。最低水平是为了节省资源,而充足是为了使系统能被充分使用。h]hX对于任何线程池的实施,管理并发水平(有多少执行上下文处于活动状 态)是一个重要问题。cmwq试图将并发保持在一个尽可能低且充足的 水平。最低水平是为了节省资源,而充足是为了使系统能被充分使用。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKihj_hhubh)}(hX每个与实际CPU绑定的worker-pool通过钩住调度器来实现并发管理。每当 一个活动的工作者被唤醒或睡眠时,工作者池就会得到通知,并跟踪当前可 运行的工作者的数量。一般来说,工作项不会占用CPU并消耗很多周期。这 意味着保持足够的并发性以防止工作处理停滞应该是最优的。只要CPU上有 一个或多个可运行的工作者,工作者池就不会开始执行新的工作,但是,当 最后一个运行的工作者进入睡眠状态时,它会立即安排一个新的工作者,这 样CPU就不会在有待处理的工作项目时闲置。这允许在不损失执行带宽的情 况下使用最少的工作者。h]hX每个与实际CPU绑定的worker-pool通过钩住调度器来实现并发管理。每当 一个活动的工作者被唤醒或睡眠时,工作者池就会得到通知,并跟踪当前可 运行的工作者的数量。一般来说,工作项不会占用CPU并消耗很多周期。这 意味着保持足够的并发性以防止工作处理停滞应该是最优的。只要CPU上有 一个或多个可运行的工作者,工作者池就不会开始执行新的工作,但是,当 最后一个运行的工作者进入睡眠状态时,它会立即安排一个新的工作者,这 样CPU就不会在有待处理的工作项目时闲置。这允许在不损失执行带宽的情 况下使用最少的工作者。}(hj"hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKmhj_hhubh)}(h除了kthreads的内存空间外,保留空闲的工作者并没有其他成本,所以cmwq 在杀死它们之前会保留一段时间的空闲。h]h除了kthreads的内存空间外,保留空闲的工作者并没有其他成本,所以cmwq 在杀死它们之前会保留一段时间的空闲。}(hj0hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKvhj_hhubh)}(hXl对于非绑定的工作队列,后备池的数量是动态的。可以使用 ``apply_workqueue_attrs()`` 为非绑定工作队列分配自定义属性, workqueue将自动创建与属性相匹配的后备工作者池。调节并发水平的责任在 用户身上。也有一个标志可以将绑定的wq标记为忽略并发管理。 详情请参考API部分。h](hO对于非绑定的工作队列,后备池的数量是动态的。可以使用 }(hj>hhhNhNubj)}(h``apply_workqueue_attrs()``h]happly_workqueue_attrs()}(hjFhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj>ubhX 为非绑定工作队列分配自定义属性, workqueue将自动创建与属性相匹配的后备工作者池。调节并发水平的责任在 用户身上。也有一个标志可以将绑定的wq标记为忽略并发管理。 详情请参考API部分。}(hj>hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKyhj_hhubh)}(hX前进进度的保证依赖于当需要更多的执行上下文时可以创建工作者,这也是 通过使用救援工作者来保证的。所有可能在处理内存回收的代码路径上使用 的工作项都需要在wq上排队,wq上保留了一个救援工作者,以便在内存有压 力的情况下下执行。否则,工作者池就有可能出现死锁,等待执行上下文释 放出来。h]hX前进进度的保证依赖于当需要更多的执行上下文时可以创建工作者,这也是 通过使用救援工作者来保证的。所有可能在处理内存回收的代码路径上使用 的工作项都需要在wq上排队,wq上保留了一个救援工作者,以便在内存有压 力的情况下下执行。否则,工作者池就有可能出现死锁,等待执行上下文释 放出来。}(hj^hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj_hhubeh}(h]id4ah ]h"]设计ah$]h&]uh1jhjhhhhhKDubj)}(hhh](j)}(h应用程序编程接口 (API)h]h应用程序编程接口 (API)}(hjwhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjthhhhhKubh)}(hX``alloc_workqueue()`` 分配了一个wq。原来的 ``create_*workqueue()`` 函数已被废弃,并计划删除。 ``alloc_workqueue()`` 需要三个 参数 - ``@name`` , ``@flags`` 和 ``@max_active`` 。 ``@name`` 是wq的名称,如果有的话,也用作救援线程的名称。h](j)}(h``alloc_workqueue()``h]halloc_workqueue()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 分配了一个wq。原来的 }(hjhhhNhNubj)}(h``create_*workqueue()``h]hcreate_*workqueue()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh) 函数已被废弃,并计划删除。 }(hjhhhNhNubj)}(h``alloc_workqueue()``h]halloc_workqueue()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 需要三个 参数 - }(hjhhhNhNubj)}(h ``@name``h]h@name}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh , }(hjhhhNhNubj)}(h ``@flags``h]h@flags}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 和 }(hjhhhNhNubj)}(h``@max_active``h]h @max_active}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 。 }(hjhhhNhNubj)}(h ``@name``h]h@name}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhE 是wq的名称,如果有的话,也用作救援线程的名称。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjthhubh)}(h一个wq不再管理执行资源,而是作为前进进度保证、刷新(flush)和 工作项属性的域。 ``@flags`` 和 ``@max_active`` 控制着工作 项如何被分配执行资源、安排和执行。h](hn一个wq不再管理执行资源,而是作为前进进度保证、刷新(flush)和 工作项属性的域。 }(hj hhhNhNubj)}(h ``@flags``h]h@flags}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh 和 }(hj hhhNhNubj)}(h``@max_active``h]h @max_active}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubhD 控制着工作 项如何被分配执行资源、安排和执行。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjthhubj)}(hhh](j)}(h ``flags``h]j)}(hjDh]hflags}(hjFhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjBubah}(h]h ]h"]h$]h&]uh1jhj?hhhhhKubhdefinition_list)}(hhh](hdefinition_list_item)}(hX``WQ_BH`` BH工作队列可以被看作软中断的便捷接口。它总是每个CPU一份, 其中的各个工作项也会按在队列中的顺序,被所属CPU在软中断 上下文中执行。 BH工作队列的 ``max_active`` 值必须为0,且只能单独或和 ``WQ_HIGHPRI`` 标志组合使用。 BH工作项不可以睡眠。像延迟排队、冲洗、取消等所有其他特性 都是支持的。 h](hterm)}(h ``WQ_BH``h]j)}(hjhh]hWQ_BH}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjfubah}(h]h ]h"]h$]h&]uh1jdhhhKhj`ubh definition)}(hhh](h)}(hBH工作队列可以被看作软中断的便捷接口。它总是每个CPU一份, 其中的各个工作项也会按在队列中的顺序,被所属CPU在软中断 上下文中执行。h]hBH工作队列可以被看作软中断的便捷接口。它总是每个CPU一份, 其中的各个工作项也会按在队列中的顺序,被所属CPU在软中断 上下文中执行。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hkBH工作队列的 ``max_active`` 值必须为0,且只能单独或和 ``WQ_HIGHPRI`` 标志组合使用。h](hBH工作队列的 }(hjhhhNhNubj)}(h``max_active``h]h max_active}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh' 值必须为0,且只能单独或和 }(hjhhhNhNubj)}(h``WQ_HIGHPRI``h]h WQ_HIGHPRI}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 标志组合使用。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hfBH工作项不可以睡眠。像延迟排队、冲洗、取消等所有其他特性 都是支持的。h]hfBH工作项不可以睡眠。像延迟排队、冲洗、取消等所有其他特性 都是支持的。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1j}hj`ubeh}(h]h ]h"]h$]h&]uh1j^hhhKhj[ubj_)}(hX~``WQ_UNBOUND`` 排队到非绑定wq的工作项由特殊的工作者池提供服务,这些工作者不 绑定在任何特定的CPU上。这使得wq表现得像一个简单的执行环境提 供者,没有并发管理。非绑定工作者池试图尽快开始执行工作项。非 绑定的wq牺牲了局部性,但在以下情况下是有用的。 * 预计并发水平要求会有很大的波动,使用绑定的wq最终可能会在不 同的CPU上产生大量大部分未使用的工作者,因为发起线程在不同 的CPU上跳转。 * 长期运行的CPU密集型工作负载,可以由系统调度器更好地管理。 h](je)}(h``WQ_UNBOUND``h]j)}(hjh]h WQ_UNBOUND}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jdhhhKhjubj~)}(hhh](h)}(hXP排队到非绑定wq的工作项由特殊的工作者池提供服务,这些工作者不 绑定在任何特定的CPU上。这使得wq表现得像一个简单的执行环境提 供者,没有并发管理。非绑定工作者池试图尽快开始执行工作项。非 绑定的wq牺牲了局部性,但在以下情况下是有用的。h]hXP排队到非绑定wq的工作项由特殊的工作者池提供服务,这些工作者不 绑定在任何特定的CPU上。这使得wq表现得像一个简单的执行环境提 供者,没有并发管理。非绑定工作者池试图尽快开始执行工作项。非 绑定的wq牺牲了局部性,但在以下情况下是有用的。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubj)}(hhh](j)}(h预计并发水平要求会有很大的波动,使用绑定的wq最终可能会在不 同的CPU上产生大量大部分未使用的工作者,因为发起线程在不同 的CPU上跳转。 h]h)}(h预计并发水平要求会有很大的波动,使用绑定的wq最终可能会在不 同的CPU上产生大量大部分未使用的工作者,因为发起线程在不同 的CPU上跳转。h]h预计并发水平要求会有很大的波动,使用绑定的wq最终可能会在不 同的CPU上产生大量大部分未使用的工作者,因为发起线程在不同 的CPU上跳转。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hU长期运行的CPU密集型工作负载,可以由系统调度器更好地管理。 h]h)}(hT长期运行的CPU密集型工作负载,可以由系统调度器更好地管理。h]hT长期运行的CPU密集型工作负载,可以由系统调度器更好地管理。}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj#ubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jUjVuh1jhhhKhjubeh}(h]h ]h"]h$]h&]uh1j}hjubeh}(h]h ]h"]h$]h&]uh1j^hhhKhj[hhubj_)}(h``WQ_FREEZABLE`` 一个可冻结的wq参与了系统暂停操作的冻结阶段。wq上的工作项被 排空,在解冻之前没有新的工作项开始执行。 h](je)}(h``WQ_FREEZABLE``h]j)}(hjSh]h WQ_FREEZABLE}(hjUhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjQubah}(h]h ]h"]h$]h&]uh1jdhhhKhjMubj~)}(hhh]h)}(h一个可冻结的wq参与了系统暂停操作的冻结阶段。wq上的工作项被 排空,在解冻之前没有新的工作项开始执行。h]h一个可冻结的wq参与了系统暂停操作的冻结阶段。wq上的工作项被 排空,在解冻之前没有新的工作项开始执行。}(hjkhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhubah}(h]h ]h"]h$]h&]uh1j}hjMubeh}(h]h ]h"]h$]h&]uh1j^hhhKhj[hhubj_)}(h``WQ_MEM_RECLAIM`` 所有可能在内存回收路径中使用的wq都必须设置这个标志。无论内 存压力如何,wq都能保证至少有一个执行上下文。 h](je)}(h``WQ_MEM_RECLAIM``h]j)}(hjh]hWQ_MEM_RECLAIM}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jdhhhKhjubj~)}(hhh]h)}(h所有可能在内存回收路径中使用的wq都必须设置这个标志。无论内 存压力如何,wq都能保证至少有一个执行上下文。h]h所有可能在内存回收路径中使用的wq都必须设置这个标志。无论内 存压力如何,wq都能保证至少有一个执行上下文。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1j}hjubeh}(h]h ]h"]h$]h&]uh1j^hhhKhj[hhubj_)}(hXc``WQ_HIGHPRI`` 高优先级wq的工作项目被排到目标cpu的高优先级工作者池中。高 优先级的工作者池由具有较高级别的工作者线程提供服务。 请注意,普通工作者池和高优先级工作者池之间并不相互影响。他 们各自维护其独立的工作者池,并在其工作者之间实现并发管理。 h](je)}(h``WQ_HIGHPRI``h]j)}(hjh]h WQ_HIGHPRI}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jdhhhKhjubj~)}(hhh](h)}(h高优先级wq的工作项目被排到目标cpu的高优先级工作者池中。高 优先级的工作者池由具有较高级别的工作者线程提供服务。h]h高优先级wq的工作项目被排到目标cpu的高优先级工作者池中。高 优先级的工作者池由具有较高级别的工作者线程提供服务。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h请注意,普通工作者池和高优先级工作者池之间并不相互影响。他 们各自维护其独立的工作者池,并在其工作者之间实现并发管理。h]h请注意,普通工作者池和高优先级工作者池之间并不相互影响。他 们各自维护其独立的工作者池,并在其工作者之间实现并发管理。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1j}hjubeh}(h]h ]h"]h$]h&]uh1j^hhhKhj[hhubj_)}(hXO``WQ_CPU_INTENSIVE`` CPU密集型wq的工作项对并发水平没有贡献。换句话说,可运行的 CPU密集型工作项不会阻止同一工作者池中的其他工作项开始执行。 这对于那些预计会占用CPU周期的绑定工作项很有用,这样它们的 执行就会受到系统调度器的监管。 尽管CPU密集型工作项不会对并发水平做出贡献,但它们的执行开 始仍然受到并发管理的管制,可运行的非CPU密集型工作项会延迟 CPU密集型工作项的执行。 这个标志对于未绑定的wq来说是没有意义的。 h](je)}(h``WQ_CPU_INTENSIVE``h]j)}(hj h]hWQ_CPU_INTENSIVE}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jdhhhKhjubj~)}(hhh](h)}(hX.CPU密集型wq的工作项对并发水平没有贡献。换句话说,可运行的 CPU密集型工作项不会阻止同一工作者池中的其他工作项开始执行。 这对于那些预计会占用CPU周期的绑定工作项很有用,这样它们的 执行就会受到系统调度器的监管。h]hX.CPU密集型wq的工作项对并发水平没有贡献。换句话说,可运行的 CPU密集型工作项不会阻止同一工作者池中的其他工作项开始执行。 这对于那些预计会占用CPU周期的绑定工作项很有用,这样它们的 执行就会受到系统调度器的监管。}(hj!hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h尽管CPU密集型工作项不会对并发水平做出贡献,但它们的执行开 始仍然受到并发管理的管制,可运行的非CPU密集型工作项会延迟 CPU密集型工作项的执行。h]h尽管CPU密集型工作项不会对并发水平做出贡献,但它们的执行开 始仍然受到并发管理的管制,可运行的非CPU密集型工作项会延迟 CPU密集型工作项的执行。}(hj/hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h;这个标志对于未绑定的wq来说是没有意义的。h]h;这个标志对于未绑定的wq来说是没有意义的。}(hj=hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1j}hjubeh}(h]h ]h"]h$]h&]uh1j^hhhKhj[hhubeh}(h]h ]h"]h$]h&]uh1jYhj?hhhhhNubeh}(h]flagsah ]h"]flagsah$]h&]uh1jhjthhhhhKubj)}(hhh](j)}(h``max_active``h]j)}(hjjh]h max_active}(hjlhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhubah}(h]h ]h"]h$]h&]uh1jhjehhhhhKubh)}(h``@max_active`` 决定了每个CPU可以分配给wq的工作项的最大执行上 下文数量。例如,如果 ``@max_active`` 为16 ,每个CPU最多可以同 时执行16个wq的工作项。它总是每CPU属性,即便对于未绑定 wq。h](j)}(h``@max_active``h]h @max_active}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhb 决定了每个CPU可以分配给wq的工作项的最大执行上 下文数量。例如,如果 }(hjhhhNhNubj)}(h``@max_active``h]h @max_active}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhu 为16 ,每个CPU最多可以同 时执行16个wq的工作项。它总是每CPU属性,即便对于未绑定 wq。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjehhubh)}(h``@max_active`` 的最大限制是512,当指定为0时使用的默认值是256。 这些值被选得足够高,所以它们不是限制性因素,同时会在失控情况下提供 保护。h](j)}(h``@max_active``h]h @max_active}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 的最大限制是512,当指定为0时使用的默认值是256。 这些值被选得足够高,所以它们不是限制性因素,同时会在失控情况下提供 保护。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjehhubh)}(h一个wq的活动工作项的数量通常由wq的用户来调节,更具体地说,是由用 户在同一时间可以排列多少个工作项来调节。除非有特定的需求来控制活动 工作项的数量,否则建议指定 为"0"。h]h一个wq的活动工作项的数量通常由wq的用户来调节,更具体地说,是由用 户在同一时间可以排列多少个工作项来调节。除非有特定的需求来控制活动 工作项的数量,否则建议指定 为”0”。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjehhubh)}(hX一些用户依赖于任意时刻最多只有一个工作项被执行,且各工作项被按队列中 顺序处理带来的严格执行顺序。``@max_active`` 为1和 ``WQ_UNBOUND`` 的组合曾被用来实现这种行为,现在不用了。请使用 ``alloc_ordered_workqueue()`` 。h](h一些用户依赖于任意时刻最多只有一个工作项被执行,且各工作项被按队列中 顺序处理带来的严格执行顺序。}(hjhhhNhNubj)}(h``@max_active``h]h @max_active}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 为1和 }(hjhhhNhNubj)}(h``WQ_UNBOUND``h]h WQ_UNBOUND}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhG 的组合曾被用来实现这种行为,现在不用了。请使用 }(hjhhhNhNubj)}(h``alloc_ordered_workqueue()``h]halloc_ordered_workqueue()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjehhubeh}(h] max-activeah ]h"] max_activeah$]h&]uh1jhjthhhhhKubeh}(h]apiah ]h"]应用程序编程接口 (api)ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h执行场景示例h]h执行场景示例}(hj.hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj+hhhhhKubh)}(hI下面的示例执行场景试图说明cmwq在不同配置下的行为。h]hI下面的示例执行场景试图说明cmwq在不同配置下的行为。}(hj<hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj+hhubh block_quote)}(h工作项w0、w1、w2被排到同一个CPU上的一个绑定的wq q0上。w0 消耗CPU 5ms,然后睡眠10ms,然后在完成之前再次消耗CPU 5ms。 h]h)}(h工作项w0、w1、w2被排到同一个CPU上的一个绑定的wq q0上。w0 消耗CPU 5ms,然后睡眠10ms,然后在完成之前再次消耗CPU 5ms。h]h工作项w0、w1、w2被排到同一个CPU上的一个绑定的wq q0上。w0 消耗CPU 5ms,然后睡眠10ms,然后在完成之前再次消耗CPU 5ms。}(hjPhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjLubah}(h]h ]h"]h$]h&]uh1jJhhhKhj+hhubh)}(h忽略所有其他的任务、工作和处理开销,并假设简单的FIFO调度, 下面是一个高度简化的原始wq的可能事件序列的版本。::h]h忽略所有其他的任务、工作和处理开销,并假设简单的FIFO调度, 下面是一个高度简化的原始wq的可能事件序列的版本。:}(hjdhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj+hhubh literal_block)}(hXhTIME IN MSECS EVENT 0 w0 starts and burns CPU 5 w0 sleeps 15 w0 wakes up and burns CPU 20 w0 finishes 20 w1 starts and burns CPU 25 w1 sleeps 35 w1 wakes up and finishes 35 w2 starts and burns CPU 40 w2 sleeps 50 w2 wakes up and finishesh]hXhTIME IN MSECS EVENT 0 w0 starts and burns CPU 5 w0 sleeps 15 w0 wakes up and burns CPU 20 w0 finishes 20 w1 starts and burns CPU 25 w1 sleeps 35 w1 wakes up and finishes 35 w2 starts and burns CPU 40 w2 sleeps 50 w2 wakes up and finishes}hjtsbah}(h]h ]h"]h$]h&]hhuh1jrhhhKhj+hhubh)}(h+And with cmwq with ``@max_active`` >= 3, ::h](hAnd with cmwq with }(hjhhhNhNubj)}(h``@max_active``h]h @max_active}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh >= 3,}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj+hhubjs)}(hXhTIME IN MSECS EVENT 0 w0 starts and burns CPU 5 w0 sleeps 5 w1 starts and burns CPU 10 w1 sleeps 10 w2 starts and burns CPU 15 w2 sleeps 15 w0 wakes up and burns CPU 20 w0 finishes 20 w1 wakes up and finishes 25 w2 wakes up and finishesh]hXhTIME IN MSECS EVENT 0 w0 starts and burns CPU 5 w0 sleeps 5 w1 starts and burns CPU 10 w1 sleeps 10 w2 starts and burns CPU 15 w2 sleeps 15 w0 wakes up and burns CPU 20 w0 finishes 20 w1 wakes up and finishes 25 w2 wakes up and finishes}hjsbah}(h]h ]h"]h$]h&]hhuh1jrhhhKhj+hhubh)}(h如果 ``@max_active`` == 2, ::h](h如果 }(hjhhhNhNubj)}(h``@max_active``h]h @max_active}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh == 2,}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj+hhubjs)}(hXhTIME IN MSECS EVENT 0 w0 starts and burns CPU 5 w0 sleeps 5 w1 starts and burns CPU 10 w1 sleeps 15 w0 wakes up and burns CPU 20 w0 finishes 20 w1 wakes up and finishes 20 w2 starts and burns CPU 25 w2 sleeps 35 w2 wakes up and finishesh]hXhTIME IN MSECS EVENT 0 w0 starts and burns CPU 5 w0 sleeps 5 w1 starts and burns CPU 10 w1 sleeps 15 w0 wakes up and burns CPU 20 w0 finishes 20 w1 wakes up and finishes 20 w2 starts and burns CPU 25 w2 sleeps 35 w2 wakes up and finishes}hjsbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhj+hhubh)}(hi现在,我们假设w1和w2被排到了不同的wq q1上,这个wq q1 有 ``WQ_CPU_INTENSIVE`` 设置::h](hL现在,我们假设w1和w2被排到了不同的wq q1上,这个wq q1 有 }(hjhhhNhNubj)}(h``WQ_CPU_INTENSIVE``h]hWQ_CPU_INTENSIVE}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 设置:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj+hhubjs)}(hXFTIME IN MSECS EVENT 0 w0 starts and burns CPU 5 w0 sleeps 5 w1 and w2 start and burn CPU 10 w1 sleeps 15 w2 sleeps 15 w0 wakes up and burns CPU 20 w0 finishes 20 w1 wakes up and finishes 25 w2 wakes up and finishesh]hXFTIME IN MSECS EVENT 0 w0 starts and burns CPU 5 w0 sleeps 5 w1 and w2 start and burn CPU 10 w1 sleeps 15 w2 sleeps 15 w0 wakes up and burns CPU 20 w0 finishes 20 w1 wakes up and finishes 25 w2 wakes up and finishes}hjsbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhj+hhubeh}(h]id5ah ]h"]执行场景示例ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h指南h]h指南}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj hhhhhM!ubj)}(hhh](j)}(hXe如果一个wq可能处理在内存回收期间使用的工作项目,请不 要忘记使用 ``WQ_MEM_RECLAIM`` 。每个设置了 ``WQ_MEM_RECLAIM`` 的wq都有一个为其保留的执行环境。 如果在内存回收过程中使用的多个工作项之间存在依赖关系, 它们应该被排在不同的wq中,每个wq都有 ``WQ_MEM_RECLAIM`` 。 h]h)}(hXd如果一个wq可能处理在内存回收期间使用的工作项目,请不 要忘记使用 ``WQ_MEM_RECLAIM`` 。每个设置了 ``WQ_MEM_RECLAIM`` 的wq都有一个为其保留的执行环境。 如果在内存回收过程中使用的多个工作项之间存在依赖关系, 它们应该被排在不同的wq中,每个wq都有 ``WQ_MEM_RECLAIM`` 。h](h^如果一个wq可能处理在内存回收期间使用的工作项目,请不 要忘记使用 }(hj, hhhNhNubj)}(h``WQ_MEM_RECLAIM``h]hWQ_MEM_RECLAIM}(hj4 hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj, ubh 。每个设置了 }(hj, hhhNhNubj)}(h``WQ_MEM_RECLAIM``h]hWQ_MEM_RECLAIM}(hjF hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj, ubh 的wq都有一个为其保留的执行环境。 如果在内存回收过程中使用的多个工作项之间存在依赖关系, 它们应该被排在不同的wq中,每个wq都有 }(hj, hhhNhNubj)}(h``WQ_MEM_RECLAIM``h]hWQ_MEM_RECLAIM}(hjX hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj, ubh 。}(hj, hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM#hj( ubah}(h]h ]h"]h$]h&]uh1jhj% hhhhhNubj)}(h<除非需要严格排序,否则没有必要使用ST wq。 h]h)}(h;除非需要严格排序,否则没有必要使用ST wq。h]h;除非需要严格排序,否则没有必要使用ST wq。}(hjz hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM)hjv ubah}(h]h ]h"]h$]h&]uh1jhj% hhhhhNubj)}(h除非有特殊需要,建议使用0作为@max_active。在大多数使用情 况下,并发水平通常保持在默认限制之下。 h]h)}(h除非有特殊需要,建议使用0作为@max_active。在大多数使用情 况下,并发水平通常保持在默认限制之下。h]h除非有特殊需要,建议使用0作为@max_active。在大多数使用情 况下,并发水平通常保持在默认限制之下。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM+hj ubah}(h]h ]h"]h$]h&]uh1jhj% hhhhhNubj)}(hX>一个wq作为前进进度保证,``WQ_MEM_RECLAIM`` ,冲洗(flush)和工 作项属性的域。不涉及内存回收的工作项,不需要作为工作项组的一 部分被刷新,也不需要任何特殊属性,可以使用系统中的一个wq。使 用专用wq和系统wq在执行特性上没有区别。 h]h)}(hX=一个wq作为前进进度保证,``WQ_MEM_RECLAIM`` ,冲洗(flush)和工 作项属性的域。不涉及内存回收的工作项,不需要作为工作项组的一 部分被刷新,也不需要任何特殊属性,可以使用系统中的一个wq。使 用专用wq和系统wq在执行特性上没有区别。h](h#一个wq作为前进进度保证,}(hj hhhNhNubj)}(h``WQ_MEM_RECLAIM``h]hWQ_MEM_RECLAIM}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubhX ,冲洗(flush)和工 作项属性的域。不涉及内存回收的工作项,不需要作为工作项组的一 部分被刷新,也不需要任何特殊属性,可以使用系统中的一个wq。使 用专用wq和系统wq在执行特性上没有区别。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM.hj ubah}(h]h ]h"]h$]h&]uh1jhj% hhhhhNubj)}(h除非工作项预计会消耗大量的CPU周期,否则使用绑定的wq通常是有 益的,因为wq操作和工作项执行中的定位水平提高了。 h]h)}(h除非工作项预计会消耗大量的CPU周期,否则使用绑定的wq通常是有 益的,因为wq操作和工作项执行中的定位水平提高了。h]h除非工作项预计会消耗大量的CPU周期,否则使用绑定的wq通常是有 益的,因为wq操作和工作项执行中的定位水平提高了。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM3hj ubah}(h]h ]h"]h$]h&]uh1jhj% hhhhhNubeh}(h]h ]h"]h$]h&]jUjVuh1jhhhM#hj hhubeh}(h]id6ah ]h"]指南ah$]h&]uh1jhjhhhhhM!ubj)}(hhh](j)}(h亲和性作用域h]h亲和性作用域}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj hhhhhM8ubh)}(hX一个非绑定工作队列根据其亲和性作用域来对CPU进行分组以提高缓存 局部性。比如如果一个工作队列使用默认的“cache”亲和性作用域, 它将根据最后一级缓存的边界来分组处理器。这个工作队列上的工作项 将被分配给一个与发起CPU共用最后级缓存的处理器上的工作者。根据 ``affinity_strict`` 的设置,工作者在启动后可能被允许移出 所在作用域,也可能不被允许。h](hXn一个非绑定工作队列根据其亲和性作用域来对CPU进行分组以提高缓存 局部性。比如如果一个工作队列使用默认的“cache”亲和性作用域, 它将根据最后一级缓存的边界来分组处理器。这个工作队列上的工作项 将被分配给一个与发起CPU共用最后级缓存的处理器上的工作者。根据 }(hj hhhNhNubj)}(h``affinity_strict``h]haffinity_strict}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubhb 的设置,工作者在启动后可能被允许移出 所在作用域,也可能不被允许。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM:hj hhubh)}(h3工作队列目前支持以下亲和性作用域。h]h3工作队列目前支持以下亲和性作用域。}(hj' hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMAhj hhubjZ)}(hhh](j_)}(h``default`` 使用模块参数 ``workqueue.default_affinity_scope`` 指定 的作用域,该参数总是会被设为以下作用域中的一个。 h](je)}(h ``default``h]j)}(hj> h]hdefault}(hj@ hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj< ubah}(h]h ]h"]h$]h&]uh1jdhhhMEhj8 ubj~)}(hhh]h)}(h使用模块参数 ``workqueue.default_affinity_scope`` 指定 的作用域,该参数总是会被设为以下作用域中的一个。h](h使用模块参数 }(hjV hhhNhNubj)}(h$``workqueue.default_affinity_scope``h]h workqueue.default_affinity_scope}(hj^ hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjV ubhP 指定 的作用域,该参数总是会被设为以下作用域中的一个。}(hjV hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMDhjS ubah}(h]h ]h"]h$]h&]uh1j}hj8 ubeh}(h]h ]h"]h$]h&]uh1j^hhhMEhj5 ubj_)}(h``cpu`` CPU不被分组。一个CPU上发起的工作项会被同一CPU上的工作者执行。 这使非绑定工作队列表现得像是不含并发管理的每CPU工作队列。 h](je)}(h``cpu``h]j)}(hj h]hcpu}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jdhhhMIhj ubj~)}(hhh]h)}(hCPU不被分组。一个CPU上发起的工作项会被同一CPU上的工作者执行。 这使非绑定工作队列表现得像是不含并发管理的每CPU工作队列。h]hCPU不被分组。一个CPU上发起的工作项会被同一CPU上的工作者执行。 这使非绑定工作队列表现得像是不含并发管理的每CPU工作队列。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMHhj ubah}(h]h ]h"]h$]h&]uh1j}hj ubeh}(h]h ]h"]h$]h&]uh1j^hhhMIhj5 hhubj_)}(hs``smt`` CPU被按SMT边界分组。这通常意味着每个物理CPU核上的各逻辑CPU会 被分进同一组。 h](je)}(h``smt``h]j)}(hj h]hsmt}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jdhhhMMhj ubj~)}(hhh]h)}(hjCPU被按SMT边界分组。这通常意味着每个物理CPU核上的各逻辑CPU会 被分进同一组。h]hjCPU被按SMT边界分组。这通常意味着每个物理CPU核上的各逻辑CPU会 被分进同一组。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMLhj ubah}(h]h ]h"]h$]h&]uh1j}hj ubeh}(h]h ]h"]h$]h&]uh1j^hhhMMhj5 hhubj_)}(h``cache`` CPU被按缓存边界分组。采用哪个缓存边界由架构代码决定。很多情况 下会使用L3。这是默认的亲和性作用域。 h](je)}(h ``cache``h]j)}(hj h]hcache}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jdhhhMQhj ubj~)}(hhh]h)}(hCPU被按缓存边界分组。采用哪个缓存边界由架构代码决定。很多情况 下会使用L3。这是默认的亲和性作用域。h]hCPU被按缓存边界分组。采用哪个缓存边界由架构代码决定。很多情况 下会使用L3。这是默认的亲和性作用域。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMPhj ubah}(h]h ]h"]h$]h&]uh1j}hj ubeh}(h]h ]h"]h$]h&]uh1j^hhhMQhj5 hhubj_)}(h&``numa`` CPU被按NUMA边界分组。 h](je)}(h``numa``h]j)}(hj0 h]hnuma}(hj2 hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj. ubah}(h]h ]h"]h$]h&]uh1jdhhhMThj* ubj~)}(hhh]h)}(hCPU被按NUMA边界分组。h]hCPU被按NUMA边界分组。}(hjH hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMThjE ubah}(h]h ]h"]h$]h&]uh1j}hj* ubeh}(h]h ]h"]h$]h&]uh1j^hhhMThj5 hhubj_)}(hm``system`` 所有CPU被放在同一组。工作队列不尝试在临近发起CPU的CPU上运行 工作项。 h](je)}(h ``system``h]j)}(hjh h]hsystem}(hjj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjf ubah}(h]h ]h"]h$]h&]uh1jdhhhMXhjb ubj~)}(hhh]h)}(ha所有CPU被放在同一组。工作队列不尝试在临近发起CPU的CPU上运行 工作项。h]ha所有CPU被放在同一组。工作队列不尝试在临近发起CPU的CPU上运行 工作项。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMWhj} ubah}(h]h ]h"]h$]h&]uh1j}hjb ubeh}(h]h ]h"]h$]h&]uh1j^hhhMXhj5 hhubeh}(h]h ]h"]h$]h&]uh1jYhj hhhhhNubh)}(h默认的亲和性作用域可以被模块参数 ``workqueue.default_affinity_scope`` 修改,特定工作队列的亲和性作用域可以通过 ``apply_workqueue_attrs()`` 被更改。h](h1默认的亲和性作用域可以被模块参数 }(hj hhhNhNubj)}(h$``workqueue.default_affinity_scope``h]h workqueue.default_affinity_scope}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh> 修改,特定工作队列的亲和性作用域可以通过 }(hj hhhNhNubj)}(h``apply_workqueue_attrs()``h]happly_workqueue_attrs()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh 被更改。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMZhj hhubh)}(h如果设置了 ``WQ_SYSFS`` ,工作队列会在它的 ``/sys/devices/virtual/workqueue/WQ_NAME/`` 目录中有以下亲和性作用域相关的接口文件。h](h如果设置了 }(hj hhhNhNubj)}(h ``WQ_SYSFS``h]hWQ_SYSFS}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh ,工作队列会在它的 }(hj hhhNhNubj)}(h+``/sys/devices/virtual/workqueue/WQ_NAME/``h]h'/sys/devices/virtual/workqueue/WQ_NAME/}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh= 目录中有以下亲和性作用域相关的接口文件。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM^hj hhubjZ)}(hhh](j_)}(h``affinity_scope`` 读操作以查看当前的亲和性作用域。写操作用于更改设置。 当前作用域是默认值时,当前生效的作用域也可以被从这个文件中 读到(小括号内),例如 ``default (cache)`` 。 h](je)}(h``affinity_scope``h]j)}(hj h]haffinity_scope}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jdhhhMehj ubj~)}(hhh](h)}(hN读操作以查看当前的亲和性作用域。写操作用于更改设置。h]hN读操作以查看当前的亲和性作用域。写操作用于更改设置。}(hj% hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMbhj" ubh)}(h当前作用域是默认值时,当前生效的作用域也可以被从这个文件中 读到(小括号内),例如 ``default (cache)`` 。h](hz当前作用域是默认值时,当前生效的作用域也可以被从这个文件中 读到(小括号内),例如 }(hj3 hhhNhNubj)}(h``default (cache)``h]hdefault (cache)}(hj; hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj3 ubh 。}(hj3 hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMdhj" ubeh}(h]h ]h"]h$]h&]uh1j}hj ubeh}(h]h ]h"]h$]h&]uh1j^hhhMehj ubj_)}(hX``affinity_strict`` 默认值0表明亲和性作用域不是严格的。当一个工作项开始执行时, 工作队列尽量尝试使工作者处于亲和性作用域内,称为遣返。启动后, 调度器可以自由地将工作者调度到系统中任意它认为合适的地方去。 这使得在保留使用其他CPU(如果必需且有可用)能力的同时, 还能从作用域局部性上获益。 如果设置为1,作用域内的所有工作者将被保证总是处于作用域内。 这在跨亲和性作用域会导致如功耗、负载隔离等方面的潜在影响时 会有用。严格的NUMA作用域也可用于和旧版内核中工作队列的行为 保持一致。 h](je)}(h``affinity_strict``h]j)}(hje h]haffinity_strict}(hjg hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjc ubah}(h]h ]h"]h$]h&]uh1jdhhhMrhj_ ubj~)}(hhh](h)}(hX默认值0表明亲和性作用域不是严格的。当一个工作项开始执行时, 工作队列尽量尝试使工作者处于亲和性作用域内,称为遣返。启动后, 调度器可以自由地将工作者调度到系统中任意它认为合适的地方去。 这使得在保留使用其他CPU(如果必需且有可用)能力的同时, 还能从作用域局部性上获益。h]hX默认值0表明亲和性作用域不是严格的。当一个工作项开始执行时, 工作队列尽量尝试使工作者处于亲和性作用域内,称为遣返。启动后, 调度器可以自由地将工作者调度到系统中任意它认为合适的地方去。 这使得在保留使用其他CPU(如果必需且有可用)能力的同时, 还能从作用域局部性上获益。}(hj} hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhhjz ubh)}(hX如果设置为1,作用域内的所有工作者将被保证总是处于作用域内。 这在跨亲和性作用域会导致如功耗、负载隔离等方面的潜在影响时 会有用。严格的NUMA作用域也可用于和旧版内核中工作队列的行为 保持一致。h]hX如果设置为1,作用域内的所有工作者将被保证总是处于作用域内。 这在跨亲和性作用域会导致如功耗、负载隔离等方面的潜在影响时 会有用。严格的NUMA作用域也可用于和旧版内核中工作队列的行为 保持一致。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMnhjz ubeh}(h]h ]h"]h$]h&]uh1j}hj_ ubeh}(h]h ]h"]h$]h&]uh1j^hhhMrhj hhubeh}(h]h ]h"]h$]h&]uh1jYhj hhhhhNubeh}(h]id7ah ]h"]亲和性作用域ah$]h&]uh1jhjhhhhhM8ubj)}(hhh](j)}(h亲和性作用域与性能h]h亲和性作用域与性能}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj hhhhhMuubh)}(hX如果非绑定工作队列的行为对绝大多数使用场景来说都是最优的, 不需要更多调节,就完美了。很不幸,在当前内核中,重度使用 工作队列时,需要在局部性和利用率间显式地作一个明显的权衡。h]hX如果非绑定工作队列的行为对绝大多数使用场景来说都是最优的, 不需要更多调节,就完美了。很不幸,在当前内核中,重度使用 工作队列时,需要在局部性和利用率间显式地作一个明显的权衡。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMwhj hhubh)}(hX;更高的局部性带来更高效率,也就是相同数量的CPU周期内可以做 更多工作。然而,如果发起者没能将工作项充分地分散在亲和性 作用域间,更高的局部性也可能带来更低的整体系统利用率。以下 dm-crypt 的性能测试清楚地阐明了这一取舍。h]hX;更高的局部性带来更高效率,也就是相同数量的CPU周期内可以做 更多工作。然而,如果发起者没能将工作项充分地分散在亲和性 作用域间,更高的局部性也可能带来更低的整体系统利用率。以下 dm-crypt 的性能测试清楚地阐明了这一取舍。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM{hj hhubh)}(h测试运行在一个12核24线程、4个L3缓存的处理器(AMD Ryzen 9 3900x)上。为保持一致性,关闭CPU超频。 ``/dev/dm-0`` 是NVME SSD(三星 990 PRO)上创建,用 ``cryptsetup`` 以默认配置打开的一个 dm-crypt 设备。Ah](h测试运行在一个12核24线程、4个L3缓存的处理器(AMD Ryzen 9 3900x)上。为保持一致性,关闭CPU超频。 }(hj hhhNhNubj)}(h ``/dev/dm-0``h]h /dev/dm-0}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh0 是NVME SSD(三星 990 PRO)上创建,用 }(hj hhhNhNubj)}(h``cryptsetup``h]h cryptsetup}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh2 以默认配置打开的一个 dm-crypt 设备。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj hhubj)}(hhh](j)}(h=场景 1: 机器上遍布着有充足的发起者和工作量h]h=场景 1: 机器上遍布着有充足的发起者和工作量}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj hhhhhMubh)}(h使用命令:::h]h使用命令::}(hj# hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj hhubjs)}(h$ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k --ioengine=libaio \ --iodepth=64 --runtime=60 --numjobs=24 --time_based --group_reporting \ --name=iops-test-job --verify=sha512h]h$ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k --ioengine=libaio \ --iodepth=64 --runtime=60 --numjobs=24 --time_based --group_reporting \ --name=iops-test-job --verify=sha512}hj1 sbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhj hhubh)}(hX2这里有24个发起者,每个同时发起64个IO。 ``--verify=sha512`` 使得 ``fio`` 每次生成和读回内容受发起者和 ``kcryptd`` 间的执行局部性影响。下面是基于不同 ``kcryptd`` 的亲和性 作用域设置,各经过五次测试得到的读取带宽和CPU利用率数据。h](h7这里有24个发起者,每个同时发起64个IO。 }(hj? hhhNhNubj)}(h``--verify=sha512``h]h--verify=sha512}(hjG hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj? ubh 使得 }(hj? hhhNhNubj)}(h``fio``h]hfio}(hjY hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj? ubh, 每次生成和读回内容受发起者和 }(hj? hhhNhNubj)}(h ``kcryptd``h]hkcryptd}(hjk hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj? ubh5 间的执行局部性影响。下面是基于不同 }(hj? hhhNhNubj)}(h ``kcryptd``h]hkcryptd}(hj} hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj? ubhb 的亲和性 作用域设置,各经过五次测试得到的读取带宽和CPU利用率数据。}(hj? hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj hhubhtable)}(hhh]htgroup)}(hhh](hcolspec)}(hhh]h}(h]h ]h"]h$]h&]colwidthKuh1j hj ubj )}(hhh]h}(h]h ]h"]h$]h&]j Kuh1j hj ubj )}(hhh]h}(h]h ]h"]h$]h&]j Kuh1j hj ubhthead)}(hhh]hrow)}(hhh](hentry)}(hhh]h)}(h 亲和性h]h 亲和性}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj ubj )}(hhh]h)}(h带宽 (MiBps)h]h带宽 (MiBps)}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj ubj )}(hhh]h)}(hCPU利用率(%)h]hCPU利用率(%)}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj ubeh}(h]h ]h"]h$]h&]uh1j hj ubah}(h]h ]h"]h$]h&]uh1j hj ubhtbody)}(hhh](j )}(hhh](j )}(hhh]h)}(hsystemh]hsystem}(hj%hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj"ubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h1159.40 ±1.34h]h1159.40 ±1.34}(hj<hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj9ubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h 99.31 ±0.02h]h 99.31 ±0.02}(hjShhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjPubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh](j )}(hhh]h)}(hcacheh]hcache}(hjshhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjpubah}(h]h ]h"]h$]h&]uh1j hjmubj )}(hhh]h)}(h1166.40 ±0.89h]h1166.40 ±0.89}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjmubj )}(hhh]h)}(h 99.34 ±0.01h]h 99.34 ±0.01}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjmubeh}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh](j )}(hhh]h)}(hcache (strict)h]hcache (strict)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h1166.00 ±0.71h]h1166.00 ±0.71}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h 99.35 ±0.01h]h 99.35 ±0.01}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]colsKuh1j hj ubah}(h]h ]colwidths-givenah"]h$]h&]uh1j hj hhhNhNubh)}(h在系统中分布着足够多发起者的情况下,不论严格与否,“cache” 没有表现得更差。三种配置均使整个机器达到饱和,但由于提高了 局部性,缓存相关的两种有0.6%的(带宽)提升。h]h在系统中分布着足够多发起者的情况下,不论严格与否,“cache” 没有表现得更差。三种配置均使整个机器达到饱和,但由于提高了 局部性,缓存相关的两种有0.6%的(带宽)提升。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj hhubeh}(h]id9ah ]h"]=场景 1: 机器上遍布着有充足的发起者和工作量ah$]h&]uh1jhj hhhhhMubj)}(hhh](j)}(h:场景 2: 更少发起者,足以达到饱和的工作量h]h:场景 2: 更少发起者,足以达到饱和的工作量}(hj6hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj3hhhhhMubh)}(h使用命令:::h]h使用命令::}(hjDhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj3hhubjs)}(h$ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k \ --ioengine=libaio --iodepth=64 --runtime=60 --numjobs=8 \ --time_based --group_reporting --name=iops-test-job --verify=sha512h]h$ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k \ --ioengine=libaio --iodepth=64 --runtime=60 --numjobs=8 \ --time_based --group_reporting --name=iops-test-job --verify=sha512}hjRsbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhj3hhubh)}(h与上一个场景唯一的区别是 ``--numjobs=8``。 发起者数量 减少为三分之一,但仍然有足以使系统达到饱和的工作总量。h](h%与上一个场景唯一的区别是 }(hj`hhhNhNubj)}(h``--numjobs=8``h]h --numjobs=8}(hjhhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj`ubhe。 发起者数量 减少为三分之一,但仍然有足以使系统达到饱和的工作总量。}(hj`hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj3hhubj )}(hhh]j )}(hhh](j )}(hhh]h}(h]h ]h"]h$]h&]j Kuh1j hjubj )}(hhh]h}(h]h ]h"]h$]h&]j Kuh1j hjubj )}(hhh]h}(h]h ]h"]h$]h&]j Kuh1j hjubj )}(hhh]j )}(hhh](j )}(hhh]h)}(h 亲和性h]h 亲和性}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h带宽 (MiBps)h]h带宽 (MiBps)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(hCPU利用率(%)h]hCPU利用率(%)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j hjubj)}(hhh](j )}(hhh](j )}(hhh]h)}(hsystemh]hsystem}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h1155.40 ±0.89h]h1155.40 ±0.89}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h 97.41 ±0.05h]h 97.41 ±0.05}(hj/hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj,ubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh](j )}(hhh]h)}(hcacheh]hcache}(hjOhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjLubah}(h]h ]h"]h$]h&]uh1j hjIubj )}(hhh]h)}(h1154.40 ±1.14h]h1154.40 ±1.14}(hjfhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjcubah}(h]h ]h"]h$]h&]uh1j hjIubj )}(hhh]h)}(h 96.15 ±0.09h]h 96.15 ±0.09}(hj}hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjzubah}(h]h ]h"]h$]h&]uh1j hjIubeh}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh](j )}(hhh]h)}(hcache (strict)h]hcache (strict)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h1112.00 ±4.64h]h1112.00 ±4.64}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h 93.26 ±0.35h]h 93.26 ±0.35}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]colsKuh1j hjubah}(h]h ]jah"]h$]h&]uh1j hj3hhhNhNubh)}(h这里有超过使系统达到饱和所需的工作量。“system”和“cache” 都接近但并未使机器完全饱和。“cache”消耗更少的CPU但更高的 效率使其得到和“system”相同的带宽。h]h这里有超过使系统达到饱和所需的工作量。“system”和“cache” 都接近但并未使机器完全饱和。“cache”消耗更少的CPU但更高的 效率使其得到和“system”相同的带宽。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj3hhubh)}(h八个发起者盘桓在四个L3缓存作用域间仍然允许“cache (strict)” 几乎使机器饱和,但缺少对工作的保持(不移到空闲处理器上) 开始带来3.7%的带宽损失。h]h八个发起者盘桓在四个L3缓存作用域间仍然允许“cache (strict)” 几乎使机器饱和,但缺少对工作的保持(不移到空闲处理器上) 开始带来3.7%的带宽损失。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj3hhubeh}(h]id10ah ]h"]:场景 2: 更少发起者,足以达到饱和的工作量ah$]h&]uh1jhj hhhhhMubj)}(hhh](j)}(h1场景 3: 更少发起者,不充足的工作量h]h1场景 3: 更少发起者,不充足的工作量}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMubh)}(h使用命令:::h]h使用命令::}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubjs)}(h$ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k \ --ioengine=libaio --iodepth=64 --runtime=60 --numjobs=4 \ --time_based --group_reporting --name=iops-test-job --verify=sha512h]h$ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k \ --ioengine=libaio --iodepth=64 --runtime=60 --numjobs=4 \ --time_based --group_reporting --name=iops-test-job --verify=sha512}hj;sbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhjhhubh)}(h再次,唯一的区别是 ``--numjobs=4``。由于发起者减少到四个, 现在没有足以使系统饱和的工作量,带宽变得依赖于完成时延。h](h再次,唯一的区别是 }(hjIhhhNhNubj)}(h``--numjobs=4``h]h --numjobs=4}(hjQhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjIubhy。由于发起者减少到四个, 现在没有足以使系统饱和的工作量,带宽变得依赖于完成时延。}(hjIhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhjhhubj )}(hhh]j )}(hhh](j )}(hhh]h}(h]h ]h"]h$]h&]j Kuh1j hjlubj )}(hhh]h}(h]h ]h"]h$]h&]j Kuh1j hjlubj )}(hhh]h}(h]h ]h"]h$]h&]j Kuh1j hjlubj )}(hhh]j )}(hhh](j )}(hhh]h)}(h 亲和性h]h 亲和性}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h带宽 (MiBps)h]h带宽 (MiBps)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(hCPU利用率(%)h]hCPU利用率(%)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1j hjubah}(h]h ]h"]h$]h&]uh1j hjlubj)}(hhh](j )}(hhh](j )}(hhh]h)}(hsystemh]hsystem}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h 993.60 ±1.82h]h 993.60 ±1.82}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h 75.49 ±0.06h]h 75.49 ±0.06}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh](j )}(hhh]h)}(hcacheh]hcache}(hj8hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj5ubah}(h]h ]h"]h$]h&]uh1j hj2ubj )}(hhh]h)}(h 973.40 ±1.52h]h 973.40 ±1.52}(hjOhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjLubah}(h]h ]h"]h$]h&]uh1j hj2ubj )}(hhh]h)}(h 74.90 ±0.07h]h 74.90 ±0.07}(hjfhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjcubah}(h]h ]h"]h$]h&]uh1j hj2ubeh}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh](j )}(hhh]h)}(hcache (strict)h]hcache (strict)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h 828.20 ±4.49h]h 828.20 ±4.49}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubj )}(hhh]h)}(h 66.84 ±0.29h]h 66.84 ±0.29}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1j hjubeh}(h]h ]h"]h$]h&]uh1jhjlubeh}(h]h ]h"]h$]h&]colsKuh1j hjiubah}(h]h ]jah"]h$]h&]uh1j hjhhhNhNubh)}(h现在,局部性和利用率间的权衡更清晰了。“cache”展示出相比 “system”2%的带宽损失,而“cache (strict)”跌到20%。h]h现在,局部性和利用率间的权衡更清晰了。“cache”展示出相比 “system”2%的带宽损失,而“cache (strict)”跌到20%。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubeh}(h]id11ah ]h"]1场景 3: 更少发起者,不充足的工作量ah$]h&]uh1jhj hhhhhMubj)}(hhh](j)}(h结论和建议h]h结论和建议}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMubh)}(h在以上试验中,虽然一致并且也明显,但“cache”亲和性作用域 相比“system”的性能优势并不大。然而,这影响是依赖于作用域 间距离的,在更复杂的处理器拓扑下可能有更明显的影响。h]h在以上试验中,虽然一致并且也明显,但“cache”亲和性作用域 相比“system”的性能优势并不大。然而,这影响是依赖于作用域 间距离的,在更复杂的处理器拓扑下可能有更明显的影响。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubh)}(h虽然这些情形下缺少工作保持是有坏处的,但比“cache (strict)” 好多了,而且最大化工作队列利用率的需求也并不常见。因此, “cache”是非绑定池的默认亲和性作用域。h]h虽然这些情形下缺少工作保持是有坏处的,但比“cache (strict)” 好多了,而且最大化工作队列利用率的需求也并不常见。因此, “cache”是非绑定池的默认亲和性作用域。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubj)}(hhh](j)}(h由于不存在一个适用于大多数场景的选择,对于可能需要消耗 大量CPU的工作队列,建议通过 ``apply_workqueue_attrs()`` 进行(专门)配置,并考虑是否启用 ``WQ_SYSFS``。 h]h)}(h由于不存在一个适用于大多数场景的选择,对于可能需要消耗 大量CPU的工作队列,建议通过 ``apply_workqueue_attrs()`` 进行(专门)配置,并考虑是否启用 ``WQ_SYSFS``。h](hz由于不存在一个适用于大多数场景的选择,对于可能需要消耗 大量CPU的工作队列,建议通过 }(hj+hhhNhNubj)}(h``apply_workqueue_attrs()``h]happly_workqueue_attrs()}(hj3hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj+ubh2 进行(专门)配置,并考虑是否启用 }(hj+hhhNhNubj)}(h ``WQ_SYSFS``h]hWQ_SYSFS}(hjEhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj+ubh。}(hj+hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj'ubah}(h]h ]h"]h$]h&]uh1jhj$hhhhhNubj)}(h设置了严格“cpu”亲和性作用域的非绑定工作队列,它的行为与 ``WQ_CPU_INTENSIVE`` 每CPU工作队列一样。后者没有真正 优势,而前者提供了大幅度的灵活性。 h]h)}(h设置了严格“cpu”亲和性作用域的非绑定工作队列,它的行为与 ``WQ_CPU_INTENSIVE`` 每CPU工作队列一样。后者没有真正 优势,而前者提供了大幅度的灵活性。h](hU设置了严格“cpu”亲和性作用域的非绑定工作队列,它的行为与 }(hjghhhNhNubj)}(h``WQ_CPU_INTENSIVE``h]hWQ_CPU_INTENSIVE}(hjohhhNhNubah}(h]h ]h"]h$]h&]uh1jhjgubhb 每CPU工作队列一样。后者没有真正 优势,而前者提供了大幅度的灵活性。}(hjghhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM hjcubah}(h]h ]h"]h$]h&]uh1jhj$hhhhhNubj)}(h亲和性作用域是从Linux v6.5起引入的。为了模拟旧版行为, 可以使用严格的“numa”亲和性作用域。 h]h)}(h亲和性作用域是从Linux v6.5起引入的。为了模拟旧版行为, 可以使用严格的“numa”亲和性作用域。h]h亲和性作用域是从Linux v6.5起引入的。为了模拟旧版行为, 可以使用严格的“numa”亲和性作用域。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM hjubah}(h]h ]h"]h$]h&]uh1jhj$hhhhhNubj)}(hX不严格的亲和性作用域中,缺少工作保持大概缘于调度器。内核 为什么没能维护好大多数场景下的工作保持,把事情作对,还没有 理论上的解释。因此,未来调度器的改进可能会使我们不再需要 这些调节项。 h]h)}(hX不严格的亲和性作用域中,缺少工作保持大概缘于调度器。内核 为什么没能维护好大多数场景下的工作保持,把事情作对,还没有 理论上的解释。因此,未来调度器的改进可能会使我们不再需要 这些调节项。h]hX不严格的亲和性作用域中,缺少工作保持大概缘于调度器。内核 为什么没能维护好大多数场景下的工作保持,把事情作对,还没有 理论上的解释。因此,未来调度器的改进可能会使我们不再需要 这些调节项。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhj$hhhhhNubeh}(h]h ]h"]h$]h&]jUjVuh1jhhhMhjhhubeh}(h]id12ah ]h"]结论和建议ah$]h&]uh1jhj hhhhhMubeh}(h]id8ah ]h"]亲和性作用域与性能ah$]h&]uh1jhjhhhhhMuubj)}(hhh](j)}(h 检查配置h]h 检查配置}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMubh)}(h使用 tools/workqueue/wq_dump.py(drgn脚本) 来检查未 绑定CPU的亲和性配置,工作者池,以及工作队列如何映射到池上: ::h]h使用 tools/workqueue/wq_dump.py(drgn脚本) 来检查未 绑定CPU的亲和性配置,工作者池,以及工作队列如何映射到池上:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubjs)}(hXb$ tools/workqueue/wq_dump.py Affinity Scopes =============== wq_unbound_cpumask=0000000f CPU nr_pods 4 pod_cpus [0]=00000001 [1]=00000002 [2]=00000004 [3]=00000008 pod_node [0]=0 [1]=0 [2]=1 [3]=1 cpu_pod [0]=0 [1]=1 [2]=2 [3]=3 SMT nr_pods 4 pod_cpus [0]=00000001 [1]=00000002 [2]=00000004 [3]=00000008 pod_node [0]=0 [1]=0 [2]=1 [3]=1 cpu_pod [0]=0 [1]=1 [2]=2 [3]=3 CACHE (default) nr_pods 2 pod_cpus [0]=00000003 [1]=0000000c pod_node [0]=0 [1]=1 cpu_pod [0]=0 [1]=0 [2]=1 [3]=1 NUMA nr_pods 2 pod_cpus [0]=00000003 [1]=0000000c pod_node [0]=0 [1]=1 cpu_pod [0]=0 [1]=0 [2]=1 [3]=1 SYSTEM nr_pods 1 pod_cpus [0]=0000000f pod_node [0]=-1 cpu_pod [0]=0 [1]=0 [2]=0 [3]=0 Worker Pools ============ pool[00] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 0 pool[01] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 0 pool[02] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 1 pool[03] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 1 pool[04] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 2 pool[05] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 2 pool[06] ref= 1 nice= 0 idle/workers= 3/ 3 cpu= 3 pool[07] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 3 pool[08] ref=42 nice= 0 idle/workers= 6/ 6 cpus=0000000f pool[09] ref=28 nice= 0 idle/workers= 3/ 3 cpus=00000003 pool[10] ref=28 nice= 0 idle/workers= 17/ 17 cpus=0000000c pool[11] ref= 1 nice=-20 idle/workers= 1/ 1 cpus=0000000f pool[12] ref= 2 nice=-20 idle/workers= 1/ 1 cpus=00000003 pool[13] ref= 2 nice=-20 idle/workers= 1/ 1 cpus=0000000c Workqueue CPU -> pool ===================== [ workqueue \ CPU 0 1 2 3 dfl] events percpu 0 2 4 6 events_highpri percpu 1 3 5 7 events_long percpu 0 2 4 6 events_unbound unbound 9 9 10 10 8 events_freezable percpu 0 2 4 6 events_power_efficient percpu 0 2 4 6 events_freezable_power_ percpu 0 2 4 6 rcu_gp percpu 0 2 4 6 rcu_par_gp percpu 0 2 4 6 slub_flushwq percpu 0 2 4 6 netns ordered 8 8 8 8 8 ...h]hXb$ tools/workqueue/wq_dump.py Affinity Scopes =============== wq_unbound_cpumask=0000000f CPU nr_pods 4 pod_cpus [0]=00000001 [1]=00000002 [2]=00000004 [3]=00000008 pod_node [0]=0 [1]=0 [2]=1 [3]=1 cpu_pod [0]=0 [1]=1 [2]=2 [3]=3 SMT nr_pods 4 pod_cpus [0]=00000001 [1]=00000002 [2]=00000004 [3]=00000008 pod_node [0]=0 [1]=0 [2]=1 [3]=1 cpu_pod [0]=0 [1]=1 [2]=2 [3]=3 CACHE (default) nr_pods 2 pod_cpus [0]=00000003 [1]=0000000c pod_node [0]=0 [1]=1 cpu_pod [0]=0 [1]=0 [2]=1 [3]=1 NUMA nr_pods 2 pod_cpus [0]=00000003 [1]=0000000c pod_node [0]=0 [1]=1 cpu_pod [0]=0 [1]=0 [2]=1 [3]=1 SYSTEM nr_pods 1 pod_cpus [0]=0000000f pod_node [0]=-1 cpu_pod [0]=0 [1]=0 [2]=0 [3]=0 Worker Pools ============ pool[00] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 0 pool[01] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 0 pool[02] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 1 pool[03] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 1 pool[04] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 2 pool[05] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 2 pool[06] ref= 1 nice= 0 idle/workers= 3/ 3 cpu= 3 pool[07] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 3 pool[08] ref=42 nice= 0 idle/workers= 6/ 6 cpus=0000000f pool[09] ref=28 nice= 0 idle/workers= 3/ 3 cpus=00000003 pool[10] ref=28 nice= 0 idle/workers= 17/ 17 cpus=0000000c pool[11] ref= 1 nice=-20 idle/workers= 1/ 1 cpus=0000000f pool[12] ref= 2 nice=-20 idle/workers= 1/ 1 cpus=00000003 pool[13] ref= 2 nice=-20 idle/workers= 1/ 1 cpus=0000000c Workqueue CPU -> pool ===================== [ workqueue \ CPU 0 1 2 3 dfl] events percpu 0 2 4 6 events_highpri percpu 1 3 5 7 events_long percpu 0 2 4 6 events_unbound unbound 9 9 10 10 8 events_freezable percpu 0 2 4 6 events_power_efficient percpu 0 2 4 6 events_freezable_power_ percpu 0 2 4 6 rcu_gp percpu 0 2 4 6 rcu_par_gp percpu 0 2 4 6 slub_flushwq percpu 0 2 4 6 netns ordered 8 8 8 8 8 ...}hjsbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhjhhubh)}(h3参见命令的帮助消息以获取更多信息。h]h3参见命令的帮助消息以获取更多信息。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM`hjhhubeh}(h]id13ah ]h"] 检查配置ah$]h&]uh1jhjhhhhhMubj)}(hhh](j)}(h监视h]h监视}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMdubh)}(hI使用 tools/workqueue/wq_monitor.py 来监视工作队列的运行: ::h]hF使用 tools/workqueue/wq_monitor.py 来监视工作队列的运行:}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMfhjhhubjs)}(hX$ tools/workqueue/wq_monitor.py events total infl CPUtime CPUhog CMW/RPR mayday rescued events 18545 0 6.1 0 5 - - events_highpri 8 0 0.0 0 0 - - events_long 3 0 0.0 0 0 - - events_unbound 38306 0 0.1 - 7 - - events_freezable 0 0 0.0 0 0 - - events_power_efficient 29598 0 0.2 0 0 - - events_freezable_power_ 10 0 0.0 0 0 - - sock_diag_events 0 0 0.0 0 0 - - total infl CPUtime CPUhog CMW/RPR mayday rescued events 18548 0 6.1 0 5 - - events_highpri 8 0 0.0 0 0 - - events_long 3 0 0.0 0 0 - - events_unbound 38322 0 0.1 - 7 - - events_freezable 0 0 0.0 0 0 - - events_power_efficient 29603 0 0.2 0 0 - - events_freezable_power_ 10 0 0.0 0 0 - - sock_diag_events 0 0 0.0 0 0 - - ...h]hX$ tools/workqueue/wq_monitor.py events total infl CPUtime CPUhog CMW/RPR mayday rescued events 18545 0 6.1 0 5 - - events_highpri 8 0 0.0 0 0 - - events_long 3 0 0.0 0 0 - - events_unbound 38306 0 0.1 - 7 - - events_freezable 0 0 0.0 0 0 - - events_power_efficient 29598 0 0.2 0 0 - - events_freezable_power_ 10 0 0.0 0 0 - - sock_diag_events 0 0 0.0 0 0 - - total infl CPUtime CPUhog CMW/RPR mayday rescued events 18548 0 6.1 0 5 - - events_highpri 8 0 0.0 0 0 - - events_long 3 0 0.0 0 0 - - events_unbound 38322 0 0.1 - 7 - - events_freezable 0 0 0.0 0 0 - - events_power_efficient 29603 0 0.2 0 0 - - events_freezable_power_ 10 0 0.0 0 0 - - sock_diag_events 0 0 0.0 0 0 - - ...}hj5sbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhhjhhubh)}(h3参见命令的帮助消息以获取更多信息。h]h3参见命令的帮助消息以获取更多信息。}(hjChhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubeh}(h]id14ah ]h"]监视ah$]h&]uh1jhjhhhhhMdubj)}(hhh](j)}(h调试h]h调试}(hj\hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjYhhhhhMubh)}(h因为工作函数是由通用的工作者线程执行的,所以需要一些手段来揭示一些行为不端的工作队列用户。h]h因为工作函数是由通用的工作者线程执行的,所以需要一些手段来揭示一些行为不端的工作队列用户。}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjYhhubh)}(h.工作者线程在进程列表中显示为: ::h]h+工作者线程在进程列表中显示为:}(hjxhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjYhhubjs)}(hX;root 5671 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/0:1] root 5672 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/1:2] root 5673 0.0 0.0 0 0 ? S 12:12 0:00 [kworker/0:0] root 5674 0.0 0.0 0 0 ? S 12:13 0:00 [kworker/1:0]h]hX;root 5671 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/0:1] root 5672 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/1:2] root 5673 0.0 0.0 0 0 ? S 12:12 0:00 [kworker/0:0] root 5674 0.0 0.0 0 0 ? S 12:13 0:00 [kworker/1:0]}hjsbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhjYhhubh)}(hN如果kworkers失控了(使用了太多的cpu),有两类可能的问题:h]hN如果kworkers失控了(使用了太多的cpu),有两类可能的问题:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjYhhubjK)}(hM1. 正在迅速调度的事情 2. 一个消耗大量cpu周期的工作项。 h]henumerated_list)}(hhh](j)}(h正在迅速调度的事情h]h)}(hjh]h正在迅速调度的事情}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h+一个消耗大量cpu周期的工作项。 h]h)}(h*一个消耗大量cpu周期的工作项。h]h*一个消耗大量cpu周期的工作项。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]enumtypearabicprefixhsuffix.uh1jhjubah}(h]h ]h"]h$]h&]uh1jJhhhMhjYhhubh)}(h1第一个可以用追踪的方式进行跟踪: ::h]h.第一个可以用追踪的方式进行跟踪:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjYhhubjs)}(h$ echo workqueue:workqueue_queue_work > /sys/kernel/tracing/set_event $ cat /sys/kernel/tracing/trace_pipe > out.txt (wait a few secs)h]h$ echo workqueue:workqueue_queue_work > /sys/kernel/tracing/set_event $ cat /sys/kernel/tracing/trace_pipe > out.txt (wait a few secs)}hjsbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhjYhhubh)}(h{如果有什么东西在工作队列上忙着做循环,它就会主导输出,可以用工作项函数确定违规者。h]h{如果有什么东西在工作队列上忙着做循环,它就会主导输出,可以用工作项函数确定违规者。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjYhhubh)}(hW对于第二类问题,应该可以只检查违规工作者线程的堆栈跟踪。 ::h]hT对于第二类问题,应该可以只检查违规工作者线程的堆栈跟踪。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjYhhubjs)}(h'$ cat /proc/THE_OFFENDING_KWORKER/stackh]h'$ cat /proc/THE_OFFENDING_KWORKER/stack}hj#sbah}(h]h ]h"]h$]h&]hhuh1jrhhhMhjYhhubh)}(h<工作项函数在堆栈追踪中应该是微不足道的。h]h<工作项函数在堆栈追踪中应该是微不足道的。}(hj1hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjYhhubeh}(h]id15ah ]h"]调试ah$]h&]uh1jhjhhhhhMubj)}(hhh](j)}(h不可重入条件h]h不可重入条件}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjGhhhhhMubh)}(h`工作队列保证,如果在工作项排队后满足以下条件,则工作项不能重入:h]h`工作队列保证,如果在工作项排队后满足以下条件,则工作项不能重入:}(hjXhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjGhhubjK)}(h1. 工作函数没有被改变。 2. 没有人将该工作项排到另一个工作队列中。 3. 该工作项尚未被重新启动。 h]j)}(hhh](j)}(h工作函数没有被改变。h]h)}(hjoh]h工作函数没有被改变。}(hjqhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjmubah}(h]h ]h"]h$]h&]uh1jhjjubj)}(h9没有人将该工作项排到另一个工作队列中。h]h)}(hjh]h9没有人将该工作项排到另一个工作队列中。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjjubj)}(h%该工作项尚未被重新启动。 h]h)}(h$该工作项尚未被重新启动。h]h$该工作项尚未被重新启动。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjjubeh}(h]h ]h"]h$]h&]jjjhjjuh1jhjfubah}(h]h ]h"]h$]h&]uh1jJhhhMhjGhhubh)}(h换言之,如果上述条件成立,则保证在任何给定时间最多由一个系统范围内的工作程序执行 该工作项。h]h换言之,如果上述条件成立,则保证在任何给定时间最多由一个系统范围内的工作程序执行 该工作项。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjGhhubh)}(h请注意,在self函数中将工作项重新排队(到同一队列)不会破坏这些条件,因此可以安全 地执行此操作。否则在破坏工作函数内部的条件时需要小心。h]h请注意,在self函数中将工作项重新排队(到同一队列)不会破坏这些条件,因此可以安全 地执行此操作。否则在破坏工作函数内部的条件时需要小心。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjGhhubeh}(h]id16ah ]h"]不可重入条件ah$]h&]uh1jhjhhhhhMubj)}(hhh](j)}(h内核内联文档参考h]h内核内联文档参考}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMubh)}(h该API在以下内核代码中:h]h该API在以下内核代码中:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubh)}(hinclude/linux/workqueue.hh]hinclude/linux/workqueue.h}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubh)}(hkernel/workqueue.ch]hkernel/workqueue.c}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubeh}(h]id17ah ]h"]内核内联文档参考ah$]h&]uh1jhjhhhhhMubeh}(h](jid1eh ]h"]( 工作队列cn_workqueue.rsteh$]h&]uh1jhhhhhhhKexpect_referenced_by_name}j,jsexpect_referenced_by_id}jjsubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(jN generatorN datestampN source_linkN source_urlN toc_backlinksj footnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerjUerror_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}j]jasnameids}(j,jj+j(jjj\jYjqjnj(j%jbj_j jj j j j j j jjj0j-jjjjjjjjjVjSjDjAjjj#j u nametypes}(j,j+jj\jqj(jbj j j j jj0jjjjjVjDjj#uh}(jjj(jjj]jYjjnj_j%jtj_j?jjej j+j j j j jj j-j jj3jjjjjjjSjjAjYjjGj ju footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}jcKsRparse_messages]transform_messages]hsystem_message)}(hhh]h)}(hhh]h6Hyperlink target "cn-workqueue-rst" is not referenced.}hjsbah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]levelKtypeINFOsourcehlineKuh1juba transformerN include_log]7Documentation/translations/zh_CN/core-api/workqueue.rst(NNNNta decorationNhhub.