Faiss使用多线程出现的性能问题

faiss在增加CPU的情况下,反而出现效率低下的问题。

从理论上看,作为一个CPU/GPU计算型的应用,更多的核意味着更大的计算吞吐能力,性能只会越来越好才是。

在实际过程中,通过taskset命令分配更多的核给faiss只会带来更长响应时间以及更大的响应时间偏差(variation)。

faiss的主要流程:建库(train)、校验(sanity check)、搜索。

由于建库是一次性操作,就不考虑建库带来的影响。对校验分析,也没有发现需要耗时太多的时间,那么主要问题就在搜索上面。

对于”核心越多,性能越差”的奇怪表现,搜索阶段又分两个部分,一个是quantizer,一个是search_preassigned。考虑应该跟线程的计算有关,于是将nprobe值和batch设置强置为1,从算法上保证search_preassigned只能用单核单线程。结果发现多核cpu依然满载。

那么直接用perf top命令查看系统调用栈。发现在多核、单线程的模式下占比最高的居然是libgomp,而真正的benchmark(6-IVFPQ)只占了很少的CPU资源。

这就是核心的问题了:

  1. Faiss的多核心是通过openMP实现的。
  2. 默认OMP_NUM_THREADS等于所有可用的CPU数,即OpenMP默认将会在启动与核心数相同的线程数作为线程池。
  3. 默认情况下,openmp假定所有的调用都是计算密集型的。为了减少线程启动/唤醒过程需要上下文开销,系统必须时刻保证每一个线程都是alive状态。换句话说,要让线程活着,OpenMP会让线程池的每个线程做大量的无意义计算占据时间片而不是wait挂起。
  4. quantizer 的过程中系统启动了omp线程池,理论上在修改后的search_preassigned开始后,线程池已经没有任何意义。但在放任不管的情况下,系统的每个核心的CPU使用率都会被空白计算占据,理论上100%。主线程结束之前线程池不会自己销毁。
  5. 这个时候如果位于主线程上的search_preassigned函数需要执行,那就不得不与OMP线程池抢占CPU time。这就是核心越多性能越差的原因。而放大这个影响的原因是我们的测试程序经过了变态级别的优化之后导致OMP的线程维护开销远远大于任务的CPU开销(微秒级响应,少于0.1个最小上下文)。这个测试事实上成为了某种程度“系统调度时延”测量。这个结果恰恰反应了预期。

剩下的就是解这个问题了,那只要在合适的时候让线程池销毁所有线程就迎刃而解了。OpenMP的实现是基于编译器的,发现没有办法可以直接实现目的,只有两个对应的环境变量可以缓解:

  • GOMP_SPINCOUNT= omp线程经过了n个spin lock之后便被挂起。自然,n值越小就越早的挂起线程。
  • OMP_WAIT_POLICY=PASSIVE 通过使用wait方法挂起 omp线程。对应的ACTIVE 意味着线程池中的线程始终处于活动状态——消耗大量的CPU。

看上去效果还是不错的。

PS:并没有对所有情况进行测试,现在的结果指向是由于faiss依赖的openblat库中额外的omp线程池出现了问题导致主线程性能受到影响。理论上多线程也会如此,只是概率上导致看上去性能不是线性下降。

然后OMP_WAIT_POLICY的问题,主要是对在openmp下使用OpenBLAS的BLAS实现的时候起作用,此外,如果用了MKL库,一定条件下的MKL同样也会触发。

然后在faiss建立索引(train),也可能会出现这种情况,使用最新的faiss1.6.5及以后建立索引,CPU占用率明显有下降。

参考:http://www.litrin.net/2020/03/26/faiss的多线程效率问题/

https://www.cnblogs.com/yhzhou/p/10568728.html

https://www.cnblogs.com/yangyangcv/archive/2012/03/23/2413335.html

