From patchwork Tue Jan 17 16:28:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergei Trofimov X-Patchwork-Id: 91695 Delivered-To: patch@linaro.org Received: by 10.182.3.34 with SMTP id 2csp523725obz; Tue, 17 Jan 2017 08:33:07 -0800 (PST) X-Received: by 10.36.245.5 with SMTP id k5mr22047764ith.100.1484670787792; Tue, 17 Jan 2017 08:33:07 -0800 (PST) Return-Path: Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id l10si12782141itd.116.2017.01.17.08.33.07; Tue, 17 Jan 2017 08:33:07 -0800 (PST) Received-SPF: pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Authentication-Results: mx.google.com; spf=pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) smtp.mailfrom=lng-odp-bounces@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 4B43760954; Tue, 17 Jan 2017 16:33:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, URIBL_BLOCKED autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id D861D60EE1; Tue, 17 Jan 2017 16:29:22 +0000 (UTC) X-Original-To: lng-odp@lists.linaro.org Delivered-To: lng-odp@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id AFFA360641; Tue, 17 Jan 2017 16:28:58 +0000 (UTC) Received: from EUR01-HE1-obe.outbound.protection.outlook.com (mail-he1eur01on0069.outbound.protection.outlook.com [104.47.0.69]) by lists.linaro.org (Postfix) with ESMTPS id 2870F60951 for ; Tue, 17 Jan 2017 16:28:54 +0000 (UTC) Received: from e109786-lin.cambridge.arm.com (217.140.96.140) by AM5PR0801MB1746.eurprd08.prod.outlook.com (10.169.247.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.845.12; Tue, 17 Jan 2017 16:28:52 +0000 From: Sergei Trofimov To: Date: Tue, 17 Jan 2017 16:28:41 +0000 Message-ID: <1484670521-28503-6-git-send-email-sergei.trofimov@arm.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1484670521-28503-1-git-send-email-sergei.trofimov@arm.com> References: <1484670521-28503-1-git-send-email-sergei.trofimov@arm.com> MIME-Version: 1.0 X-Originating-IP: [217.140.96.140] X-ClientProxiedBy: DB6PR0301CA0004.eurprd03.prod.outlook.com (10.168.49.14) To AM5PR0801MB1746.eurprd08.prod.outlook.com (10.169.247.12) X-MS-Office365-Filtering-Correlation-Id: 7afb83f3-07c4-4a31-0c76-08d43ef5ecc8 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:AM5PR0801MB1746; X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 3:F7GERp1mfeSV4khLh5gLt8YGw+8wNlhiyoDHeZbDZmhe+fwqyTCrPD/T46oks/FDwk9KfIs3OrF2HkS192PG4BJIBQzV0dT1guD3Fy5gu+bv68eftat7T+l1NU/3onBcfbFwkGM4Nn2z0VevKjhQH9yv1FQf33WQcaH8rMfL+O6hoBJfYb6S7gC+J6yq3KOAo7B9Ox5QaTUSKb7Fm80Ll3lS74qurkpPJYUN5zTvnLG4eDWDBzYkKV22xFS6NXS/qAPKfJxA8TU50grfF67hIA== X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 25:N0l5WrNM6yQsThIxRF6lz08mmJ4DWOe106rqJmfEDYuStNJqhrcHxIvotGnyXa9uShLRfJO3BiiH6Miq3s/3XcpJSXjjyNXbb/eiLez8DywQafH8xP1VAG7dYDVfJC7hd7z70YEtvjv2Z7cwR+VP4BYHlsH1+Cf4vuIK2f0JslMEF3VF54IDHCQfCtOyyCtDU37fLCWbGriigZFMMoAHUG1C76e0qDmKLp4fJkglXbXHBcp+ETCcxAO6X4sYqqSSY0ZNUyUo+ZmWuXCoyBUGGUak7l4lsJFfGQytC5gD948xUSYUUh1uLXUU6tQxv5CvIxeh3YjrVUEdQzmTQiiQCq65s8BzTdaqBUwaG6BLUtnW6hZLaCpCD6FyRtbbs1FZ95F4jruQJ2Ss3LJ1TGNTSMMHDFXScjMWgpLH55r1+A2y0AExL6BEgxKHPxQA8Fpua3TciAJCqYOcE3tMfU7mJMqffB+yis+TiuSql1P3fEVUDMOUk5XOVp/xS/MPvvbmNNfQCOqP7a9Dm9gFYjQADvhpd0T2vAbdljrAxtLwVZiUN/+k47zjLxFVF1jCcxYcedUM3uO0JXv+f5IO6Y3LBK1PLJMNDTtncSGtrgnegJ4oULxeaFd17xW4hQNRGLIoww7tgk7T6PfDRWVXI6ytULDf8UW5kGqyhaVE4MuWRmourgMl2Wi7tCcvxk0cZ8XjzhawluPaKDP1S6XlqOxo3U+/5qdmMEOtdOWf6IAo6TdWKge+lpIPgr4wu2pxNyS2bqxDz8TVAHPUqwg60KHMTOwpJoUdNWs1Tcx1TxDtR4I= X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 31:xq1gU5OwUanVz2Bbcl7sbYHwqvFUVrnEEKiUnmWbKaCQUzFWwlZzHfdceKTdI9jF/+aUY3SX1HQPLJE+8oA3CwhnJFnCPlUv5uViUG5HuZYMW3zFqKfmKzK89li8tMINhh7hXdYtMuIPXVp67cO49uMWPrAdww2X+2d0dcCcGuoc7Yx17o6M5innrPSLSYo4qU0QOYrWL/ErTYz/jPjKJPfRLFOzALdlpuATTPiOnm0p3050jUhjk5hHtM0IFXC/; 20:bXDqcsMC10XMxG0lVT2duGMb1vgIdy5eTETg0lPNwQkXsQAkMsTVEQwjQgJI5k6hbnEaHlJ3qQcnQbvCp7azDPdJC9ZlR/MD8i8r//1IHZ1wk+ReIkkAQsO3ySWaULmymZggzVANnBwhq580jjTzKL+z5wKIVVszy28rDHJz56M= NoDisclaimer: True X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(180628864354917)(72170088055959); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040375)(601004)(2401047)(5005006)(8121501046)(10201501046)(3002001)(6055026)(6041248)(20161123555025)(20161123560025)(20161123564025)(20161123562025)(6072148); SRVR:AM5PR0801MB1746; BCL:0; PCL:0; RULEID:; SRVR:AM5PR0801MB1746; X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 4:LttY2YGmWs1K11DavxqM76sz9rjRIk+l4vy/I/846IR0riCC7aKBx8E/tWl3/CMGz1Az85m7T7CyVnW6Y3bWd1UuGuOA2PWFFG3dYbq/Qim+XYwkBv0PUfix7whYKO6JWHqKIDKaqPnqY1UpcbRG8QLl/LWFvXO9rsSjFOvTGS7CmM9Zb4qDWqgbDqKd0OH1F3f7xf540ZkzIK8MBPtOf2leiYvTX+sUOsKukr1Yf1lTQzxsS/0sALTg6YoaOEFyuXfYla6iu5aDO/Y+5sHkrWHnA+cw4xqGQURMVWNLTacjOJ2EOrNxQe9qnq8dbaSQ0JMsmiCRHuCBAM5xCIOGBXGXTQl39FN1i986UMBjkEvsh22KAcAOHBO3iCnSSPM0w6Z7m6sf3ZoP8z8D6rZ3NS8ml21PI5W1S104/1QXX7O10GJ5lxQfLdXIZZSfGsmPVOXo8RVhewvPt/phcp6WmlaWRfLryifJ1vAfLG1ID8B4BhJ+WBKetYc4FylCIxmB1f80S6phO3aTmX5Hq8zVBj64rya3wbiWcCI2fMKYykqDVMclzAc4N4tu2aODFOkcO+Rba1VU1w88/PYnzL3cLg0MJxePGifj16szEQMLnCBgHF3fClUwlWUDrrlmLfW+CNoEyrD5OzLfHMOwWXY5br2BAPxDs2DvrcLnp0lgPsU= X-Forefront-PRVS: 01901B3451 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6009001)(7916002)(39450400003)(39840400002)(39410400002)(39860400002)(39850400002)(199003)(189002)(6666003)(31430400001)(81166006)(8676002)(50226002)(81156014)(305945005)(450100001)(7736002)(38730400001)(2950100002)(6116002)(97736004)(92566002)(6916009)(47776003)(2906002)(3846002)(54906002)(33646002)(66066001)(48376002)(50466002)(50986999)(189998001)(4326007)(76176999)(25786008)(36756003)(6486002)(110136003)(106356001)(105586002)(5660300001)(575784001)(101416001)(68736007)(42186005)(2351001)(86362001)(5003940100001)(217873001); DIR:OUT; SFP:1101; SCL:1; SRVR:AM5PR0801MB1746; H:e109786-lin.cambridge.arm.com; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: arm.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; AM5PR0801MB1746; 23:fw3IRz7aYtam166NP3k6cyZLMS54DgE5jkElW/j?= URWZDoPulcabrpCRZ8fEuqZSKtnSecoiXQqrhzHWzu+bt1nyUREha4nE8Zb9HklfXy+nLRBoq5DggZ0Z0eVRQj4Tsp2kvBYrBPwgw9ItuupHaDVvqmdDmZ3EY/YRg7597W5fcY2jZzNnHmP4LtjXkmoiR+XS1wbggy+BA0hkbtuHmxidtugFpT1VrB5NF4OuGGgsL/ZxM6fG9PEggK5NmsqtsZXu5C3DFN4uFfk6vi0DKwX+u1utp1d2pK8GGE/Acu6AMwko49yu8wLqj83KtYoOt75uen9UABBhpHb0oV/WeaAgpJlwpkM9v+QS13alMXDnfUZhnhh8zPm9tPPIvn+G3fy8KpdZfiXIz65bRnzYfceLLWhe6TGDfVGEO29rqvKlpfVC5zFEqGsbloSUYywZdhA5qEhvbi3vgtX/HY/4baaUgJFSUAAKCM/7fflPGk7BxG93aY+qN80a+SDIKcQRVTOBeodpUrBJVxoN3hNNFQfTh/fTy0fOoOHXMyRS5+JD/hoi+ARJaNJ2c5r3gd22rZ5sa16/8dLkH2lISrQkTuCzwkv3dXQyGldARB81UHO4XOFxmB2A9T2fAUyRZT1+1y5CWrTQr5jAYsE8cjjzC6mvZ94lcSElRVhX9uhaDnXEKlDbzCPr1vAytiDEwlc5eenfCPa+/N4NxszektucAdN6F5Btp2EZsE4JzVaxFC0r82xIuhTPoS9pfgKKPiCHxEz1DJ3g1JqoDwWzBk9X3DI69JLinSGvec1llJlP34jQvEDhXzBcnzQrf9EyPLsxMAEW1ToiWQEZT+O0QKI19WBuoi4lqgcwLeTX+s58fZXjvISJmTwHDTOihIGwfw6KssFdwrfrP3S5zJzVLSkczHj0EjIo25uANFrzGjzXDLYb5SZ0hu9ZMjbs/LqsiXI4ulFqx9gZOzOKktl2OQck9DBXI2I1HwMmd8Q3LayzanUwI5jfZdGCPEa6onGihcEcA7gMMOHFfNkxPKfSEkLm08DDc3xfumfVC8vJTWdMEp55JjH+APV1fZAtymVSlqmBxaEAvY3hyi2uiSnbjmRTcizBh/uouu/Nq9s80RuviyzeYvfOaydYxLWgx6aGtDyX4Go3p0Lm+c6yTbk9hFBUlOZJ38YCwrI+Fytpj2FlMtIuM7u3UEhUEDfdhGmuzVjKCfucLdZGmu1i/iBn2iUrxcE1xuSZ2DDgOgNTv2KUjrY2hLxpee/WHS7Qih+MMYIRc9m8klg8DCN+A4kXPwOcgmA== X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 6:Jygvwj+8Glo6GsfeRTi3iDAtqj9TLJETkde9gRPabcCbCrHTIIxMWqvCsqe+qT9lR4kWHjZD8WsRIL3PTE3FmgP7Zp51tbwvVX4cr0ToDcl8jdYndDlcoqDD9Zql1A11DoLoIK2QW4FR9RrjYp6is6iCkep12oSgK4GpPkP/HXP53SP9xTRpVnayGDdFzOOrNdb0/RTvK2nav5NsPKRCfvEcarxXUOWnF8N5W1yxfcjvzUW+M5QPboNxVIJKrgwrWCpILAdZ1K9vSC75trM3OQ7/NEG4Dwl7rqJ/FpBk5hxyH28UI0X88FhkbU+DcgZjLG2EYaj9eVSeK5jfcrc7G4W92QMsMdUAZ0iShRs0rxfqWu4gJKyWVFGynbc3BgUOXMncpybCEphJbNh7phG6m7xx1O4fquE9YINiuNI0q+B8FdRTuNWbgtb7rFib+Xvs6etp2fjrCEdnRpn/J1oQeA==; 5:Rlbe4iW5BjaeiUBx8JYG9Eb81u1CaNe203MNAuAZGjirhaqQ0fqEacdvEqQ/wT+46ny/MP708QitgDvNsZZwSA9Gi8BX1tpsEzrQyqouTlOohF2ZwsRmt4BBw/OHI6YMy3msrceJf0CQhuRhak8d7A==; 24:8DbdmWFLJdYwlnEXGhw7LDCxQWV+dk/YivPwVaZ1DqYDMj43iF+6+UwQAmK2rB4hxqPl+3VIiMPeLpvcCbK6GlaqrqtXrPw2+3fTmbNNtxw= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 7:8rfoSN9IG+vqDf2s2x5xsBGgqSUrloQyly+nwUoBkiDqd8RGtH9D7/OEPGgZl7f2asjI2CZ4pyMpo3XOhe8ssqFvxaLy2JrtHAeRL0QELe3xDYbQPeH/N0A+s64I0tbzf9a94rms1Is3rUzyNF+OGRXtZB99xHjzaQuyzIkxD7BJgIn9OrIoGeZydu2pYVHEWeig7zyohPOFfm8sKpsCKQnFTncW43saU2yIltykyjsU3nqwcFxeCtz7leLmWvDQDdzBcOWhShU5ac4z+L6WCQ10hc+FR7oBBpVh6LXu0oJmPMW7MHT62mK+vjVv5CgK+fZY5pY+Lz2EHB8cEVJtMgynfhPcpYOtcsburbuyayZQMZSGp+K8srx4LX5adqTvxDlp+8w5A5JHOX3UQ5+eRyQOQ52mFVndN/MPIOMncis0RyPoyFPtei42vNQWfsecHgFr3JzDLj4L4cwHXyPSkg== X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Jan 2017 16:28:52.4493 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM5PR0801MB1746 Cc: nd@arm.com Subject: [lng-odp] [API-NEXT PATCH 5/5] power: Adding a power governor implementation X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "The OpenDataPlane \(ODP\) List" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: lng-odp-bounces@lists.linaro.org Sender: "lng-odp" Adding an API for a power governor. A governor will try to optimise power usage within an associated power domains by monitoring packet queue(s) to determine how much "performance" is necessary at a given point in time. This also implements a PoC DVFS governor that will step down the frequency periodically while the queue is under the thershold and jump to max if thershold is exceeded (this a similar behavior to the Linux ondemand cpufreq governor). Signed-off-by: Sergei Trofimov --- doc/users-guide/users-guide.adoc | 7 + include/odp/api/spec/power.h | 37 ++++ platform/linux-generic/Makefile.am | 1 + .../linux-generic/include/odp_config_internal.h | 5 + platform/linux-generic/include/odp_internal.h | 4 + platform/linux-generic/odp_init.c | 12 ++ platform/linux-generic/odp_power_governor.c | 220 +++++++++++++++++++++ 7 files changed, 286 insertions(+) create mode 100644 platform/linux-generic/odp_power_governor.c -- 1.9.1 diff --git a/doc/users-guide/users-guide.adoc b/doc/users-guide/users-guide.adoc index 41c57d1..00299cf 100755 --- a/doc/users-guide/users-guide.adoc +++ b/doc/users-guide/users-guide.adoc @@ -404,6 +404,13 @@ types of atomic variables. The ODP event model also makes use of queues to avoid the need for explicit locking in many cases. This will be discussed in the next section. +=== Power Governor +A power governor will try to minimize power usage of a set of cores while +maintaining QoS on one or more queues. The API define an interface for +initializing a governor for a set of CPUs specified by a mask, and for +registering and unregistering queues that will be monitored for QoS with an +existing governor. + == ODP Components == Building on ODP concepts, ODP offers several components that relate to the flow of work through an ODP application. These include the Classifier, diff --git a/include/odp/api/spec/power.h b/include/odp/api/spec/power.h index 26dd64e..09a4b0a 100644 --- a/include/odp/api/spec/power.h +++ b/include/odp/api/spec/power.h @@ -18,12 +18,20 @@ #include #include + #include +#include +#include +#include #ifdef __cplusplus extern "C" { #endif +typedef ODP_HANDLE_T(odp_power_governor_t); + +#define ODP_POWER_GOVERNOR_INVALID _odp_cast_scalar(odp_power_governor_t, 0) + /** * CPU power domain description. @@ -108,6 +116,35 @@ int odp_power_domain_set_perf_level(odp_power_domain_t *domain, int level); */ uint64_t odp_power_domain_get_perf_level(odp_power_domain_t *domain); +/** + * Initialize a power governor for the specified power domain. + * + * @param domain domain to be governed + * + */ +odp_power_governor_t odp_power_governor_init(odp_cpumask_t *cpus); + +/** + * + * Add a queue to be monitored by the power governor. The governor will be notified when the + * queue hits the specified threshold and will boost performance if possible. + * + * @param governor power governor to which the queue will be added + * @param queue queue who's depth will be monitored to determine when power + * needs to be boosted. + * @param threshold queue depth threshold at which power will be boosted (if possible). + */ +int odp_power_governor_add_queue(odp_power_governor_t governor, odp_queue_t queue, uint64_t threshold); + +/** + * Remove the queue from being monitored by the specified power governor. + * + * @param governor power governor to which the queue will be added + * @param queue queue who's depth will be monitored to determine when power + * needs to be boosted. + */ +int odp_power_governor_remove_queue(odp_power_governor_t governor, odp_queue_t queue); + #ifdef __cplusplus } #endif diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 738c582..16832cd 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -207,6 +207,7 @@ __LIB__libodp_linux_la_SOURCES = \ odp_pkt_queue.c \ odp_pool.c \ odp_power.c \ + odp_power_governor.c \ odp_queue.c \ odp_rwlock.c \ odp_rwlock_recursive.c \ diff --git a/platform/linux-generic/include/odp_config_internal.h b/platform/linux-generic/include/odp_config_internal.h index dadd59e..c0d12dd 100644 --- a/platform/linux-generic/include/odp_config_internal.h +++ b/platform/linux-generic/include/odp_config_internal.h @@ -130,6 +130,11 @@ extern "C" { #define CONFIG_BURST_SIZE 16 /* + * Maximum number of power governors + */ +#define ODP_CONFIG_POWER_GOVERNORS 16 + +/* * Maximum number of events in a pool */ #define CONFIG_POOL_MAX_NUM (1 * 1024 * 1024) diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h index b313b1f..c84239d 100644 --- a/platform/linux-generic/include/odp_internal.h +++ b/platform/linux-generic/include/odp_internal.h @@ -69,6 +69,7 @@ enum init_stage { CLASSIFICATION_INIT, TRAFFIC_MNGR_INIT, NAME_TABLE_INIT, + POWER_GOVERNOR_INIT, ALL_INIT /* All init stages completed */ }; @@ -116,6 +117,9 @@ int odp_time_term_global(void); int odp_tm_init_global(void); int odp_tm_term_global(void); +int odp_power_governor_init_global(void); +int odp_power_governor_term_global(void); + int _odp_int_name_tbl_init_global(void); int _odp_int_name_tbl_term_global(void); diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c index 06c6143..56df042 100644 --- a/platform/linux-generic/odp_init.c +++ b/platform/linux-generic/odp_init.c @@ -179,6 +179,13 @@ int odp_init_global(odp_instance_t *instance, ODP_ERR("ODP name table init failed\n"); goto init_failed; } + stage = NAME_TABLE_INIT; + + if (odp_power_governor_init_global()) { + ODP_ERR("ODP power governor init failed\n"); + goto init_failed; + } + stage = POWER_GOVERNOR_INIT; *instance = (odp_instance_t)odp_global_data.main_pid; @@ -204,6 +211,11 @@ int _odp_term_global(enum init_stage stage) switch (stage) { case ALL_INIT: + case POWER_GOVERNOR_INIT: + if (odp_power_governor_term_global()) { + ODP_ERR("Power governor term failed.\n"); + rc = -1; + } case NAME_TABLE_INIT: if (_odp_int_name_tbl_term_global()) { ODP_ERR("Name table term failed.\n"); diff --git a/platform/linux-generic/odp_power_governor.c b/platform/linux-generic/odp_power_governor.c new file mode 100644 index 0000000..1f30ffd --- /dev/null +++ b/platform/linux-generic/odp_power_governor.c @@ -0,0 +1,220 @@ +#define _POSIX_C_SOURCE 199309L + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct power_governor_entry_s; +typedef struct power_governor_entry_s { + struct power_governor_entry_s *next; + odp_spinlock_t lock; + odp_power_domain_t *domain; + odp_queue_t queue; + int current_perf_level_idx; + int _stop; + timer_t timer; + pthread_t thread; + odp_pool_t pool; + odp_event_t event; +} power_governor_entry_t; + +typedef struct power_governor_table_t { + power_governor_entry_t power_governor[ODP_CONFIG_POWER_GOVERNORS]; + uint32_t num_entries; +} power_governor_table_t; + +static power_governor_table_t *power_governor_tbl; + +static inline odp_power_governor_t power_governor_index_to_handle(uint32_t power_governor_id) +{ + return _odp_cast_scalar(odp_power_governor_t, power_governor_id); +} + +static inline uint32_t power_governor_handle_to_index(odp_power_governor_t power_governor_hdl) +{ + return _odp_typeval(power_governor_hdl); +} + +static inline power_governor_entry_t *get_power_governor_entry(uint32_t index) { + return &power_governor_tbl->power_governor[index]; +} + +static void governor_reset_timer(power_governor_entry_t *the_governor) +{ + struct itimerspec spec; + + spec.it_interval.tv_sec = 0; + spec.it_interval.tv_nsec = 0; + spec.it_value.tv_sec = 0; + spec.it_value.tv_nsec = 10000000; + timer_settime(the_governor->timer, 0, &spec, NULL); +} + +static void governor_spindown_cores(union sigval val) +{ + power_governor_entry_t *the_governor = (power_governor_entry_t *)val.sival_ptr; + odp_spinlock_lock(&the_governor->lock); + odp_power_domain_t *pdom = the_governor->domain; + + if (the_governor->current_perf_level_idx > 0) { + uint64_t next_level = pdom->perf_levels[--the_governor->current_perf_level_idx]; + odp_power_domain_set_perf_level(pdom, next_level); + governor_reset_timer(the_governor); + } + + odp_spinlock_unlock(&the_governor->lock); +} + +static void *governor_monitor(void *arg) +{ + power_governor_entry_t *the_governor = (power_governor_entry_t *)arg; + + while (1) { + odp_event_t event = odp_queue_deq_wait(the_governor->queue); + + if (the_governor->_stop) + break; + + odp_spinlock_lock(&the_governor->lock); + + odp_power_domain_t *pdom = the_governor->domain; + uint64_t max_level = pdom->perf_levels[pdom->num_perf_levels - 1]; + + if (the_governor->current_perf_level_idx < pdom->num_perf_levels - 1) { + odp_power_domain_set_perf_level(pdom, max_level); + the_governor->current_perf_level_idx = pdom->num_perf_levels - 1; + governor_reset_timer(the_governor); + } + + odp_spinlock_unlock(&the_governor->lock); + odp_queue_threshold_arm(the_governor->queue, event); + } + + return NULL; +} + +int odp_power_governor_init_global(void) +{ + odp_shm_t shm; + + shm = odp_shm_reserve("odp_power_governors", + sizeof(power_governor_table_t), + sizeof(power_governor_entry_t), 0); + + power_governor_tbl = odp_shm_addr(shm); + + if (power_governor_tbl == NULL) + return -1; + + memset(power_governor_tbl, 0, sizeof(power_governor_table_t)); + + return 0; +} + +int odp_power_governor_term_global(void) +{ + int ret = odp_shm_free(odp_shm_lookup("odp_power_governors")); + if (ret < 0) { + ODP_ERR("shm free failed for odp_power_governors"); + return ret; + } + + return 0; +} + +odp_power_governor_t odp_power_governor_init(odp_cpumask_t *cpus) +{ + odp_power_domain_info_t cpu_info; + odp_power_domain_info_populate(&cpu_info); + odp_power_domain_t *domain = odp_power_domain_for_cpu(&cpu_info, odp_cpumask_first(cpus)); + + if (power_governor_tbl->num_entries == ODP_CONFIG_POWER_GOVERNORS) { + errno = ENOMEM; + return ODP_POWER_GOVERNOR_INVALID; + } + power_governor_entry_t *the_governor = &power_governor_tbl->power_governor[power_governor_tbl->num_entries++]; + + odp_spinlock_init(&the_governor->lock); + the_governor->next = NULL; + + odp_queue_param_t qparams; + odp_queue_param_init(&qparams); + qparams.type = ODP_QUEUE_TYPE_NOTIF; + the_governor->queue = odp_queue_create("power-governor-queue", &qparams); + if (the_governor->queue == ODP_QUEUE_INVALID) { + errno = EINVAL; + return ODP_POWER_GOVERNOR_INVALID; + } + + the_governor->_stop = 0; + + the_governor->domain = domain; + int current_perf_level = odp_power_domain_get_perf_level(domain); + int i; + for (i =0; i < domain->num_perf_levels; i++) { + if (current_perf_level == domain->perf_levels[i]) { + the_governor->current_perf_level_idx = i; + break; + } + } + + odp_pool_param_t params; + odp_pool_param_init(¶ms); + params.buf.size = sizeof(void *); + params.buf.num = 1; + params.buf.align = 0; + params.type = ODP_POOL_BUFFER; + + the_governor->pool = odp_pool_create("power_governor_pool", ¶ms); + odp_buffer_t buffer = odp_buffer_alloc(the_governor->pool); + *(void **)odp_buffer_addr(buffer) = (void *)&the_governor; + the_governor->event = odp_buffer_to_event(buffer); + + struct sigevent sev; + sev.sigev_notify = SIGEV_THREAD; + sev.sigev_value.sival_ptr = (void *)the_governor; + sev.sigev_notify_function = governor_spindown_cores; + sev.sigev_notify_attributes = NULL; + + int ret = timer_create(CLOCK_MONOTONIC, &sev, &the_governor->timer); + if (ret == -1) { + return ODP_POWER_GOVERNOR_INVALID; + } + + ret = pthread_create(&the_governor->thread, NULL, governor_monitor, the_governor); + if (ret) { + errno = ret; + return ODP_POWER_GOVERNOR_INVALID; + } + + governor_reset_timer(the_governor); + + return power_governor_index_to_handle(power_governor_tbl->num_entries - 1); +} + +int odp_power_governor_add_queue(odp_power_governor_t handle, odp_queue_t targetq, uint64_t threshold) +{ + uint32_t index = power_governor_handle_to_index(handle); + power_governor_entry_t *the_governor = get_power_governor_entry(index); + odp_queue_threshold_arm(the_governor->queue, the_governor->event); + return odp_queue_threshold_set(targetq, threshold, the_governor->queue); +} + +int odp_power_governor_remove_queue(odp_power_governor_t handle ODP_UNUSED, odp_queue_t targetq) +{ + return odp_queue_threshold_reset(targetq); +}