[{"id":31746,"web_url":"https://patchwork.libcamera.org/comment/31746/","msgid":"<20241015103328.GK5682@pendragon.ideasonboard.com>","date":"2024-10-15T10:33:28","subject":"Re: [PATCH v3 1/1] libcamera: add method to set thread affinity","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Harvey, Han-Lin,\n\nThank you for the patch.\n\nOn Mon, Oct 14, 2024 at 06:58:56AM +0000, Harvey Yang wrote:\n> From: Han-Lin Chen <hanlinchen@chromium.org>\n> \n> Add method to set thread affinity to Thread class.\n> \n> Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>\n> Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>\n> Signed-off-by: Harvey Yang <chenghaoyang@chromium.org>\n> ---\n>  include/libcamera/base/thread.h |  5 ++++\n>  src/libcamera/base/thread.cpp   | 52 +++++++++++++++++++++++++++++++++\n>  2 files changed, 57 insertions(+)\n> \n> diff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h\n> index 4f33de63d..58cae341b 100644\n> --- a/include/libcamera/base/thread.h\n> +++ b/include/libcamera/base/thread.h\n> @@ -15,6 +15,7 @@\n>  \n>  #include <libcamera/base/message.h>\n>  #include <libcamera/base/signal.h>\n> +#include <libcamera/base/span.h>\n>  #include <libcamera/base/utils.h>\n>  \n>  namespace libcamera {\n> @@ -35,6 +36,8 @@ public:\n>  \tvoid exit(int code = 0);\n>  \tbool wait(utils::duration duration = utils::duration::max());\n>  \n> +\tvoid setThreadAffinity(const Span<const unsigned int> &cpus);\n> +\n>  \tbool isRunning();\n>  \n>  \tSignal<> finished;\n> @@ -54,6 +57,8 @@ private:\n>  \tvoid startThread();\n>  \tvoid finishThread();\n>  \n> +\tvoid setThreadAffinityInternal();\n> +\n>  \tvoid postMessage(std::unique_ptr<Message> msg, Object *receiver);\n>  \tvoid removeMessages(Object *receiver);\n>  \n> diff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp\n> index 8735670b8..f40c7d8e7 100644\n> --- a/src/libcamera/base/thread.cpp\n> +++ b/src/libcamera/base/thread.cpp\n> @@ -9,6 +9,7 @@\n>  \n>  #include <atomic>\n>  #include <list>\n> +#include <optional>\n>  #include <sys/syscall.h>\n>  #include <sys/types.h>\n>  #include <unistd.h>\n> @@ -128,6 +129,8 @@ private:\n>  \tint exitCode_;\n>  \n>  \tMessageQueue messages_;\n> +\n> +\tstd::optional<cpu_set_t> cpuset_ = std::nullopt;\n>  };\n>  \n>  /**\n> @@ -254,6 +257,8 @@ void Thread::start()\n>  \tdata_->exit_.store(false, std::memory_order_relaxed);\n>  \n>  \tthread_ = std::thread(&Thread::startThread, this);\n> +\n> +\tsetThreadAffinityInternal();\n>  }\n>  \n>  void Thread::startThread()\n> @@ -410,6 +415,53 @@ bool Thread::wait(utils::duration duration)\n>  \treturn hasFinished;\n>  }\n>  \n> +/**\n> + * \\brief Set the CPU affinity mask of the thread\n> + * \\param[in] cpus The list of CPU indices that the thread is set affinity to\n> + *\n> + * The cpu indices should be within [0, std::thread::hardware_concurrency()),\n\ns/cpu/CPU/\n\n> + * and the total number should not exceed `CPU_SETSIZE`. Invalid indices and\n> + * extra indices will be ignored.\n> + */\n> +void Thread::setThreadAffinity(const Span<const unsigned int> &cpus)\n> +{\n> +\tconst unsigned int numCpus = std::thread::hardware_concurrency();\n> +\n> +\tMutexLocker locker(data_->mutex_);\n> +\tdata_->cpuset_ = cpu_set_t();\n> +\tCPU_ZERO(&data_->cpuset_.value());\n> +\n> +\tunsigned int count = 0;\n> +\tfor (const unsigned int &cpu : cpus) {\n> +\t\tif (count == CPU_SETSIZE) {\n> +\t\t\tLOG(Thread, Error) << \"cpus_ already contains \" << CPU_SETSIZE\n> +\t\t\t\t\t   << \" cpus. Ignoring the rest.\";\n> +\t\t\tbreak;\n> +\t\t}\n\nI don't think this check is needed anymore. You should adapt the\ndocumentation accordingly.\n\n> +\n> +\t\tif (cpu >= numCpus) {\n> +\t\t\tLOG(Thread, Error) << \"Ignore an invalid cpu index: \" << cpu;\n> +\t\t\tcontinue;\n\nWhy is it better to ignore the value instead of returning an error ?\n\n> +\t\t}\n> +\n> +\t\t++count;\n> +\t\tCPU_SET(cpu, &data_->cpuset_.value());\n> +\t}\n> +\n> +\tif (data_->running_)\n> +\t\tsetThreadAffinityInternal();\n> +}\n> +\n> +void Thread::setThreadAffinityInternal()\n> +{\n> +\tif (!data_->cpuset_)\n> +\t\treturn;\n> +\n> +\tauto handle = thread_.native_handle();\n> +\n> +\tpthread_setaffinity_np(handle, sizeof(cpu_set_t), &data_->cpuset_.value());\n\n\tconst cpu_set_t &cpuset_ = data_->cpuset_.value();\n\tpthread_setaffinity_np(thread_.native_handle(), sizeof(cpuset), &cpuset);\n\nand you can drop the handle variable.\n\n> +}\n> +\n>  /**\n>   * \\brief Check if the thread is running\n>   *","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id DAD8DC0F2A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 15 Oct 2024 10:33:34 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A139165381;\n\tTue, 15 Oct 2024 12:33:33 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id ADB8963525\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 15 Oct 2024 12:33:31 +0200 (CEST)","from pendragon.ideasonboard.com (unknown [185.143.39.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 29F099CE;\n\tTue, 15 Oct 2024 12:31:50 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"vczOJiGM\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1728988310;\n\tbh=GL9n1MXvcs6YrWAMhX3/xNC5aUrPkWrhLXZX4Vibc80=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=vczOJiGM3M686G/G4gT4xe1OBby1h66kf+A9sjBju58cY7fQASj2jssNLpKmmGOCJ\n\tGK0OBgI+vPAx3yK6yMh4osfP9776nqC2UK0pIPyoEyrapr6NnYF80P7+SyRTdezupi\n\tlXDh8CrcIudyhzdFqDu9EOGC9YBFbdTWWrVNzdaU=","Date":"Tue, 15 Oct 2024 13:33:28 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Harvey Yang <chenghaoyang@chromium.org>","Cc":"libcamera-devel@lists.libcamera.org,\n\tHan-Lin Chen <hanlinchen@chromium.org>","Subject":"Re: [PATCH v3 1/1] libcamera: add method to set thread affinity","Message-ID":"<20241015103328.GK5682@pendragon.ideasonboard.com>","References":"<20241014070000.658023-1-chenghaoyang@chromium.org>\n\t<20241014070000.658023-2-chenghaoyang@chromium.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20241014070000.658023-2-chenghaoyang@chromium.org>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":31755,"web_url":"https://patchwork.libcamera.org/comment/31755/","msgid":"<CAEB1ahs9ugkyF59n7zcL3VDEa98AxXZqdAH_VRK=ZvhbTN8qPw@mail.gmail.com>","date":"2024-10-16T08:45:41","subject":"Re: [PATCH v3 1/1] libcamera: add method to set thread affinity","submitter":{"id":117,"url":"https://patchwork.libcamera.org/api/people/117/","name":"Cheng-Hao Yang","email":"chenghaoyang@chromium.org"},"content":"Hi Laurent,\n\nOn Tue, Oct 15, 2024 at 6:33 PM Laurent Pinchart\n<laurent.pinchart@ideasonboard.com> wrote:\n>\n> Hi Harvey, Han-Lin,\n>\n> Thank you for the patch.\n>\n> On Mon, Oct 14, 2024 at 06:58:56AM +0000, Harvey Yang wrote:\n> > From: Han-Lin Chen <hanlinchen@chromium.org>\n> >\n> > Add method to set thread affinity to Thread class.\n> >\n> > Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>\n> > Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>\n> > Signed-off-by: Harvey Yang <chenghaoyang@chromium.org>\n> > ---\n> >  include/libcamera/base/thread.h |  5 ++++\n> >  src/libcamera/base/thread.cpp   | 52 +++++++++++++++++++++++++++++++++\n> >  2 files changed, 57 insertions(+)\n> >\n> > diff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h\n> > index 4f33de63d..58cae341b 100644\n> > --- a/include/libcamera/base/thread.h\n> > +++ b/include/libcamera/base/thread.h\n> > @@ -15,6 +15,7 @@\n> >\n> >  #include <libcamera/base/message.h>\n> >  #include <libcamera/base/signal.h>\n> > +#include <libcamera/base/span.h>\n> >  #include <libcamera/base/utils.h>\n> >\n> >  namespace libcamera {\n> > @@ -35,6 +36,8 @@ public:\n> >       void exit(int code = 0);\n> >       bool wait(utils::duration duration = utils::duration::max());\n> >\n> > +     void setThreadAffinity(const Span<const unsigned int> &cpus);\n> > +\n> >       bool isRunning();\n> >\n> >       Signal<> finished;\n> > @@ -54,6 +57,8 @@ private:\n> >       void startThread();\n> >       void finishThread();\n> >\n> > +     void setThreadAffinityInternal();\n> > +\n> >       void postMessage(std::unique_ptr<Message> msg, Object *receiver);\n> >       void removeMessages(Object *receiver);\n> >\n> > diff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp\n> > index 8735670b8..f40c7d8e7 100644\n> > --- a/src/libcamera/base/thread.cpp\n> > +++ b/src/libcamera/base/thread.cpp\n> > @@ -9,6 +9,7 @@\n> >\n> >  #include <atomic>\n> >  #include <list>\n> > +#include <optional>\n> >  #include <sys/syscall.h>\n> >  #include <sys/types.h>\n> >  #include <unistd.h>\n> > @@ -128,6 +129,8 @@ private:\n> >       int exitCode_;\n> >\n> >       MessageQueue messages_;\n> > +\n> > +     std::optional<cpu_set_t> cpuset_ = std::nullopt;\n> >  };\n> >\n> >  /**\n> > @@ -254,6 +257,8 @@ void Thread::start()\n> >       data_->exit_.store(false, std::memory_order_relaxed);\n> >\n> >       thread_ = std::thread(&Thread::startThread, this);\n> > +\n> > +     setThreadAffinityInternal();\n> >  }\n> >\n> >  void Thread::startThread()\n> > @@ -410,6 +415,53 @@ bool Thread::wait(utils::duration duration)\n> >       return hasFinished;\n> >  }\n> >\n> > +/**\n> > + * \\brief Set the CPU affinity mask of the thread\n> > + * \\param[in] cpus The list of CPU indices that the thread is set affinity to\n> > + *\n> > + * The cpu indices should be within [0, std::thread::hardware_concurrency()),\n>\n> s/cpu/CPU/\n\nDone\n\n>\n> > + * and the total number should not exceed `CPU_SETSIZE`. Invalid indices and\n> > + * extra indices will be ignored.\n> > + */\n> > +void Thread::setThreadAffinity(const Span<const unsigned int> &cpus)\n> > +{\n> > +     const unsigned int numCpus = std::thread::hardware_concurrency();\n> > +\n> > +     MutexLocker locker(data_->mutex_);\n> > +     data_->cpuset_ = cpu_set_t();\n> > +     CPU_ZERO(&data_->cpuset_.value());\n> > +\n> > +     unsigned int count = 0;\n> > +     for (const unsigned int &cpu : cpus) {\n> > +             if (count == CPU_SETSIZE) {\n> > +                     LOG(Thread, Error) << \"cpus_ already contains \" << CPU_SETSIZE\n> > +                                        << \" cpus. Ignoring the rest.\";\n> > +                     break;\n> > +             }\n>\n> I don't think this check is needed anymore. You should adapt the\n> documentation accordingly.\n\nDone\n\n>\n> > +\n> > +             if (cpu >= numCpus) {\n> > +                     LOG(Thread, Error) << \"Ignore an invalid cpu index: \" << cpu;\n> > +                     continue;\n>\n> Why is it better to ignore the value instead of returning an error ?\n\nYeah that's also an option. Updated.\n\n>\n> > +             }\n> > +\n> > +             ++count;\n> > +             CPU_SET(cpu, &data_->cpuset_.value());\n> > +     }\n> > +\n> > +     if (data_->running_)\n> > +             setThreadAffinityInternal();\n> > +}\n> > +\n> > +void Thread::setThreadAffinityInternal()\n> > +{\n> > +     if (!data_->cpuset_)\n> > +             return;\n> > +\n> > +     auto handle = thread_.native_handle();\n> > +\n> > +     pthread_setaffinity_np(handle, sizeof(cpu_set_t), &data_->cpuset_.value());\n>\n>         const cpu_set_t &cpuset_ = data_->cpuset_.value();\n>         pthread_setaffinity_np(thread_.native_handle(), sizeof(cpuset), &cpuset);\n>\n> and you can drop the handle variable.\n\nDone\n\nBR,\nHarvey\n\n\n\n>\n> > +}\n> > +\n> >  /**\n> >   * \\brief Check if the thread is running\n> >   *\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D6852C32FA\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 16 Oct 2024 08:45:55 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 92A1A65382;\n\tWed, 16 Oct 2024 10:45:55 +0200 (CEST)","from mail-lj1-x234.google.com (mail-lj1-x234.google.com\n\t[IPv6:2a00:1450:4864:20::234])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 809FA6053E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 16 Oct 2024 10:45:53 +0200 (CEST)","by mail-lj1-x234.google.com with SMTP id\n\t38308e7fff4ca-2fb5014e2daso31419301fa.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 16 Oct 2024 01:45:53 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=chromium.org header.i=@chromium.org\n\theader.b=\"iAjFAdE1\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=chromium.org; s=google; t=1729068353; x=1729673153;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=kD13gsDED6GvnmqZwXQzicVD8tEDmSNX6aEp4TUXT4I=;\n\tb=iAjFAdE1b2HWuiZOuvK0KBO4PZJdlRaVyUk4nZxjPYwar/JQS3PJVGeEJRT8/dHY6h\n\tSJ9AEJJdMcrO3B+FLQXjlN/z7Mc3XKCz8OCnJYTkAtPeMRp88jA863QvaHEJ3s9BTh+r\n\tRJXUOYRo/y02v390KsPmEg+VlhzKFwxKvD4Ls=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1729068353; x=1729673153;\n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=kD13gsDED6GvnmqZwXQzicVD8tEDmSNX6aEp4TUXT4I=;\n\tb=wHfss+0aYZU+h5Q88m0lG/VM9jRa2eFvdn2+HFVmyhqNQKUfiM4zcqm1GofJ3k8mQh\n\tttn2B9sEH7IYyMStvGyni+dm5RUBZ4JDqF7NqjlqaHWdlFKnD46Dd2rlmROUN+bGzuHP\n\tkku355GPnojhycnikF0T/Rky5KcrKQGGOjM610W8Rsg9LDH9fBXAJ1e59Cbv/ECDA63s\n\tRUzGQCnjH8yV3a8fwJCOp9Y3KWpKefR/vfLWeAOtCq5+N+x7Wrh4XG1WwP4XeCbPr5PQ\n\t0fImvSOwj98wplfULm24pHt0rfNY3MYPiETDI56xvFCO0w+h/JOmLkBf4tCWILVXXBWB\n\txhng==","X-Gm-Message-State":"AOJu0YwO74RVNUaNpelJ+tkzLdf4gMK4zVF2MsNDGVHUr53ryNWFZTaX\n\tZ+tzNoBdrIhlT5zPM7fhJZiF6dYvogGnDvrgCTVh3SoCbmx1lRucPu08BBuwIv7ywELCpZWdYjQ\n\tD9ikj4dzI6ZNsb+76h8k0QFb/9m8o3d6nS1lK","X-Google-Smtp-Source":"AGHT+IFRcR3MeB0K7H5yf+GvZY/gPU4suPfJHJ7vkZlVoTgddOB/h6AnYPppewMDlrMQzYMCYiMnO9iLHs9X+XspEhk=","X-Received":"by 2002:a05:651c:504:b0:2fb:6057:e67e with SMTP id\n\t38308e7fff4ca-2fb6057ed34mr23994071fa.32.1729068352556;\n\tWed, 16 Oct 2024 01:45:52 -0700 (PDT)","MIME-Version":"1.0","References":"<20241014070000.658023-1-chenghaoyang@chromium.org>\n\t<20241014070000.658023-2-chenghaoyang@chromium.org>\n\t<20241015103328.GK5682@pendragon.ideasonboard.com>","In-Reply-To":"<20241015103328.GK5682@pendragon.ideasonboard.com>","From":"Cheng-Hao Yang <chenghaoyang@chromium.org>","Date":"Wed, 16 Oct 2024 16:45:41 +0800","Message-ID":"<CAEB1ahs9ugkyF59n7zcL3VDEa98AxXZqdAH_VRK=ZvhbTN8qPw@mail.gmail.com>","Subject":"Re: [PATCH v3 1/1] libcamera: add method to set thread affinity","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tHan-Lin Chen <hanlinchen@chromium.org>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]