Faiss使用多线程出现的性能问题的更多相关文章

  1. [.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(三) 利用多线程提高程序性能(下)

    [.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(二) 利用多线程提高程序性能(下) 本节导读: 上节说了线程同步中使用线程锁和线程通知的方式来处理资源共享问题,这 ...

  2. [.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 利用多线程提高程序性能(中)

    [.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 利用多线程提高程序性能(中) 本节要点: 上节介绍了多线程的基本使用方法和基本应用示例,本节深入介绍.NET ...

  3. [.net 面向对象程序设计进阶] (16) 多线程(Multithreading)(一) 利用多线程提高程序性能(上)

    [.net 面向对象程序设计进阶] (16) 多线程(Multithreading)(一) 利用多线程提高程序性能(上) 本节导读: 随着硬件和网络的高速发展,为多线程(Multithreading) ...

  4. DirectX* 11 多线程渲染的性能、方法和实践

    对于在 CPU 上运行的 PC 游戏,渲染通常是主要的性能瓶颈:多线程渲染是一种消除瓶颈的有效方法.本文研究了 DirectX* 11 多线程渲染的性能可扩展性,讨论了多线程渲染的两种基本方法,并介绍 ...

  5. DELPHI用const来提高应用程序在多核多线程下的性能

    来自:http://bbs.csdn.net/topics/330048800 --------------------------------------------------------- 我们 ...

  6. 【原创】python多线程测试接口性能

    除了使用性能测试工具进行性能测试,我们也可以直接用python多线程进行性能测试. 下面,使用这几个模块,对一个查询接口做性能测试: requests:发送http请求 json:返回的字符串转换成j ...

  7. 【Bugly干货】Android性能优化典范之多线程篇

    本文涉及的内容有:多线程并发的性能问题,介绍了 AsyncTask,HandlerThread,IntentService 与 ThreadPool 分别适合的使用场景以及各自的使用注意事项,这是一篇 ...

  8. [转载] Python的GIL是什么鬼,多线程性能究竟如何

    原文: http://cenalulu.github.io/python/gil-in-python/ GIL是什么 首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器( ...

  9. python GIL 全局锁,多核cpu下的多线程性能究竟如何?

    python GIL 全局锁,多核cpu下的多线程性能究竟如何?GIL全称Global Interpreter Lock GIL是什么? 首先需要明确的一点是GIL并不是Python的特性,它是在实现 ...

随机推荐

  1. 微信小程序云开发-云存储的应用-识别银行卡

    一.准备工作 1.创建云函数identify.自定义action=="2"的时候识别银行卡信息. 2.云函数identify中index.js代码 1 const cloud = ...

  2. PAT乙级:1087 有多少不同的值 (20分)

    PAT乙级:1087 有多少不同的值 (20分) 当自然数 n 依次取 1.2.3.--.N 时,算式 ⌊n/2⌋+⌊n/3⌋+⌊n/5⌋ 有多少个不同的值?(注:⌊x⌋ 为取整函数,表示不超过 x ...

  3. c#链接MySql数据库方法

    方法一: 打开visual studio,在项目->管理NuGet程序包->搜索"MySql.Data"并安装: 在程序部分,引入 using MySql.Data.M ...

  4. windows 查看端口号,关闭端口进程

    1.打开cmd,输入:netstat -ano | findstr 8080,根据端口号查找对应的PID.结果如下: 2.根据PID找进程名称,输入命令:tasklist | findstr 1789 ...

  5. Nginx反向代理访问内网服务器

    Nginx反向代理访问内网服务器 问题描述 ​ 公司给配的台式机太垃圾了,不能访问外部网络就算了,还没有maven私服.近期项目不光得使用maven还得使用内网中的数据库之类,台式机太卡只能用自己的笔 ...

  6. 浏览器WEB Browser 常识

    浏览器WEB Browser 浏览器发展史 浏览器诞生与发展 浏览器的诞生 早期浏览器 Netscape Internet Explorer 与浏览器战争 chrome的崛起 时代之泪 IE浏览器终成 ...

  7. docker上运行mysql服务器

    1.搜索MySQL镜像 $ docker search mysql INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED docker.io docker.i ...

  8. 几张图搞懂 NodeJS 的流

    假设我们现在要盖一座房子,我们买了一些砖块,厂家正在送货.现在我们有两个选择,一是等所有砖块都到了以后再开始动工:二是到一批砖块就开始动工,砖块到多少我们就用多少. 这两种方式哪种效率更高呢?显然是第 ...

  9. C++ //多态案例三 ---电脑组装

    1 //多态案例三 ---电脑组装 2 3 #include <iostream> 4 #include <string> 5 using namespace std; 6 7 ...

  10. java 注释,关键字和标识符

    注释 注释是为了防止当写代码的时间过久了之后,忘记了这行代码的意思或者是在一个大型的项目里面,不可能每一个模块的功能你都记得,所以需要一个注释来帮助记忆. 注释不会被执行 平时写代码一定要养成写注释的 ...