[{"id":31915,"web_url":"https://patchwork.libcamera.org/comment/31915/","msgid":"<172981733294.3353069.12626022977390973101@ping.linuxembedded.co.uk>","date":"2024-10-25T00:48:52","subject":"Re: [PATCH v6 1/1] libcamera: add method to set thread affinity","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Harvey Yang (2024-10-24 09:13:53)\n> From: Han-Lin Chen <hanlinchen@chromium.org>\n> \n> Add method to set thread affinity to Thread class.\n\nAs it stands, this is still adding unused code.\n\nCan't we get 'something' into test/threads.cpp so that at least we know\nthe code is both compiled and /run/ by the CI runs ?\n\nPerhaps even as simple as setting the threadAffinity to CPU 0 and making\nsure that's the CPU the thread is on!?\n\n\n#include <sched.h>  // For sched_getcpu()\nint cpu = sched_getcpu();\n\nAnd make sure 'cpu' is the value we expect ?\n\nIt could launch a thread on 'each' CPU for instance? Or even just only\nvalidate it gets tied to CPU 0 ?\n\nAre any specific permissions required to be able to use\nThread::setThreadAffinity()?\n\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   | 47 +++++++++++++++++++++++++++++++++\n>  2 files changed, 52 insertions(+)\n> \n> diff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h\n> index 4f33de63d..3209d4f7c 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> +       int 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..f6322fe31 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_;\n>  };\n>  \n>  /**\n> @@ -281,6 +284,8 @@ void Thread::startThread()\n>         data_->tid_ = syscall(SYS_gettid);\n>         currentThreadData = data_;\n>  \n> +       setThreadAffinityInternal();\n> +\n>         run();\n>  }\n>  \n> @@ -410,6 +415,48 @@ 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> + * If any index is invalid, this function won't modify the thread affinity and\n> + * will return an error.\n> + *\n> + * \\return 0 if all indices are valid, -EINVAL otherwise\n> + */\n> +int 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> +       for (const unsigned int &cpu : cpus) {\n> +               if (cpu >= numCpus) {\n> +                       LOG(Thread, Error) << \"Invalid CPU \" << cpu << \"for thread affinity\";\n> +                       return -EINVAL;\n> +               }\n> +\n> +               CPU_SET(cpu, &data_->cpuset_.value());\n> +       }\n> +\n> +       if (data_->running_)\n> +               setThreadAffinityInternal();\n> +\n> +       return 0;\n> +}\n> +\n> +void Thread::setThreadAffinityInternal()\n> +{\n> +       if (!data_->cpuset_)\n> +               return;\n> +\n> +       const cpu_set_t &cpuset = data_->cpuset_.value();\n> +       pthread_setaffinity_np(thread_.native_handle(), sizeof(cpuset), &cpuset);\n> +}\n> +\n>  /**\n>   * \\brief Check if the thread is running\n>   *\n> -- \n> 2.47.0.163.g1226f6d8fa-goog\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 9B325C3220\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 25 Oct 2024 00:48:59 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8E67065393;\n\tFri, 25 Oct 2024 02:48:58 +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 3CA3360366\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 25 Oct 2024 02:48:56 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C47008D4;\n\tFri, 25 Oct 2024 02:47:07 +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=\"MJgRszNP\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1729817227;\n\tbh=L6uoDKrlV5ZD7zMmEdgWPoATAnv+f8PJBIFWOcSvCNI=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=MJgRszNPP8RYB8zi4iiNGAPizDV6/Phrt/XENEa+0zh+TlVJnByZx+FKISWgScFTi\n\trqX924UVANxBhRgUOR0OuRqbssR4gbLFsJnMtcy5Pql00801h0D2YOfB11mlTKjwzE\n\t/BccFS20V0zR8/n4nmt9JJVT5yluuCcIUJMa6NIA=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20241024081520.2912819-2-chenghaoyang@chromium.org>","References":"<20241024081520.2912819-1-chenghaoyang@chromium.org>\n\t<20241024081520.2912819-2-chenghaoyang@chromium.org>","Subject":"Re: [PATCH v6 1/1] libcamera: add method to set thread affinity","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Han-Lin Chen <hanlinchen@chromium.org>,\n\tHarvey Yang <chenghaoyang@chromium.org>","To":"Harvey Yang <chenghaoyang@chromium.org>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Fri, 25 Oct 2024 01:48:52 +0100","Message-ID":"<172981733294.3353069.12626022977390973101@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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":31952,"web_url":"https://patchwork.libcamera.org/comment/31952/","msgid":"<CAEB1ahs24Q9D5Jc6MYGmBZoK1VRKKTTZAD4yvZ-HamcQqCABOQ@mail.gmail.com>","date":"2024-10-29T08:58:50","subject":"Re: [PATCH v6 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 Kieran,\n\nOn Fri, Oct 25, 2024 at 8:48 AM Kieran Bingham\n<kieran.bingham@ideasonboard.com> wrote:\n>\n> Quoting Harvey Yang (2024-10-24 09:13:53)\n> > From: Han-Lin Chen <hanlinchen@chromium.org>\n> >\n> > Add method to set thread affinity to Thread class.\n>\n> As it stands, this is still adding unused code.\n>\n> Can't we get 'something' into test/threads.cpp so that at least we know\n> the code is both compiled and /run/ by the CI runs ?\n>\n> Perhaps even as simple as setting the threadAffinity to CPU 0 and making\n> sure that's the CPU the thread is on!?\n>\n>\n> #include <sched.h>  // For sched_getcpu()\n> int cpu = sched_getcpu();\n>\n> And make sure 'cpu' is the value we expect ?\n>\n> It could launch a thread on 'each' CPU for instance? Or even just only\n> validate it gets tied to CPU 0 ?\n\nAdded unit tests to set affinity to every available cpu core.\nI'm not sure how to run a function on a thread elegantly, so I ended up\ndeclaring a class derived from Object. Please let me know how to make\nit cleaner.\n\n>\n> Are any specific permissions required to be able to use\n> Thread::setThreadAffinity()?\n\nIIUC, a user can call pthread_setaffinity_np on a thread that it owns.\nThe syscall under the hood is sched_setaffinity, which is already included\nin CrOS' allowed syscalls.\nShould I add this info in the commit message?\n\nBR,\nHarvey\n\n\n\n\n>\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   | 47 +++++++++++++++++++++++++++++++++\n> >  2 files changed, 52 insertions(+)\n> >\n> > diff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h\n> > index 4f33de63d..3209d4f7c 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> > +       int 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..f6322fe31 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_;\n> >  };\n> >\n> >  /**\n> > @@ -281,6 +284,8 @@ void Thread::startThread()\n> >         data_->tid_ = syscall(SYS_gettid);\n> >         currentThreadData = data_;\n> >\n> > +       setThreadAffinityInternal();\n> > +\n> >         run();\n> >  }\n> >\n> > @@ -410,6 +415,48 @@ 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> > + * If any index is invalid, this function won't modify the thread affinity and\n> > + * will return an error.\n> > + *\n> > + * \\return 0 if all indices are valid, -EINVAL otherwise\n> > + */\n> > +int 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> > +       for (const unsigned int &cpu : cpus) {\n> > +               if (cpu >= numCpus) {\n> > +                       LOG(Thread, Error) << \"Invalid CPU \" << cpu << \"for thread affinity\";\n> > +                       return -EINVAL;\n> > +               }\n> > +\n> > +               CPU_SET(cpu, &data_->cpuset_.value());\n> > +       }\n> > +\n> > +       if (data_->running_)\n> > +               setThreadAffinityInternal();\n> > +\n> > +       return 0;\n> > +}\n> > +\n> > +void Thread::setThreadAffinityInternal()\n> > +{\n> > +       if (!data_->cpuset_)\n> > +               return;\n> > +\n> > +       const cpu_set_t &cpuset = data_->cpuset_.value();\n> > +       pthread_setaffinity_np(thread_.native_handle(), sizeof(cpuset), &cpuset);\n> > +}\n> > +\n> >  /**\n> >   * \\brief Check if the thread is running\n> >   *\n> > --\n> > 2.47.0.163.g1226f6d8fa-goog\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 E4B92C3220\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 29 Oct 2024 08:59:04 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 92D0A653AA;\n\tTue, 29 Oct 2024 09:59:04 +0100 (CET)","from mail-lj1-x22c.google.com (mail-lj1-x22c.google.com\n\t[IPv6:2a00:1450:4864:20::22c])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0BFD865399\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Oct 2024 09:59:03 +0100 (CET)","by mail-lj1-x22c.google.com with SMTP id\n\t38308e7fff4ca-2fb5111747cso47200531fa.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Oct 2024 01:59:03 -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=\"XA1We4i9\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=chromium.org; s=google; t=1730192342; x=1730797142;\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=jZO/psls+W+UjZysCamQ3QfYpy5YaTrPUHs77xr0+yI=;\n\tb=XA1We4i9Ejf/EUjUtw6ddLwn3oU7VBOSlikMV/Z4ACQvDZ0l6j6wtH8+AsgmCU+ubn\n\tXU/e9HTr5O5QPIBnTthxD2CWIBl5br08xIuzb7mTvCgEQVADLxko6bv/AgaRdcqDm9tH\n\tmb4aminto825gucPaopnL5jhxcyvvQQhzX5UQ=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1730192342; x=1730797142;\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=jZO/psls+W+UjZysCamQ3QfYpy5YaTrPUHs77xr0+yI=;\n\tb=unL88Y2zStls2EjooBg1pY4inWu9Rotl/HCJWuNfTTY27PM+YABQMd4Mn9WbTf27Qp\n\tsiA83OLyWq69CkWDVO39naxl+MERM1WI22a/rARhnzU/C8xbPI1LOh6XPiOdkQuDKrAn\n\tCVcvO9/Slfp8agxhl6Kr++95uQA+Yz0wW5NjLG5TOZ7f9XgRQvdsA3OD/xttFafJSp9u\n\t9V+FhgWv2OI+/3RfNo5OBXe6b+4N3zIE+tCCnF5q0MwcHEY+SHsHxsnS/EfPciUHGEFf\n\twtswhSPmVTFsQzjOSa/eUt6sQAHjiOmTTcE7Oz4RoQKGzPWeAmlLIeam2RVCVgz5vhzU\n\tNA0Q==","X-Gm-Message-State":"AOJu0YwsVXloXkAB8allREwyFsIb6+5lmgPkH5Y9cNJeWSHGCwZvUY4E\n\tAeSH8jL1GXzq8/dsTn92xtIs9wPHg6rVAxQxbZK2bjt8Z9fITHP3lB+Xen6RGm/wfuVAPPSDzbp\n\tvJnlAsTG8QM0gXpFvwOXd5qqxH7UiWBk0uNk3OlTJY5qeeVU=","X-Google-Smtp-Source":"AGHT+IGYo4nLnm6u2FUX3F5FMkG61JXs68fQ1wBGC5m7nNBAMQgae4Qft40bvkgrwiWgMir0IbvjMT8dXKIV/ybd4wo=","X-Received":"by 2002:a2e:b8c2:0:b0:2fb:5bd1:c288 with SMTP id\n\t38308e7fff4ca-2fcbe09fc14mr51931971fa.43.1730192342210;\n\tTue, 29 Oct 2024 01:59:02 -0700 (PDT)","MIME-Version":"1.0","References":"<20241024081520.2912819-1-chenghaoyang@chromium.org>\n\t<20241024081520.2912819-2-chenghaoyang@chromium.org>\n\t<172981733294.3353069.12626022977390973101@ping.linuxembedded.co.uk>","In-Reply-To":"<172981733294.3353069.12626022977390973101@ping.linuxembedded.co.uk>","From":"Cheng-Hao Yang <chenghaoyang@chromium.org>","Date":"Tue, 29 Oct 2024 16:58:50 +0800","Message-ID":"<CAEB1ahs24Q9D5Jc6MYGmBZoK1VRKKTTZAD4yvZ-HamcQqCABOQ@mail.gmail.com>","Subject":"Re: [PATCH v6 1/1] libcamera: add method to set thread affinity","To":"Kieran Bingham <kieran.bingham@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>"}}]