【问题标题】:Android background process affinity can't be modified through native codeAndroid后台进程亲和度无法通过原生代码修改
【发布时间】:2019-01-10 10:53:20
【问题描述】:

以下 Android 代码仅生成在同一 CPU 内核上运行的本机线程。 FaceEngineWrapper.Run() 是用于面部检测推理引擎的 JNI 包装器,并产生了很多本地线程(通过 OpenCV-dnn 中的 std::thread 和 openmp)。但这些原生线程最终运行在同一个 CPU 内核上,整个进程运行速度非常慢。

那么如何让原生线程利用所有 CPU 内核呢?

Observable.create(new ObservableOnSubscribe<Boolean>() {
    @Override
    public void subscribe(ObservableEmitter<Boolean> e) throws Exception {
        e.onNext(true);
        getFrameBitmap();
        e.onComplete();
    }
}).subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Consumer<Boolean>() {
        @Override
        public void accept(Boolean aBoolean) throws Exception {
        new Thread(new Runnable() {
            @Override
            public void run() {
                mFaceEngineWrapper.Run(); 
            }
        }).start();
      }
});

附:此应用程序在 Android RK3399 板上测试,2/4 大/小核心。具有 jni 共享库的应用程序消耗 16-17% 的 cpu,具有相同代码和 root 权限的独立可执行二进制文件消耗 34-35% 的 cpu。如果我启用了一些额外的功能,二进制的 cpu 使用率会达到大约 60%,而这个应用程序仍然以 17% 的 cpu 运行,而整个删除过程会变得慢得多。所以我猜这个应用程序的cpu使用率受到了某种限制。

附言问题是关于 cpu 亲和力。我在这个 6 核 CPU 上获得了 CPU 设置掩码 000001。但是sched_setaffinity 到 111111 没有任何改变,也没有返回错误。我真的很想知道为什么在这里隐式设置 CPU 亲和性以及我可以做些什么来禁用它。

SetCpuAffinity({0,1}) 是在工作线程中调用的 C++ 代码(由std::threadRun 创建)。 sched_setaffinity 返回 0。但 sched_getaffinity 之后显示 000001。我不能使用 pthread 来做,因为 Android 的 pthread 库不提供亲和功能。

void SetCpuAffinity(const std::vector<int32_t>& cpuids) {
  int32_t nproc = sysconf(_SC_NPROCESSORS_ONLN);
  cpu_set_t cpu_set;
  CPU_ZERO(&cpu_set);
  for (auto&& cpuid: cpuids) {
    if (cpuid >= nproc || cpuid < 0) {
      LOG_ERROR("cannot set affinity cpu id to " << cpuid << " total cpu " << nproc);
    }
    CPU_SET(cpuid, &cpu_set);
  }
  int32_t res = sched_setaffinity(gettid(), sizeof(cpu_set_t), &cpu_set);
  LOG_INFO("try to set thread cpu affinity, res "<< res << ", errno " << errno);
  TestThreadAffinity();
  TestThreadCpu();
}

【问题讨论】:

  • 您是否有理由需要new Thread 而不是使用线程池?
  • availableProcessors() 返回什么数字?完全取决于 Android 告诉你的东西比你实际拥有的要少,而且你不能只用 Java 代码做任何事情。
  • 你怎么知道所有这些线程都在同一个内核上运行?
  • @KarolDowbecki C++ 代码将管理自己的线程。 Java 中的线程似乎无关紧要。
  • @PavelZdenek 我正在使用 2/4 大/小核心臂设备。工作线程由 c++ std::thread 创建。 Java 代码在 c++ 中基本上充当main

标签: java android multithreading java-native-interface affinity


【解决方案1】:

我终于想通了。对于 Android 后台服务,其亲和性仅限于一个 CPU 内核。您无法通过sched_setaffinity 或事件tasket -p 3f PID root 命令更改它,因为PID 在/dev/cpuset/background/tasks 列表中。

echo PID &gt; /dev/cpuset/foreground/tasksecho PID &gt; /dev/cpuset/top-app/tasks之后,可以通过taskset -p mask PID设置PID的亲和性。

但是我的服务的运行速度仍然很慢,也许它的线程亲和性没有立即改变(?)。而且我不确定默认的亲和行为是否可以通过代码(Java 或本机但没有 root)进行管理。如果有人能提供更详细的答案,我们将不胜感激。

【讨论】:

    猜你喜欢
    • 2011-05-26
    • 1970-01-01
    • 2016-03-26
    • 2012-11-07
    • 2010-10-11
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    相关资源
    最近更新 更多