Сходство фонового процесса Android нельзя изменить с помощью собственного кода - PullRequest
0 голосов
/ 10 января 2019

Следующий фрагмент кода Android создает только собственные потоки, работающие на том же ядре ЦП. FaceEngineWrapper.Run() - это JNI-оболочка для механизма определения лиц, которая порождает довольно много собственных потоков (через std :: thread и openmp в OpenCV-dnn). Но эти собственные потоки в конечном итоге работают на одном и том же ядре процессора, и весь процесс работает очень медленно.

Итак, как заставить собственные потоки использовать все ядра процессора?

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();
      }
});

P.S. Это приложение протестировано на плате Android RK3399, 2/4 большой / литр ядро. Приложение с jni shared lib потребляет 16-17% ЦП, а автономный исполняемый бинарный файл с тем же кодом и привилегиями root потребляет 34-35% ЦП. Если я включу некоторые дополнительные функции, загрузка процессора возрастет до 60% для двоичного файла, и это приложение по-прежнему будет работать с 17% процессором, в то время как весь сложный процесс становится намного медленнее. Так что я думаю, что использование этого приложения каким-то образом ограничено.

P.P.S. Проблема в сродстве с процессором. Я получил маску установленного CPU 000001 на этом 6-ядерном процессоре. Но по sched_setaffinity до 111111 ничего не изменилось и ошибки не было возвращено. Мне действительно интересно, почему привязка к процессору неявно установлена ​​здесь и что я могу сделать, чтобы отключить ее.

SetCpuAffinity({0,1}) - это код C ++, вызываемый в рабочем потоке (созданный std::thread в Run). sched_setaffinity возвращает 0. Но sched_getaffinity показывает 000001 впоследствии. Я не могу использовать pthread для этого, потому что в Android pthread lib нет функции привязки.

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();
}

1 Ответ

0 голосов
/ 15 января 2019

Наконец я понял это. Для фонового сервиса Android его привязанность ограничена одним ядром процессора. Вы не можете изменить его с помощью команды sched_setaffinity или события tasket -p 3f PID root, поскольку PID находится в списке /dev/cpuset/background/tasks.

После echo PID > /dev/cpuset/foreground/tasks и echo PID > /dev/cpuset/top-app/tasks сродство ПИД-регулятора можно установить с помощью taskset -p mask PID.

Но скорость работы моего сервиса все еще довольно низкая, может быть, его сродство к потоку не изменяется мгновенно (?). И я не уверен, что поведением по умолчанию можно управлять с помощью кода (либо Java, либо нативного, но без рута). Очень ценю, если кто-нибудь даст более подробный ответ.

...