多处理器、NUMA 支持,Thread Ordering Service(线程排序服务)?

具有多处理器的计算器通常有两种体系结构:非统一内存访问(NUMA)或对称多处理(SMP)。在NUMA 计算机中,每个处理器比其他处理器更靠近内存的某些部分,使得内存的某些部分的内存访问速度比其他部分更快。在NUMA 模型下,系统尝试在接近正在使用的内存的处理器上调度线程。

SMP 计算机中,两个或多个相同的处理器或核心链接到单个共享主存储器。在SMP 模型下,可以将任何线程分配给任何处理器。因此,在SMP 计算机上调度线程类似于在具有单个处理器的计算机上调度线程。但是,调度程序具有一个处理器池,因此它可以调度线程以同时运行。调度仍然由线程优先级决定,但可以通过设置线程亲和性和线程理想处理器来影响这个选择。

线程亲和性

线程亲和性强制线程在所有处理器的一个子集上执行。通常不应该设置线程的亲和性。因为他可能干扰调度程序跨处理器有效调度线程的能力。这可以降低并行处理产生的性能增强。使用线程亲和性是测试每个处理器,系统使用一个称为处理器亲和性掩码的东西表示亲和性,亲和性掩码的值,是系统中处理器的最大的数量,通过bit 设置来标志处理器的一个子集。最初,系统确定掩码中的处理器子集。可以调用GetProcessAffinityMask 查看进程中所有线程的当前亲和性。使用SetProcessAffinitymask ,为进程的所有线程指定关联。要为单个线程设置线程关联,使用SetThreadAffinityMask 设置线程关联。

在具有超过64 个处理器的系统上,关联掩码最初表示单个处理器组中的处理器。但是,可以将线程关联性设置为不同组中的处理器,这会改变进程的关联掩码。详情参见Processor Groups

线程理想处理器

当指定线程理想处理器,调度器在可能的时候,在该指定的处理器上执行你的线程。使用SetThreadIdealProcessor 指定线程的理想处理器。但不是保证的。在超过64 个处理器的系统上,使用SetThreadIdealProcessorEx 指定特定的处理器组上的特定的处理器。

NUMA 支持

多处理器支持的传统模型是对称多处理器(SMP)。在此模型中,每个处理器都具有对内存和I/O 的相同访问权限。随着更多处理器的添加,处理器总线成为系统性能的限制。

系统设计人员使用非均匀内存访问(NUMA)来提高处理器速度,而不会增加处理器总线上的负载。该架构是不均匀的,因为每个处理器靠近存储器的某些部分并且远离存储器的其他部分。处理器可以快速访问它接近的内存,而可能需要更长时间才能访问更远的内存。

在NUMA 系统中,CPU 被安排在称为节点的较小系统中。每个节点都有子集的处理器和内存,并通过缓存一致的互连总线连接到更大的系统。

系统尝试通过在与正在使用的内存位于同一节点的处理器上调度线程来尝试提高性能。它尝试从节点内满足内存分配请求,但如有必要,将从其他节点分配内存。它还提供了一个API ,使应用程序可以使用系统拓扑。可以通过使用NUMA 函数来优化调度和内存使用,并以此来提高应用程序的性能。

首先,需要确定系统中节点的布局。要检索系统中编号最大的节点,使用GetNumaHighestNodeNumber。注意,这个值,不保证,等于系统中的节点总数。此外,不保证具有顺序的数字的节点靠近在一起。要检索系统上的处理器列表,使用GetProcessAffinityMask 函数。可以使用GetNumaProcessorNode 确定列表中每个处理器的节点。或,要检索节点中所有处理器的列表,使用GetNumaNodeProcessorMask。

确定哪些处理器属于哪些节点后,可以优化应用程序的性能。要确保进程的所有线程在同一个节点上的运行,使用带有进程关联掩码的SetProcessAffinityMask函数,该掩码指定同一节点中的处理器。这提高了线程需要访问相同内存的应用程序的效率。或者,要限制每个节点上的线程数,使用SetThreadAffinityMask 函数。内存密集型应用程序需要优化其内存使用量。要检索节点可用的可用内存量,使用GetNumaAvailiableMemoryNode 函数。VirtualAllocExNuma 函数使应用程序能够为内存分配指定首选节点。VirtualAllocExNuma 不分配任何物理页面,因此无论页面在该节点上还是系统中的其他位置都可用,它都将成功。物理页面按需分配。如果首选节点用完页面,则内存管理器将使用其他节点的页面。如果内存被换出(paged out),则在重新启用时会使用相同的过程。

在超过64 个逻辑处理器上,系统上的NUMA 支持

 

NUMA API

 

线程排序服务

线程排序服务控制一个或多个客户线程的执行。它保证确保每个客户端线程在指定的时间段内以相对顺序运行一次。

从Windows Vista 和 Windows Server 2008 开始,线程排序服务才开始被提供。

该服务默认管理,必须由用户开启。当它执行,它每5 秒被唤起,以检查这里是否有新的请求,系统空闲的时候也是这个频率。这避免了系统睡眠超过5 秒,使系统消耗更多的资源。如果能量效率对应用程序至关重要,最好不要使用线程排序服务,而是允许系统调度程序管理线程的执行。

每个客户线程,属于一个线程排序服务组。父线程通过调用AvRtCreateThreadOrderingGroup创建一个或多个线程排序组。父线程使用这个函数指定线程排序服务的时间段,以及一个超时间隔。

其他的客户线程调用 AvRtJoinThreadOrderingGroup 函数来加入一个已经存在的线程排序组。这些线程指示它们是否是执行顺序中父线程的前任或后继。每个客户线程都希望每个时段完成一定数量的处理。组中的每个线程应该在时间段+超时间隔内完成它们的执行。

线程排序组中的线程,将其处理代码放到一个被 AvRtWaitOnThreadOrderingGroup 函数控制的循环中。

首先,前任线程,以它们被添加到组中的顺序每次执行一次,当父线程和后置线程在调用AvRtWaitOnThreadOrderingGroup 时被阻塞的时候。

        当每个前置线程都完成了它的执行,控制执行返回到它的处理循环的顶部,线程继续执行AvRtWaitOnThreadOrderingGroup 以阻塞,直到它的下一次运行。

在所有的前置线程已经调用了这个函数,线程排序服务可以调度父线程

        最后,当父线程完成了它的执行,并再次调用AvRtWaitOnThreadOrderingGroup,

线程排序服务可以按照线程加入到组的顺序,调度每个后置线程

如果所有的线程在一个时间段结束前完成了它们的执行,所有的线程在下此执行前等待,直到剩余的时间消耗完。

当客户不再需要以线程排序组中的一部分执行,调用AvRtLeaveThreadOrderingGroup 函数来将其移除。父线程不应该执行这个移除操作。如果一个线程未在时间段+超时间隔完成执行,它将被移除group。

父线程调用AvRtDeleteThreadOrderingGroup 函数来删除线程排序组。如果父线程未在时间段+超时间隔完成执行,线程排序组也将被删除。当线程排序组被销毁,这个组中的所有的线程对于AvRtWaitOnThreadOrderingGroup 的调用将失败或超时。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值