pax_global_header00006660000000000000000000000064142374665150014527gustar00rootroot0000000000000052 comment=0bb5f69e3c5c1a9044e8ecb99f7539ca22d29c13 powercap-0.6.0/000077500000000000000000000000001423746651500133525ustar00rootroot00000000000000powercap-0.6.0/.gitignore000066400000000000000000000000061423746651500153360ustar00rootroot00000000000000_* *~ powercap-0.6.0/.travis.yml000066400000000000000000000017601423746651500154670ustar00rootroot00000000000000os: - linux dist: focal arch: - amd64 - arm64 - ppc64le - s390x matrix: include: # Different distros and compilers on amd64 - dist: focal compiler: gcc - dist: focal compiler: clang # Different architectures, gcc only # We test these b/c Debian and Ubuntu packaging builds them - arch: arm64 - arch: ppc64le - arch: s390x language: c script: - mkdir _build - cd _build # Test build with stricter flags - export CFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector -g3 -pedantic -Wall -Wextra -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wendif-labels -Wfloat-conversion -Wfloat-equal -Wformat=2 -Wformat-nonliteral -Winline -Wmissing-declarations -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wpointer-arith -Wshadow -Wsign-conversion -Wstrict-prototypes -Wstack-protector -Wundef -Wwrite-strings -Werror" - cmake .. -DCMAKE_C_FLAGS="$CFLAGS" - cmake --build . - ctest --verbose powercap-0.6.0/AUTHORS000066400000000000000000000000771423746651500144260ustar00rootroot00000000000000Connor Imes powercap-0.6.0/CMakeLists.txt000066400000000000000000000076651423746651500161300ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-3-Clause cmake_minimum_required(VERSION 3.12) project(powercap VERSION 0.6.0 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) add_compile_options(-Wall) include(GNUInstallDirs) # See powercap-common.h for enumeration set(POWERCAP_LOG_LEVEL 4 CACHE STRING "Set the log level: 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=OFF (default)") set(POWERCAP_CMAKE_CONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/powercap) # Libraries add_library(powercap src/powercap.c src/powercap-sysfs.c src/powercap-rapl.c src/powercap-rapl-sysfs.c src/powercap-common.c) target_include_directories(powercap PUBLIC $ $) set_target_properties(powercap PROPERTIES PUBLIC_HEADER "inc/powercap.h;inc/powercap-sysfs.h;inc/powercap-rapl.h;inc/powercap-rapl-sysfs.h") target_compile_definitions(powercap PRIVATE POWERCAP_LOG_LEVEL=${POWERCAP_LOG_LEVEL}) if (BUILD_SHARED_LIBS) set_target_properties(powercap PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) endif() install(TARGETS powercap EXPORT PowercapTargets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Powercap_Runtime NAMELINK_COMPONENT Powercap_Development ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Powercap_Development PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} COMPONENT Powercap_Development) # pkg-config set(PKG_CONFIG_EXEC_PREFIX "\${prefix}") set(PKG_CONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}") set(PKG_CONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}") set(PKG_CONFIG_CFLAGS "-I\${includedir}") set(PKG_CONFIG_NAME "${PROJECT_NAME}") set(PKG_CONFIG_DESCRIPTION "C bindings to the Linux Power Capping Framework in sysfs") set(PKG_CONFIG_LIBS "-L\${libdir} -lpowercap") set(PKG_CONFIG_LIBS_PRIVATE "") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/pkgconfig.in ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/powercap.pc ) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT Powercap_Development) # CMake package helper include(CMakePackageConfigHelpers) set(CONFIG_TARGETS_FILE PowercapTargets.cmake) # While we (currently) always build and install utils, making their import optional makes downstream packaging easier. # E.g., cmake package configs belong in the Debian dev package, which depends on the lib---but not the utils---package. set(CONFIG_SUPPORTED_COMPONENTS Utils) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/PowercapConfig.cmake INSTALL_DESTINATION ${POWERCAP_CMAKE_CONFIG_INSTALL_DIR} NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/PowercapConfigVersion.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/PowercapConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/PowercapConfigVersion.cmake DESTINATION ${POWERCAP_CMAKE_CONFIG_INSTALL_DIR} COMPONENT Powercap_Development) install(EXPORT PowercapTargets DESTINATION ${POWERCAP_CMAKE_CONFIG_INSTALL_DIR} NAMESPACE Powercap:: COMPONENT Powercap_Development) # Uninstall configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake @ONLY ) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) # Tests and Utilities enable_testing() add_subdirectory(test) add_subdirectory(utils) powercap-0.6.0/Config.cmake.in000066400000000000000000000017731423746651500161760ustar00rootroot00000000000000@PACKAGE_INIT@ include(${CMAKE_CURRENT_LIST_DIR}/@CONFIG_TARGETS_FILE@) set(_${CMAKE_FIND_PACKAGE_NAME}_supported_components @CONFIG_SUPPORTED_COMPONENTS@) foreach(_comp ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS}) if(NOT _comp IN_LIST _${CMAKE_FIND_PACKAGE_NAME}_supported_components) set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False) set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}") elseif(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CMAKE_FIND_PACKAGE_NAME}${_comp}Targets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/${CMAKE_FIND_PACKAGE_NAME}${_comp}Targets.cmake") set(${CMAKE_FIND_PACKAGE_NAME}_${_comp}_FOUND True) else() set(${CMAKE_FIND_PACKAGE_NAME}_${_comp}_FOUND False) if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED_${_comp}) set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False) set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "Component not found: ${_comp}") endif() endif() endforeach() unset(_${CMAKE_FIND_PACKAGE_NAME}_supported_components) powercap-0.6.0/LICENSE000066400000000000000000000027551423746651500143700ustar00rootroot00000000000000Copyright (c) 2016-2022, Connor Imes All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Chicago nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF CHICAGO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. powercap-0.6.0/README.md000066400000000000000000000174411423746651500146400ustar00rootroot00000000000000# Powercap Sysfs C Bindings and Utilities This project provides the `powercap` library -- a generic C interface to the Linux power capping framework (sysfs interface). It includes an implementation for working with Intel Running Average Power Limit (RAPL). It also provides the following applications: * `powercap-info` - view powercap control type hierarchies or zone/constraint-specific configurations * `powercap-set` - set powercap control type zone/constraint-specific configurations These bindings were originally created for use with [RAPLCap](https://github.com/powercap/raplcap), but can be used independently. See the RAPLCap project for a more general interface for managing RAPL power caps, including other command line utilities. If using this project for other scientific works or publications, please reference: * Connor Imes, Huazhe Zhang, Kevin Zhao, Henry Hoffmann. "CoPPer: Soft Real-time Application Performance Using Hardware Power Capping". In: IEEE International Conference on Autonomic Computing (ICAC). 2019. DOI: https://doi.org/10.1109/ICAC.2019.00015
BibTex ```BibTex @inproceedings{imes2019copper, author={Imes, Connor and Zhang, Huazhe and Zhao, Kevin and Hoffmann, Henry}, booktitle={2019 IEEE International Conference on Autonomic Computing (ICAC)}, title={{CoPPer}: Soft Real-Time Application Performance Using Hardware Power Capping}, year={2019}, pages={31-41}, doi={10.1109/ICAC.2019.00015} } ```
## Prerequisites Powercap (with the RAPL implementation) was released with Linux kernel 3.13. You must be running this kernel or newer with the configs `CONFIG_POWERCAP` and `CONFIG_INTEL_RAPL` enabled. To use the `intel-rapl` control type, ensure that the appropriate kernel module is loaded. Run with proper privileges: ```sh modprobe intel_rapl_msr ``` Or on kernels older than 5.3: ```sh modprobe intel_rapl ``` ## Power Capping Modern hardware is constrained by power and temperature limitations, often quantified as Thermal Design Power. In processors and other clock-driven hardware components, power consumption `P` is proportional to capacitance `C`, the square of the voltage `V`, and clock frequency `f`: `P ~ C * V^2 * f`. A popular mechanism for balancing performance and power consumption is Dynamic Voltage and Frequency Scaling (DVFS). For compute-bound applications, DVFS provides a linear relationship between frequency and performance. However, power is non-linear with frequency since an increase in frequency also requires an increase in voltage. Although the relationship between performance and power is more difficult to model, hardware can be better at optimizing voltage and frequency than software while still respecting a power cap over a time window. Power capping allows a system administrator to configure an upper limit on the power consumption of various hardware components while letting the hardware more efficiently manage voltage and frequency. Setting a power cap does *NOT* imply that the component will actually consume that power, only that it will not violate that limit on average over the specified time window. ## Usage ### Applications See the man pages or run the applications with the `-h` or `--help` option for instructions. ### Library First, there is the `powercap-sysfs.h` interface for reading/writing to sysfs without the need to maintain state. This is reasonable for simple use cases. See the header files for documentation. The `powercap.h` interface provides read/write functions for generic powercap `zone` and `constraint` file sets. Users are responsible for managing memory and populating the structs with file descriptors (e.g., code that wrap this interface performs zone/constraint discovery and file descriptor management). The `powercap-rapl.h` interface discovers RAPL instances, power zones, and constraints (i.e., long\_term and short\_term constraints). Users are responsible for managing memory, but the library will manage discovering, opening, and closing files within instances. Basic lifecycle example: ```C // get number of top-level (parent) RAPL instances uint32_t count = powercap_rapl_get_num_instances(); if (count == 0) { // none found (maybe the kernel module isn't loaded?) perror("powercap_rapl_get_num_instances") return -1; } powercap_rapl_pkg* pkgs = malloc(count * sizeof(powercap_rapl_pkg)); // initialize uint32_t i; for (i = 0; i < count; i++) { if (powercap_rapl_init(i, &pkgs[i], 0)) { // could be that you don't have write privileges perror("powercap_rapl_init"); return -1; } } // do a bunch of stuff with the interface here, // e.g., enable desired zones and get/set power caps... // now cleanup for (i = 0; i < count; i++) { if (powercap_rapl_destroy(&pkgs[i])) { perror("powercap_rapl_destroy"); } } free(pkgs); ``` ### Additional Comments The interfaces do _NOT_ guarantee that values are actually accepted by the kernel, they only notice errors if I/O operations fail. It is recommended that, at least during development/debugging, users read back to see if their write operations were successful. Additionally, the kernel sysfs bindings (and thus the `powercap-rapl` interface) do _NOT_ guarantee that RAPL instances are presented in any particular order. For example, the first instance (sysfs directory `intel-rapl:0`) on a dual-socket system may actually provide access to `package-1` instead of `package-0`, and vice versa. In cases where order matters, e.g., when sockets are managed asymmetrically, the user is responsible for ensuring that the correct powercap instance is being operated on, e.g., by checking its name with `powercap_rapl_get_name(...)`. More concretely, in the example above, `powercap_rapl_get_name(&pkgs[0], POWERCAP_RAPL_ZONE_PACKAGE, ...)` gives name `package-1`, and `powercap_rapl_get_name(&pkgs[1], POWERCAP_RAPL_ZONE_PACKAGE, ...)` is `package-0`. It might be helpful to sort the `pkgs` array *after* initialization (see the `powercap` implementation of [RAPLCap](https://github.com/powercap/raplcap) for an example). Finally, the `powercap-rapl` interface exposes functions for files that are not (currently) supported by RAPL in order to be compliant with the powercap interface. Use the `powercap_rapl_is_zone_file_supported(...)` and `powercap_rapl_is_constraint_file_supported(...)` functions to check in advance if you are unsure if a zone or constraint file is supported. Furthermore, files may exist but always return an error code for some zones or constraints, e.g., the constraint `max_power_uw` file (`powercap_rapl_get_max_power_uw(...)`) for zones other than `POWERCAP_RAPL_ZONE_PACKAGE`. ## Building ### Compiling This project uses CMake. To build, run: ``` sh mkdir _build cd _build cmake .. make ``` To create a shared object library as a release build, specify for cmake: ``` sh cmake .. -DBUILD_SHARED_LIBS=On -DCMAKE_BUILD_TYPE=Release ``` ### Installing To install, run with proper privileges: ``` sh make install ``` On Linux, installation typically places libraries in `/usr/local/lib` and header files in `/usr/local/include`. ### Uninstalling Install must be run before uninstalling in order to have a manifest. To uninstall, run with proper privileges: ``` sh make uninstall ``` ## Project Source Find this and related project sources at the [powercap organization on GitHub](https://github.com/powercap). This project originates at: https://github.com/powercap/powercap Bug reports and pull requests for bug fixes and enhancements are welcome. ## License This project is developed by Connor Imes. It is released under the 3-Clause BSD License. ## Thanks Special thanks to Henry Hoffmann (University of Chicago) and Steven Hofmeyr (Lawrence Berkeley National Laboratory) for advising and supporting projects that this code was originally developed for. powercap-0.6.0/RELEASES.md000066400000000000000000000132461423746651500151050ustar00rootroot00000000000000# Release Notes ## [v0.6.0] - 2022-05-13 ### Added * powercap-info: control type name no longer required - will print info for all control types if not set ### Changed * Powercap CMake package config helper now uses package-specific name for global components variable. See [CMake Issue #23112] and [CMake Merge Request #6975] for reasoning and technical details. * Internal tweaks based on testing with additional compiler flags ## [v0.5.0] - 2021-12-09 ### Added * CMake installation components ### Changed * Increased minimum CMake version from 3.1 to 3.12 * CMake package config now exports binaries in a 'Utils' component rather than parent package ## [v0.4.0] - 2021-04-25 ### Fixed * powercap.h: header documentation for 'powercap_*_file_get_name' functions' return behavior * rapl-{info,set}: deprecation messages that specified non-existent alternatives ### Added * Functions to support opening files in powercap.h: * 'powercap_control_type_file_open' * 'powercap_zone_file_open' * 'powercap_constraint_file_open' * CMake helper to find powercap without relying on pkg-config ### Changed * Binaries powercap-{info,set} now accept the control type argument without requiring a preceding -p flag * Increased minimum CMake version from 2.8.12 to 3.1 ### Deprecated * Flag '-p/--control-type' in powercap-{info,set} - specify control type name as the first positional argument instead * Add compiler deprecation attributes to deprecated functions ## [v0.3.1] - 2020-11-08 ### Fixed * [#6] powercap-common-test:test_snprintf_base_path fails on ppc64el architecture ## [v0.3.0] - 2020-08-15 ### Added * Support for top-level control type * Struct 'powercap_control_type', enum 'powercap_control_type_file', and associated functions in powercap.h: * 'powercap_control_type_get_enabled' * 'powercap_control_type_set_enabled' * 'powercap_control_type_file_get_name' * Functions in powercap-sysfs.h: * 'powercap_sysfs_control_type_get_enabled' * 'powercap_sysfs_control_type_set_enabled' * Functions in powercap-rapl.h: * 'powercap_rapl_control_is_supported' * 'powercap_rapl_control_is_enabled' * 'powercap_rapl_control_set_enabled' * Argument '--enabled' to powercap-{info,set} for getting/setting control type enabled field * Function 'powercap_rapl_get_num_instances' in powercap-rapl.h (supersedes 'powercap_rapl_get_num_packages') * Argument '--nconstraints' to powercap-info for getting the number of zone constraints ### Changed * Increased minimum CMake version from 2.8.5 to 2.8.12 to support target_compile_definitions * Updated 'powercap-{info,set}' man pages * Argument '--zone' for powercap-set no longer required due to introduction of '--enabled' argument * Disabled logging by default (in general, libraries shouldn't print output unless requested) ### Deprecated * Binaries rapl-{info,set} - use powercap-{info,set} instead * Interface powercap-rapl-sysfs.h - use powercap-sysfs.h directly instead * Function 'powercap_rapl_get_num_packages' in powercap-rapl.h - use 'powercap_rapl_get_num_instances' instead ### Fixed * Fixed [#4]: powercap-rapl now checks if parent zone is PACKAGE or PSYS ## [v0.2.0] - 2019-12-03 ### Added * This RELEASES.md file * Multiarch support (use GNU standard installation directories) * Additional documentation in README * Function 'rapl_sysfs_zone_exists' in powercap-rapl-sysfs.h * Command line long option '--zone' to rapl-info and rapl-set * Functions to powercap-rapl-sysfs.h allowed by the powercap API that RAPL doesn't support (but could in the future) * Options to rapl-info and rapl-set to support optional powercap features not currently implemented in RAPL ### Changed * Increased minimum CMake version from 2.8 to 2.8.5 to support GNUInstallDirs * More pedantic man page source formatting * RAPL sysfs 'pkg' parameter names changed to 'zone' to improve generality * RAPL 'package' parameter names changed to 'id' to improve generality * On failure, binaries now exit with positive error codes instead of negative values ### Deprecated * Function 'rapl_sysfs_pkg_exists' in powercap-rapl-sysfs.h - use 'rapl_sysfs_zone_exists' instead * Function 'rapl_sysfs_sz_exists' in powercap-rapl-sysfs.h - use 'rapl_sysfs_zone_exists' instead * Command line long option '--package' for rapl-info and rapl-set - use '--zone' instead ### Removed * Removed private symbol exports in shared object library (already patched in Debian) * Undocumented (and unintended) --package long option from powercap-set ### Fixed * Fixed [#1]: Kernel uses hexadecimal numbers in directory paths, not decimal ## [v0.1.1] - 2017-09-21 ### Added * Added stateless interfaces to sysfs * Added powercap-info, powercap-set, rapl-info, and rapl-set binaries and man pages * Added VERSION and SOVERSION to shared object libraries ### Changed * Update license to use author as copyright holder ## v0.1.0 - 2017-06-09 ### Added * Initial public release [v0.6.0]: https://github.com/powercap/powercap/compare/v0.5.0...v0.6.0 [v0.5.0]: https://github.com/powercap/powercap/compare/v0.4.0...v0.5.0 [v0.4.0]: https://github.com/powercap/powercap/compare/v0.3.1...v0.4.0 [v0.3.1]: https://github.com/powercap/powercap/compare/v0.3.0...v0.3.1 [v0.3.0]: https://github.com/powercap/powercap/compare/v0.2.0...v0.3.0 [v0.2.0]: https://github.com/powercap/powercap/compare/v0.1.1...v0.2.0 [v0.1.1]: https://github.com/powercap/powercap/compare/v0.1.0...v0.1.1 [#6]: https://github.com/powercap/powercap/issues/6 [#4]: https://github.com/powercap/powercap/issues/4 [#1]: https://github.com/powercap/powercap/issues/1 [CMake Issue #23112]: https://gitlab.kitware.com/cmake/cmake/-/issues/23112 [CMake Merge Request #6975]: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6975 powercap-0.6.0/cmake_uninstall.cmake.in000066400000000000000000000020121423746651500201250ustar00rootroot00000000000000if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file)powercap-0.6.0/inc/000077500000000000000000000000001423746651500141235ustar00rootroot00000000000000powercap-0.6.0/inc/powercap-rapl-sysfs.h000066400000000000000000000250751423746651500202260ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * This interface is deprecated - use powercap-sysfs.h directly instead. * By limiting zone depth to 2, this interface will break if Intel RAPL extends its tree depth in the future. * The only other abstraction it provides is to mask the control type parameter, which doesn't add much value. * Intel also added the intel-rapl-mmio control type, so even the control type abstraction is not as useful as before. * * Read/write RAPL sysfs files. * This is a wrapper around powercap-sysfs.h. * * The control type is "intel-rapl" and zone depth is limited to 2. * The "zone" parameters below are for the top-level "zone", and the optional "sz" parameters are for other control * planes like "core", "uncore", and "dram". * The "is_sz" parameter must be non-zero when working with these control planes. * * For example, zone=0, sz=0, is_sz=1 is usually for the "core" power plane and is analogous to using powercap-sysfs.h * with zones[2]={0, 0}, depth=2. * * The "intel-rapl" control type implements a subset of the powercap interface. * The following functions are not currently supported by RAPL, but are implemented here in case RAPL adds support for * them in the future: * - rapl_sysfs_zone_reset_energy_uj * - rapl_sysfs_zone_get_max_power_range_uw * - rapl_sysfs_zone_get_power_uw * - rapl_sysfs_constraint_get_min_power_uw * - rapl_sysfs_constraint_get_max_time_window_us * - rapl_sysfs_constraint_get_min_time_window_us * * @author Connor Imes * @date 2017-08-24 * @deprecated Use powercap-sysfs.h directly instead. */ #ifndef _RAPL_SYSFS_H #define _RAPL_SYSFS_H #ifdef __cplusplus extern "C" { #endif #include #include #if !defined(POWERCAP_DEPRECATED) #if defined(POWERCAP_ALLOW_DEPRECATED) #define POWERCAP_DEPRECATED(x) #elif defined(__GNUC__) || defined(__clang__) #define POWERCAP_DEPRECATED(x) __attribute__((deprecated(x))) #elif defined(_MSC_VER) #define POWERCAP_DEPRECATED(x) __declspec(deprecated(x)) #else #define POWERCAP_DEPRECATED(x) #endif #endif /** * Determine if a zone or subzone exist. * It is _not_ assumed that a zone maps one-to-one with an particular physical component like a socket or die. * * Originally, a zone mapped to a physical socket/package, but this assumed mapping did not hold. * As of 2019, a zone maps to a CPU die, but nothing prevents Intel from changing the scope again in the future. * Their backward compatibility _appears_ to be in a zone's name, but even this is not explicitly guaranteed, nor does * this sysfs binding interface make such an assumption - it is the user's responsibility to interpret what a zone is. * * @param zone * @param sz * @param is_sz * @return 0 if zone exists, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_exists() instead") int rapl_sysfs_zone_exists(uint32_t zone, uint32_t sz, int is_sz); /** * @deprecated Use rapl_sysfs_zone_exists() instead. * * This function's name no longer accurately describes its scope. * Prior to Cascade Lake CPUs (2019), RAPL top-level (parent) zones mapped one-to-one with physical sockets/packages. * Thus the term "pkg" made sense and was chosen over the more general term "zone". * Some systems now support multiple die on a physical socket/package, resulting in multiple top-level (parent) zones * per physical socket/package. * The scope of a zone could potentially change again in the future. * * This function checks if a top-level (parent) zone exists, where num(top-level zones) >= num(sockets). * For systems with a single die per physical socket, num(top-level zones) == num(sockets). * For systems with multiple die per physical socket, num(top-level zones) > num(sockets). * * @param zone * @return 0 if zone exists, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_exists() instead") int rapl_sysfs_pkg_exists(uint32_t zone); /** * @deprecated Use rapl_sysfs_zone_exists() instead. * * Determine if a subzone exists. * * @param zone * @param sz * @return 0 if subzone exists, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_exists() instead") int rapl_sysfs_sz_exists(uint32_t zone, uint32_t sz); /** * Determine if a constraint exists. * * @param zone * @param sz * @param is_sz * @param constraint * @return 0 if constraint exists, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_exists() instead") int rapl_sysfs_constraint_exists(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint); /** * Get max_energy_range_uj for a zone. * * @param zone * @param sz * @param is_sz * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_get_max_energy_range_uj() instead") int rapl_sysfs_zone_get_max_energy_range_uj(uint32_t zone, uint32_t sz, int is_sz, uint64_t* val); /** * Reset energy_uj for a zone. * * @param zone * @param sz * @param is_sz * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_reset_energy_uj() instead") int rapl_sysfs_zone_reset_energy_uj(uint32_t zone, uint32_t sz, int is_sz); /** * Get energy_uj for a zone. * * @param zone * @param sz * @param is_sz * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_get_energy_uj() instead") int rapl_sysfs_zone_get_energy_uj(uint32_t zone, uint32_t sz, int is_sz, uint64_t* val); /** * Get max_power_range_uw for a zone. * * @param zone * @param sz * @param is_sz * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_get_max_power_range_uw() instead") int rapl_sysfs_zone_get_max_power_range_uw(uint32_t zone, uint32_t sz, int is_sz, uint64_t* val); /** * Get power_uw for a zone. * * @param zone * @param sz * @param is_sz * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_get_power_uw() instead") int rapl_sysfs_zone_get_power_uw(uint32_t zone, uint32_t sz, int is_sz, uint64_t* val); /** * Enable/disable a zone. * * @param zone * @param sz * @param is_sz * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_set_enabled() instead") int rapl_sysfs_zone_set_enabled(uint32_t zone, uint32_t sz, int is_sz, uint32_t val); /** * Get whether a zone is enabled or disabled. * * @param zone * @param sz * @param is_sz * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_get_enabled() instead") int rapl_sysfs_zone_get_enabled(uint32_t zone, uint32_t sz, int is_sz, uint32_t* val); /** * Get name for a zone. * * @param zone * @param sz * @param is_sz * @param buf * @param size * @return number of bytes read, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_zone_get_name() instead") ssize_t rapl_sysfs_zone_get_name(uint32_t zone, uint32_t sz, int is_sz, char* buf, size_t size); /** * Set power_limit_uw for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_set_power_limit_uw() instead") int rapl_sysfs_constraint_set_power_limit_uw(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t val); /** * Get power_limit_uw for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_get_power_limit_uw() instead") int rapl_sysfs_constraint_get_power_limit_uw(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val); /** * Set time_window_us for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_set_time_window_us() instead") int rapl_sysfs_constraint_set_time_window_us(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t val); /** * Get time_window_us for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_get_time_window_us() instead") int rapl_sysfs_constraint_get_time_window_us(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val); /** * Get max_power_uw for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_get_max_power_uw() instead") int rapl_sysfs_constraint_get_max_power_uw(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val); /** * Get get_min_power_uw for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_get_min_power_uw() instead") int rapl_sysfs_constraint_get_min_power_uw(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val); /** * Get max_time_window_us for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_get_max_time_window_us() instead") int rapl_sysfs_constraint_get_max_time_window_us(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val); /** * Get min_time_window_us for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_get_min_time_window_us() instead") int rapl_sysfs_constraint_get_min_time_window_us(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val); /** * Get name for a constraint. * * @param zone * @param sz * @param is_sz * @param constraint * @param buf * @param size * @return number of bytes read, a negative error code otherwise. */ POWERCAP_DEPRECATED("Call powercap_sysfs_constraint_get_name() instead") ssize_t rapl_sysfs_constraint_get_name(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, char* buf, size_t size); #ifdef __cplusplus } #endif #endif powercap-0.6.0/inc/powercap-rapl.h000066400000000000000000000221531423746651500170530ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * A simple interface for configuring RAPL through a powercap control type. * Note that not all RAPL zones support short_term constraints. * Unless otherwise stated, all functions return 0 on success or a negative value on error. * * Setter functions do not verify that written values are accepted by RAPL. * Users may want to add a debug option to their software that follows writes/sets with a read/get. * * These operations do basic I/O - it may reasonably be expected that callers need to handle I/O errors. * For example, it has been seen that "powercap_rapl_get_max_power_uw" sets errno=ENODATA for power zones. * * The terms "package" and "pkg" refer to top-level (parent) RAPL instances, which aren't necessarily physical packages. * Prior to Cascade Lake CPUs (2019), RAPL top-level instances mapped one-to-one with physical sockets/packages. * Some systems now support multiple die on a physical socket/package, resulting in multiple top-level instances per * physical socket/package. * It is also possible that the scope of a top-level instances could change again in the future. * Thus, it should not be assumed that a 'powercap_rapl_pkg' instance or a 'POWERCAP_RAPL_ZONE_PACKAGE' zone maps * one-to-one with a physical socket. * Intel's backward compatibility _appears_ to be in a zone's name, but even this is not explicitly guaranteed - it is * the user's responsibility to interpret what a top-level RAPL instance actually is. * * @author Connor Imes * @date 2016-05-12 */ #ifndef _POWERCAP_RAPL_H_ #define _POWERCAP_RAPL_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include "powercap.h" #if !defined(POWERCAP_DEPRECATED) #if defined(POWERCAP_ALLOW_DEPRECATED) #define POWERCAP_DEPRECATED(x) #elif defined(__GNUC__) || defined(__clang__) #define POWERCAP_DEPRECATED(x) __attribute__((deprecated(x))) #elif defined(_MSC_VER) #define POWERCAP_DEPRECATED(x) __declspec(deprecated(x)) #else #define POWERCAP_DEPRECATED(x) #endif #endif /** * Files for each zone. */ typedef struct powercap_rapl_zone_files { powercap_zone zone; powercap_constraint constraint_long; powercap_constraint constraint_short; } powercap_rapl_zone_files; /** * All files for a top-level RAPL instance. */ typedef struct powercap_rapl_pkg { powercap_rapl_zone_files pkg; powercap_rapl_zone_files core; powercap_rapl_zone_files uncore; powercap_rapl_zone_files dram; powercap_rapl_zone_files psys; } powercap_rapl_pkg; /** * Zone enumeration. */ typedef enum powercap_rapl_zone { POWERCAP_RAPL_ZONE_PACKAGE, POWERCAP_RAPL_ZONE_CORE, POWERCAP_RAPL_ZONE_UNCORE, POWERCAP_RAPL_ZONE_DRAM, POWERCAP_RAPL_ZONE_PSYS } powercap_rapl_zone; /** * Long/short term constraint enumeration. */ typedef enum powercap_rapl_constraint { POWERCAP_RAPL_CONSTRAINT_LONG, POWERCAP_RAPL_CONSTRAINT_SHORT } powercap_rapl_constraint; /** * Check if RAPL is supported. * Returns 1 if enabled, 0 if disabled, a negative value in case of error. */ int powercap_rapl_control_is_supported(void); /** * Check if RAPL control is enabled. * Returns 1 if enabled, 0 if disabled, a negative value in case of error. */ int powercap_rapl_control_is_enabled(void); /** * Enable/disable RAPL control. */ int powercap_rapl_control_set_enabled(int val); /** * Get the number of top-level (parent) RAPL instances found. * Returns 0 and sets errno if none are found. */ uint32_t powercap_rapl_get_num_instances(void); /** * @deprecated Use powercap_rapl_get_num_instances() instead. * * This function's name no longer accurately describes its scope. * * Get the number of top-level (parent) RAPL instances found. * Returns 0 and sets errno if none are found. */ POWERCAP_DEPRECATED("Call powercap_rapl_get_num_instances() instead") uint32_t powercap_rapl_get_num_packages(void); /** * Initialize the struct for the parent zone with the given identifier. * Read-only access can be requested, which may prevent the need for elevated privileges. */ int powercap_rapl_init(uint32_t id, powercap_rapl_pkg* pkg, int read_only); /** * Clean up file descriptors. */ int powercap_rapl_destroy(powercap_rapl_pkg* pkg); /** * Check if a zone is supported. * The uncore power zone is usually only available on client-side hardware. * The DRAM power zone is usually only available on server-side hardware. * Some systems may expose zones like DRAM without actually supporting power caps for them. * The PSys power zone may be available on Skylake processors and later. * Returns 1 if supported, 0 if unsupported, a negative value in case of error. */ int powercap_rapl_is_zone_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone); /** * Check if a constraint is supported for a zone. * Returns 1 if supported, 0 if unsupported, a negative value in case of error. */ int powercap_rapl_is_constraint_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint); /** * Check if a file is supported for the given zone. * Returns 1 if supported, 0 if unsupported, a negative value in case of error. */ int powercap_rapl_is_zone_file_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_zone_file file); /** * Check if a file is supported for the given zone and constraint. * Returns 1 if supported, 0 if unsupported, a negative value in case of error. */ int powercap_rapl_is_constraint_file_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, powercap_constraint_file file); /** * Get the zone name. * Returns a non-negative value for the number of bytes read, a negative value in case of error. */ ssize_t powercap_rapl_get_name(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, char* buf, size_t size); /** * Check if zone is enabled. * Returns 1 if enabled, 0 if disabled, a negative value in case of error. */ int powercap_rapl_is_enabled(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone); /** * Enable/disable a zone. */ int powercap_rapl_set_enabled(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, int enabled); /** * Get the max energy range in microjoules. */ int powercap_rapl_get_max_energy_range_uj(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, uint64_t* val); /** * Get the current energy in microjoules. */ int powercap_rapl_get_energy_uj(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, uint64_t* val); /** * Reset the energy_uj value to 0. * Returns 0 on success, a negative value in case of error. * NOTE: As of this writing, RAPL does not support resetting the energy counter. */ int powercap_rapl_reset_energy_uj(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone); /** * Get the max power range in microwatts. * NOTE: As of this writing, RAPL does not support this file. */ int powercap_rapl_get_max_power_range_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, uint64_t* val); /** * Get the current power in microwatts. * NOTE: As of this writing, RAPL does not support this file. */ int powercap_rapl_get_power_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, uint64_t* val); /** * Get the maximum power in microwatts. */ int powercap_rapl_get_max_power_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val); /** * Get the minimum power allowed in microwatts. * NOTE: As of this writing, RAPL does not support this file. */ int powercap_rapl_get_min_power_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val); /** * Get the power limit in microwatts. */ int powercap_rapl_get_power_limit_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val); /** * Set the power limit in microwatts. */ int powercap_rapl_set_power_limit_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t val); /** * Get the maximum time window in microseconds. * NOTE: As of this writing, RAPL does not support this file. */ int powercap_rapl_get_max_time_window_us(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val); /** * Get the minimum time window in microseconds. * NOTE: As of this writing, RAPL does not support this file. */ int powercap_rapl_get_min_time_window_us(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val); /** * Get the time window in microseconds. */ int powercap_rapl_get_time_window_us(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val); /** * Set the time window in microseconds. */ int powercap_rapl_set_time_window_us(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t val); /** * Get the constraint name. * Returns a non-negative value for the number of bytes read, a negative value in case of error. */ ssize_t powercap_rapl_get_constraint_name(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, char* buf, size_t size); #ifdef __cplusplus } #endif #endif powercap-0.6.0/inc/powercap-sysfs.h000066400000000000000000000202651423746651500172660ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Read/write powercap sysfs files. * * The "control_type" parameter to functions is the name of the control type as it appears in the filesystem at * /sys/class/powercap, excluding zone/subzone identifiers, e.g., "intel-rapl". * The parameter cannot be NULL, empty, or contain any '.' or '/' characters. * * It is assumed that the folder tree structure includes the control type name at each directory level, then appends * zone indices after colons. * For example, a subpath to an Intel RAPL power plane looks like: "intel-rapl/intel-rapl:0/intel-rapl:0:1/". * * The "zones" parameter to functions is an array of at least "depth" length and describes the index to use at each * level in a control type's zone hierarchy tree. * The value at each index in the array, from zones[0] up to and including zones[depth-1], is the zone/subzone to * operate on at that index's level of the tree. * To operate on a top-level zone, only zones[0] needs to be set and "depth" must be 1. * To operate on a subzone of a top-level zone, zones[0] must be set to the top-level zone index, zones[1] must be set * to the subzone index, and "depth" must be 2. * The parameter must not be NULL. * * The "name" parameters also must not be NULL, and their "size" must be at least 2 characters. * * @author Connor Imes * @date 2017-08-24 */ #ifndef _POWERCAP_SYSFS_H #define _POWERCAP_SYSFS_H #ifdef __cplusplus extern "C" { #endif #include #include /** * Determine if a a control type exists. * * @param control_type * @return 0 if control type exists, a negative error code otherwise. */ int powercap_sysfs_control_type_exists(const char* control_type); /** * Determine if a zone exists. * * @param control_type * @param zones * @param depth * @return 0 if zone exists, a negative error code otherwise. */ int powercap_sysfs_zone_exists(const char* control_type, const uint32_t* zones, uint32_t depth); /** * Determine if a constraint exists. * * @param control_type * @param zones * @param depth * @param constraint * @return 0 if constraint exists, a negative error code otherwise. */ int powercap_sysfs_constraint_exists(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint); /** * Enable/disable a control type. * * @param control_type * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_control_type_set_enabled(const char* control_type, uint32_t val); /** * Get whether a control type is enabled or disabled. * * @param control_type * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_control_type_get_enabled(const char* control_type, uint32_t* val); /** * Get max_energy_range_uj for a zone. * * @param control_type * @param zones * @param depth * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_zone_get_max_energy_range_uj(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val); /** * Reset energy_uj for a zone. * * @param control_type * @param zones * @param depth * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_zone_reset_energy_uj(const char* control_type, const uint32_t* zones, uint32_t depth); /** * Get energy_uj for a zone. * * @param control_type * @param zones * @param depth * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_zone_get_energy_uj(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val); /** * Get max_power_range_uw for a zone. * * @param control_type * @param zones * @param depth * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_zone_get_max_power_range_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val); /** * Get power_uw for a zone. * * @param control_type * @param zones * @param depth * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_zone_get_power_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val); /** * Enable/disable a zone. * * @param control_type * @param zones * @param depth * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_zone_set_enabled(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t val); /** * Get whether a zone is enabled or disabled. * * @param control_type * @param zones * @param depth * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_zone_get_enabled(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t* val); /** * Get name for a zone. * * @param control_type * @param zones * @param depth * @param buf * @param size * @return number of bytes read (always > 0), a negative error code otherwise. */ ssize_t powercap_sysfs_zone_get_name(const char* control_type, const uint32_t* zones, uint32_t depth, char* buf, size_t size); /** * Set power_limit_uw for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_constraint_set_power_limit_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t val); /** * Get power_limit_uw for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_constraint_get_power_limit_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val); /** * Set time_window_us for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_constraint_set_time_window_us(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t val); /** * Get time_window_us for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_constraint_get_time_window_us(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val); /** * Get max_power_uw for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_constraint_get_max_power_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val); /** * Get get_min_power_uw for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_constraint_get_min_power_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val); /** * Get max_time_window_us for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_constraint_get_max_time_window_us(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val); /** * Get min_time_window_us for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param val * @return 0 on success, a negative error code otherwise. */ int powercap_sysfs_constraint_get_min_time_window_us(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val); /** * Get name for a constraint. * * @param control_type * @param zones * @param depth * @param constraint * @param buf * @param size * @return number of bytes read (always > 0), a negative error code otherwise. */ ssize_t powercap_sysfs_constraint_get_name(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, char* buf, size_t size); #ifdef __cplusplus } #endif #endif powercap-0.6.0/inc/powercap.h000066400000000000000000000174161423746651500161250ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * A simple interface for configuring powercaps using sysfs. * Unless otherwise stated, parameters are never allowed to be NULL. * Unless otherwise stated, all functions return 0 on success or a negative value on error. * * These operations do basic file I/O. * It is expected that callers handle I/O errors. * Setter functions do not verify that written values are actually accepted by the kernel. * * @author Connor Imes * @date 2016-06-01 */ #ifndef _POWERCAP_H_ #define _POWERCAP_H_ #ifdef __cplusplus extern "C" { #endif #include #include /** * File descriptors for a control type. */ typedef struct powercap_control_type { int enabled; } powercap_control_type; /** * File descriptors for a zone. */ typedef struct powercap_zone { int max_energy_range_uj; int energy_uj; int max_power_range_uw; int power_uw; int enabled; int name; } powercap_zone; /** * File descriptors for a constraint. */ typedef struct powercap_constraint { int power_limit_uw; int time_window_us; int max_power_uw; int min_power_uw; int max_time_window_us; int min_time_window_us; int name; } powercap_constraint; /** * Control type file enumeration. */ typedef enum powercap_control_type_file { POWERCAP_CONTROL_TYPE_FILE_ENABLED } powercap_control_type_file; /** * Zone file enumeration. */ typedef enum powercap_zone_file { POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ, POWERCAP_ZONE_FILE_ENERGY_UJ, POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW, POWERCAP_ZONE_FILE_POWER_UW, POWERCAP_ZONE_FILE_ENABLED, POWERCAP_ZONE_FILE_NAME } powercap_zone_file; /** * Constraint file enumeration. */ typedef enum powercap_constraint_file { POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW, POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US, POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW, POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW, POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US, POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US, POWERCAP_CONSTRAINT_FILE_NAME } powercap_constraint_file; /** * Get the filename for a control type file type. * Return is like snprintf, except if the output was truncated due to the size limit, the return value is still > size, * but not necessarily the number of characters (excluding the terminating null byte) which would have been written to * the final string if enough space had been available. * Returns a negative value in case of other error. */ int powercap_control_type_file_get_name(powercap_control_type_file type, char* buf, size_t size); /** * Get the filename for a zone file type. * Return is like snprintf, except if the output was truncated due to the size limit, the return value is still > size, * but not necessarily the number of characters (excluding the terminating null byte) which would have been written to * the final string if enough space had been available. * Returns a negative value in case of other error. */ int powercap_zone_file_get_name(powercap_zone_file type, char* buf, size_t size); /** * Get the filename for a constraint file type. * Return is like snprintf, except if the output was truncated due to the size limit, the return value is still > size, * but not necessarily the number of characters (excluding the terminating null byte) which would have been written to * the final string if enough space had been available. * Returns a negative value in case of other error. */ int powercap_constraint_file_get_name(powercap_constraint_file type, uint32_t constraint, char* buf, size_t size); /** * Open a control type file. * Returns the file descriptor from the open function and assigns it to the powercap_control_type (if not NULL). * Also returns a negative value in case of other errors, like bad parameters. */ int powercap_control_type_file_open(powercap_control_type* control, powercap_control_type_file type, const char* control_type_name, int flags); /** * Open a zone file. * Returns the file descriptor from the open function and assigns it to the powercap_zone (if not NULL). * Also returns a negative value in case of other errors, like bad parameters. */ int powercap_zone_file_open(powercap_zone* zone, powercap_zone_file type, const char* control_type_name, const uint32_t* zones, uint32_t depth, int flags); /** * Open a constraint file. * Returns the file descriptor from the open function and assigns it to the powercap_constraint (if not NULL). * Also returns a negative value in case of other errors, like bad parameters. */ int powercap_constraint_file_open(powercap_constraint* constraint, powercap_constraint_file type, const char* control_type_name, const uint32_t* zones, uint32_t depth, uint32_t constraint_num, int flags); /** * Set the control type's enabled value. */ int powercap_control_type_set_enabled(const powercap_control_type* control, int val); /** * Get the control type's enabled value. */ int powercap_control_type_get_enabled(const powercap_control_type* control, int* val); /** * Get the zone's maximum energy range in microjoules. */ int powercap_zone_get_max_energy_range_uj(const powercap_zone* zone, uint64_t* val); /** * Get the zone's current energy in microjoules. */ int powercap_zone_get_energy_uj(const powercap_zone* zone, uint64_t* val); /** * Reset the zone's energy_uj value to 0. */ int powercap_zone_reset_energy_uj(const powercap_zone* zone); /** * Get the zone's maximum power range in microwatts. */ int powercap_zone_get_max_power_range_uw(const powercap_zone* zone, uint64_t* val); /** * Get the zone's current power in microwatts. */ int powercap_zone_get_power_uw(const powercap_zone* zone, uint64_t* val); /** * Set the zone's enabled value. */ int powercap_zone_set_enabled(const powercap_zone* zone, int val); /** * Get the zone's enabled value. */ int powercap_zone_get_enabled(const powercap_zone* zone, int* val); /** * Get the zone's name. * (There does not appear to be a get_name for zones defined in powercap, but we see it in sysfs anyway.) * Returns a non-negative value for the number of bytes read, a negative value in case of error. */ ssize_t powercap_zone_get_name(const powercap_zone* zone, char* buf, size_t size); /** * Set the constraint's current power limit in microwatts. */ int powercap_constraint_set_power_limit_uw(const powercap_constraint* constraint, uint64_t val); /** * Get the constraint's current power limit in microwatts. */ int powercap_constraint_get_power_limit_uw(const powercap_constraint* constraint, uint64_t* val); /** * Set the constraint's current time window in microseconds. */ int powercap_constraint_set_time_window_us(const powercap_constraint* constraint, uint64_t val); /** * Get the constraint's current time window in microseconds. */ int powercap_constraint_get_time_window_us(const powercap_constraint* constraint, uint64_t* val); /** * Get the constraint's maximum power in microwatts. */ int powercap_constraint_get_max_power_uw(const powercap_constraint* constraint, uint64_t* val); /** * Get the constraint's minimum power in microwatts. */ int powercap_constraint_get_min_power_uw(const powercap_constraint* constraint, uint64_t* val); /** * Get the constraint's maximum time window in microseconds. */ int powercap_constraint_get_max_time_window_us(const powercap_constraint* constraint, uint64_t* val); /** * Get the constraint's minimum time window in microseconds. */ int powercap_constraint_get_min_time_window_us(const powercap_constraint* constraint, uint64_t* val); /** * Get the constraint's name. * Returns a non-negative value for the number of bytes read, a negative value in case of error. */ ssize_t powercap_constraint_get_name(const powercap_constraint* constraint, char* buf, size_t size); #ifdef __cplusplus } #endif #endif powercap-0.6.0/pkgconfig.in000066400000000000000000000005001423746651500156440ustar00rootroot00000000000000prefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${PKG_CONFIG_EXEC_PREFIX} includedir=${PKG_CONFIG_INCLUDEDIR} libdir=${PKG_CONFIG_LIBDIR} Name: ${PKG_CONFIG_NAME} Description: ${PKG_CONFIG_DESCRIPTION} Version: ${PROJECT_VERSION} Cflags: ${PKG_CONFIG_CFLAGS} Libs: ${PKG_CONFIG_LIBS} Libs.private: ${PKG_CONFIG_LIBS_PRIVATE}powercap-0.6.0/src/000077500000000000000000000000001423746651500141415ustar00rootroot00000000000000powercap-0.6.0/src/powercap-common.c000066400000000000000000000321111423746651500174110ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Common functions. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include #include #include #include #include #include #include /* Main powercap header only used for enums */ #include "powercap.h" #include "powercap-common.h" #define MAX_U64_SIZE 24 #ifdef USE_VIRTUAL_DEVICES #define POWERCAP_PATH "/sys/devices/virtual/powercap" #else #define POWERCAP_PATH "/sys/class/powercap" #endif /* These enums MUST align with powercap_control_type_file in powercap.h */ static const char* CONTROL_TYPE_FILE[] = { "enabled" }; /* These enums MUST align with powercap_zone_file in powercap.h */ static const char* ZONE_FILE[] = { "max_energy_range_uj", "energy_uj", "max_power_range_uw", "power_uw", "enabled", "name" }; /* These enums MUST align with powercap_constraint_file in powercap.h */ static const char* CONSTRAINT_FILE_SUFFIX[] = { "power_limit_uw", "time_window_us", "max_power_uw", "min_power_uw", "max_time_window_us", "min_time_window_us", "name" }; ssize_t read_string_safe(int fd, char* buf, size_t size) { ssize_t ret; if ((ret = pread(fd, buf, size - 1, 0)) > 0) { /* force a terminating character in the buffer */ if (buf[ret - 1] == '\n') { /* also remove newline character */ buf[ret - 1] = '\0'; } else { buf[ret] = '\0'; } } else if (ret < 0) { ret = -errno; } else { errno = ENODATA; ret = -errno; } return ret; } ssize_t read_string(int fd, char* buf, size_t size) { if (!buf) { errno = EINVAL; return (ssize_t) -errno; } else if (!size) { errno = ENOBUFS; return (ssize_t) -errno; } return read_string_safe(fd, buf, size); } int read_u64(int fd, uint64_t* val) { char buf[MAX_U64_SIZE]; char* end; if (!val) { errno = EINVAL; } else if (read_string_safe(fd, buf, sizeof(buf)) > 0) { errno = 0; *val = strtoull(buf, &end, 0); if (buf != end && errno != ERANGE) { return 0; } } return -errno; } int write_u64(int fd, uint64_t val) { char buf[MAX_U64_SIZE]; ssize_t written; snprintf(buf, sizeof(buf), "%"PRIu64, val); if ((written = pwrite(fd, buf, sizeof(buf), 0)) < 0) { return -errno; } if (!written) { /* Is there a better error code? */ errno = EIO; return -errno; } return 0; } int is_valid_control_type(const char* control_type) { return control_type && strlen(control_type) && strcspn(control_type, "./") == strlen(control_type); } int snprintf_base_path(char* buf, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth) { int w; int tot; uint32_t i; uint32_t j; if ((tot = snprintf(buf, size, POWERCAP_PATH"/%s/", control_type)) < 0) { return tot; } for (j = 1; j <= depth; j++) { if ((size_t) tot >= size) { return size + 1; // strictly > size since there was still more work to do } if ((w = snprintf(buf + (size_t) tot, size - (size_t) tot, "%s", control_type)) < 0) { return w; } tot += w; if ((size_t) tot >= size) { return size + 1; // strictly > size since there was still more work to do } for (i = 0; i < j && (size_t) tot < size; i++, tot += w) { if ((w = snprintf(buf + (size_t) tot, size - (size_t) tot, ":%x", zones[i])) < 0) { return w; } } if ((size_t) tot >= size) { return size + 1; // strictly > size since there was still more work to do } buf[tot++] = '/'; } if ((size_t) tot < size) { buf[tot] = '\0'; } return tot; } int snprintf_control_type_file(char* buf, size_t size, powercap_control_type_file type) { return snprintf(buf, size, "%s", CONTROL_TYPE_FILE[type]); } int snprintf_zone_file(char* buf, size_t size, powercap_zone_file type) { return snprintf(buf, size, "%s", ZONE_FILE[type]); } int snprintf_constraint_file(char* buf, size_t size, powercap_constraint_file type, uint32_t constraint) { return snprintf(buf, size, "constraint_%"PRIu32"_%s", constraint, CONSTRAINT_FILE_SUFFIX[type]); } int snprintf_control_type_file_path(char* path, size_t size, const char* control_type, powercap_control_type_file type) { int tot; int w; if ((tot = snprintf_base_path(path, size, control_type, NULL, 0)) < 0) { return tot; } if ((size_t) tot >= size) { return size + 1; // strictly > size since there was still more work to do } if ((w = snprintf_control_type_file(path + (size_t) tot, size - (size_t) tot, type)) < 0) { return w; } return tot + w; } int snprintf_zone_file_path(char* path, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth, powercap_zone_file type) { int tot; int w; if ((tot = snprintf_base_path(path, size, control_type, zones, depth)) < 0) { return tot; } if ((size_t) tot >= size) { return size + 1; // strictly > size since there was still more work to do } if ((w = snprintf_zone_file(path + (size_t) tot, size - (size_t) tot, type)) < 0) { return w; } return tot + w; } int snprintf_constraint_file_path(char* path, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type) { int tot; int w; if ((tot = snprintf_base_path(path, size, control_type, zones, depth)) < 0) { return tot; } if ((size_t) tot >= size) { return size + 1; // strictly > size since there was still more work to do } if ((w = snprintf_constraint_file(path + tot, size - (size_t) tot, type, constraint)) < 0) { return w; } return tot + w; } int open_control_type_file(char* path, size_t size, const char* control_type, powercap_control_type_file type, int flags) { int w = snprintf_control_type_file_path(path, size, control_type, type); if (w < 0) { // POSIX says snprintf should only fail if size > INT_MAX, which it's not, so this code branch should never run // If we're here, we don't even know what the error should be, so assert that errno is set assert(errno); return w; } if ((size_t) w >= size) { errno = ENOBUFS; return -1; } return open(path, flags); } int open_zone_file(char* path, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth, powercap_zone_file type, int flags) { int w = snprintf_zone_file_path(path, size, control_type, zones, depth, type); if (w < 0) { // POSIX says snprintf should only fail if size > INT_MAX, which it's not, so this code branch should never run // If we're here, we don't even know what the error should be, so assert that errno is set assert(errno); return w; } if ((size_t) w >= size) { errno = ENOBUFS; return -1; } return open(path, flags); } int open_constraint_file(char* path, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type, int flags) { int w = snprintf_constraint_file_path(path, size, control_type, zones, depth, constraint, type); if (w < 0) { // POSIX says snprintf should only fail if size > INT_MAX, which it's not, so this code branch should never run // If we're here, we don't even know what the error should be, so assert that errno is set assert(errno); return w; } if ((size_t) w >= size) { errno = ENOBUFS; return -1; } return open(path, flags); } // like open(2), but returns 0 on ENOENT (No such file or directory) static int maybe_open_control_type_file(char* buf, size_t bsize, const char* ct_name, powercap_control_type_file type, int flags) { int fd = open_control_type_file(buf, bsize, ct_name, type, flags); return (fd < 0 && errno == ENOENT) ? 0 : fd; } // like open(2), but returns 0 on ENOENT (No such file or directory) static int maybe_open_zone_file(char* buf, size_t bsize, const char* ct_name, const uint32_t* zones, uint32_t depth, powercap_zone_file type, int flags) { int fd = open_zone_file(buf, bsize, ct_name, zones, depth, type, flags); return (fd < 0 && errno == ENOENT) ? 0 : fd; } // like open(2), but returns 0 on ENOENT (No such file or directory) static int maybe_open_constraint_file(char* buf, size_t bsize, const char* ct_name, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type, int flags) { int fd = open_constraint_file(buf, bsize, ct_name, zones, depth, constraint, type, flags); return (fd < 0 && errno == ENOENT) ? 0 : fd; } int powercap_control_type_open(powercap_control_type* pct, char* buf, size_t bsize, const char* ct_name, int ro) { return ((pct->enabled = maybe_open_control_type_file(buf, bsize, ct_name, POWERCAP_CONTROL_TYPE_FILE_ENABLED, ro ? O_RDONLY : O_RDWR)) < 0) ? -1 : 0; } int powercap_zone_open(powercap_zone* pz, char* buf, size_t bsize, const char* ct_name, const uint32_t* zones, uint32_t depth, int ro) { return ((pz->max_energy_range_uj = maybe_open_zone_file(buf, bsize, ct_name, zones, depth, POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ, O_RDONLY)) < 0) || // special case for energy_uj - it's allowed to be either RW or RO ( ((pz->energy_uj = maybe_open_zone_file(buf, bsize, ct_name, zones, depth, POWERCAP_ZONE_FILE_ENERGY_UJ, ro ? O_RDONLY : O_RDWR)) < 0) && (ro || ((pz->energy_uj = maybe_open_zone_file(buf, bsize, ct_name, zones, depth, POWERCAP_ZONE_FILE_ENERGY_UJ, O_RDONLY)) < 0)) ) || ((pz->max_power_range_uw = maybe_open_zone_file(buf, bsize, ct_name, zones, depth, POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW, O_RDONLY)) < 0) || ((pz->power_uw = maybe_open_zone_file(buf, bsize, ct_name, zones, depth, POWERCAP_ZONE_FILE_POWER_UW, O_RDONLY)) < 0) || ((pz->enabled = maybe_open_zone_file(buf, bsize, ct_name, zones, depth, POWERCAP_ZONE_FILE_ENABLED, ro ? O_RDONLY : O_RDWR)) < 0) || ((pz->name = maybe_open_zone_file(buf, bsize, ct_name, zones, depth, POWERCAP_ZONE_FILE_NAME, O_RDONLY)) < 0) ? -1 : 0; } int powercap_constraint_open(powercap_constraint* pc, char* buf, size_t bsize, const char* ct_name, const uint32_t* zones, uint32_t depth, uint32_t constraint, int ro) { return ((pc->power_limit_uw = maybe_open_constraint_file(buf, bsize, ct_name, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW, ro ? O_RDONLY : O_RDWR)) < 0) || ((pc->time_window_us = maybe_open_constraint_file(buf, bsize, ct_name, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US, ro ? O_RDONLY : O_RDWR)) < 0) || ((pc->max_power_uw = maybe_open_constraint_file(buf, bsize, ct_name, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW, O_RDONLY)) < 0) || ((pc->min_power_uw = maybe_open_constraint_file(buf, bsize, ct_name, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW, O_RDONLY)) < 0) || ((pc->max_time_window_us = maybe_open_constraint_file(buf, bsize, ct_name, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US, O_RDONLY)) < 0) || ((pc->min_time_window_us = maybe_open_constraint_file(buf, bsize, ct_name, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US, O_RDONLY)) < 0) || ((pc->name = maybe_open_constraint_file(buf, bsize, ct_name, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_NAME, O_RDONLY)) < 0) ? -1 : 0; } static int powercap_close(int fd) { return (fd > 0 && close(fd)) ? -1 : 0; } int powercap_control_type_close(powercap_control_type* pct) { return powercap_close(pct->enabled); } int powercap_zone_close(powercap_zone* pz) { int rc = 0; rc |= powercap_close(pz->max_energy_range_uj); rc |= powercap_close(pz->energy_uj); rc |= powercap_close(pz->max_power_range_uw); rc |= powercap_close(pz->power_uw); rc |= powercap_close(pz->enabled); rc |= powercap_close(pz->name); return rc; } int powercap_constraint_close(powercap_constraint* pc) { int rc = 0; rc |= powercap_close(pc->power_limit_uw); rc |= powercap_close(pc->time_window_us); rc |= powercap_close(pc->max_power_uw); rc |= powercap_close(pc->min_power_uw); rc |= powercap_close(pc->max_time_window_us); rc |= powercap_close(pc->min_time_window_us); rc |= powercap_close(pc->name); return rc; } powercap-0.6.0/src/powercap-common.h000066400000000000000000000123521423746651500174230ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Common utilities, like logging. * * @author Connor Imes * @date 2017-05-09 */ #ifndef _POWERCAP_COMMON_H_ #define _POWERCAP_COMMON_H_ #ifdef __cplusplus extern "C" { #endif #include #include /* Main powercap header only used for enums */ #include "powercap.h" #pragma GCC visibility push(hidden) typedef enum powercap_loglevel { DEBUG = 0, INFO, WARN, ERROR, OFF, } powercap_loglevel; #ifndef POWERCAP_LOG_LEVEL #define POWERCAP_LOG_LEVEL WARN #endif #define TO_FILE(severity) (severity) >= WARN ? stderr : stdout #define TO_LOG_PREFIX(severity) \ (severity) == DEBUG ? "[DEBUG]" : \ (severity) == INFO ? "[INFO] " : \ (severity) == WARN ? "[WARN] " : \ "[ERROR]" #define LOG(severity, ...) \ do { if ((severity) >= POWERCAP_LOG_LEVEL) { \ fprintf(TO_FILE((severity)), "%s [powercap] ", TO_LOG_PREFIX((severity))); \ fprintf(TO_FILE((severity)), __VA_ARGS__); \ } } while (0) /* PATH_MAX should be defined in limits.h */ #ifndef PATH_MAX #pragma message("Warning: PATH_MAX was not defined") #define PATH_MAX 4096 #endif /* buf must not be NULL and size >= 1 */ ssize_t read_string_safe(int fd, char* buf, size_t size); /* Return number of bytes read (including terminating NULL char) on success, negative error code on failure */ ssize_t read_string(int fd, char* buf, size_t size); /* Return 0 on success, negative error code on failure */ int read_u64(int fd, uint64_t* val); /* Return 0 on success, negative error code on failure */ int write_u64(int fd, uint64_t val); /* Simple names only, trying to look outside the powercap directory is not allowed */ int is_valid_control_type(const char* control_type); /* * Return is like snprintf, except if the output was truncated due to the size limit, the return value is still > size, * but not necessarily the number of characters (excluding the terminating null byte) which would have been written to * the final string if enough space had been available. */ int snprintf_base_path(char* buf, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth); /* Return is like snprintf */ int snprintf_control_type_file(char* buf, size_t size, powercap_control_type_file type); /* Return is like snprintf */ int snprintf_zone_file(char* buf, size_t size, powercap_zone_file type); /* Return is like snprintf */ int snprintf_constraint_file(char* buf, size_t size, powercap_constraint_file type, uint32_t constraint); /* Return is like snprintf_base_path */ int snprintf_control_type_file_path(char* path, size_t size, const char* control_type, powercap_control_type_file type); /* Return is like snprintf_base_path */ int snprintf_zone_file_path(char* path, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth, powercap_zone_file type); /* Return is like snprintf_base_path */ int snprintf_constraint_file_path(char* path, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type); /* Return fd on success, negative error code if path is too large, -1 on open failure */ int open_control_type_file(char* path, size_t size, const char* control_type, powercap_control_type_file type, int flags); /* Return fd on success, negative error code if path is too large, -1 on open failure */ int open_zone_file(char* path, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth, powercap_zone_file type, int flags); /* Return fd on success, negative error code if path is too large, -1 on open failure */ int open_constraint_file(char* path, size_t size, const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type, int flags); /* * Open all files in a control type, if they exist. * Return 0 on success or ENOENT, -1 if buf is too small or on open failure. */ int powercap_control_type_open(powercap_control_type* pct, char* buf, size_t bsize, const char* ct_name, int ro); /* * Open all files in a zone, if they exist. * Return 0 on success or ENOENT, -1 if buf is too small or on open failure. */ int powercap_zone_open(powercap_zone* pz, char* buf, size_t bsize, const char* ct_name, const uint32_t* zones, uint32_t depth, int ro); /* * Open all files in a constraint, if they exist. * Return 0 on success or ENOENT, -1 if buf is too small or on open failure. */ int powercap_constraint_open(powercap_constraint* pc, char* buf, size_t bsize, const char* ct_name, const uint32_t* zones, uint32_t depth, uint32_t constraint, int ro); /* * Close all files in a control type. * Return 0 on success, negative error code on failure. */ int powercap_control_type_close(powercap_control_type* pct); /* * Close all files in a zone. * Return 0 on success, negative error code on failure. */ int powercap_zone_close(powercap_zone* pz); /* * Close all files in a constraint. * Return 0 on success, negative error code on failure. */ int powercap_constraint_close(powercap_constraint* pc); #pragma GCC visibility pop #ifdef __cplusplus } #endif #endif powercap-0.6.0/src/powercap-rapl-sysfs.c000066400000000000000000000111301423746651500202220ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Read/write RAPL sysfs files. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include "powercap-sysfs.h" #include "powercap-rapl-sysfs.h" #define CONTROL_TYPE "intel-rapl" #define DECL_ZONES() \ uint32_t zones[2]; \ zones[0] = zone; \ zones[1] = sz; #define DEPTH() (is_sz ? 2 : 1) int rapl_sysfs_zone_exists(uint32_t zone, uint32_t sz, int is_sz) { DECL_ZONES(); return powercap_sysfs_zone_exists(CONTROL_TYPE, zones, DEPTH()); } int rapl_sysfs_pkg_exists(uint32_t zone) { return powercap_sysfs_zone_exists(CONTROL_TYPE, &zone, 1); } int rapl_sysfs_sz_exists(uint32_t zone, uint32_t sz) { DECL_ZONES(); return powercap_sysfs_zone_exists(CONTROL_TYPE, zones, 2); } int rapl_sysfs_constraint_exists(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint) { DECL_ZONES(); return powercap_sysfs_constraint_exists(CONTROL_TYPE, zones, DEPTH(), constraint); } int rapl_sysfs_zone_reset_energy_uj(uint32_t zone, uint32_t sz, int is_sz) { DECL_ZONES(); return powercap_sysfs_zone_reset_energy_uj(CONTROL_TYPE, zones, DEPTH()); } int rapl_sysfs_zone_get_max_energy_range_uj(uint32_t zone, uint32_t sz, int is_sz, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_zone_get_max_energy_range_uj(CONTROL_TYPE, zones, DEPTH(), val); } int rapl_sysfs_zone_get_energy_uj(uint32_t zone, uint32_t sz, int is_sz, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_zone_get_energy_uj(CONTROL_TYPE, zones, DEPTH(), val); } int rapl_sysfs_zone_get_max_power_range_uw(uint32_t zone, uint32_t sz, int is_sz, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_zone_get_max_power_range_uw(CONTROL_TYPE, zones, DEPTH(), val); } int rapl_sysfs_zone_get_power_uw(uint32_t zone, uint32_t sz, int is_sz, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_zone_get_power_uw(CONTROL_TYPE, zones, DEPTH(), val); } int rapl_sysfs_zone_set_enabled(uint32_t zone, uint32_t sz, int is_sz, uint32_t val) { DECL_ZONES(); return powercap_sysfs_zone_set_enabled(CONTROL_TYPE, zones, DEPTH(), val); } int rapl_sysfs_zone_get_enabled(uint32_t zone, uint32_t sz, int is_sz, uint32_t* val) { DECL_ZONES(); return powercap_sysfs_zone_get_enabled(CONTROL_TYPE, zones, DEPTH(), val); } ssize_t rapl_sysfs_zone_get_name(uint32_t zone, uint32_t sz, int is_sz, char* buf, size_t size) { DECL_ZONES(); return powercap_sysfs_zone_get_name(CONTROL_TYPE, zones, DEPTH(), buf, size); } int rapl_sysfs_constraint_set_power_limit_uw(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t val) { DECL_ZONES(); return powercap_sysfs_constraint_set_power_limit_uw(CONTROL_TYPE, zones, DEPTH(), constraint, val); } int rapl_sysfs_constraint_get_power_limit_uw(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_constraint_get_power_limit_uw(CONTROL_TYPE, zones, DEPTH(), constraint, val); } int rapl_sysfs_constraint_set_time_window_us(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t val) { DECL_ZONES(); return powercap_sysfs_constraint_set_time_window_us(CONTROL_TYPE, zones, DEPTH(), constraint, val); } int rapl_sysfs_constraint_get_time_window_us(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_constraint_get_time_window_us(CONTROL_TYPE, zones, DEPTH(), constraint, val); } int rapl_sysfs_constraint_get_max_power_uw(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_constraint_get_max_power_uw(CONTROL_TYPE, zones, DEPTH(), constraint, val); } int rapl_sysfs_constraint_get_min_power_uw(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_constraint_get_min_power_uw(CONTROL_TYPE, zones, DEPTH(), constraint, val); } int rapl_sysfs_constraint_get_max_time_window_us(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_constraint_get_max_time_window_us(CONTROL_TYPE, zones, DEPTH(), constraint, val); } int rapl_sysfs_constraint_get_min_time_window_us(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, uint64_t* val) { DECL_ZONES(); return powercap_sysfs_constraint_get_min_time_window_us(CONTROL_TYPE, zones, DEPTH(), constraint, val); } ssize_t rapl_sysfs_constraint_get_name(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, char* buf, size_t size) { DECL_ZONES(); return powercap_sysfs_constraint_get_name(CONTROL_TYPE, zones, DEPTH(), constraint, buf, size); } powercap-0.6.0/src/powercap-rapl.c000066400000000000000000000370701423746651500170700ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * RAPL implementation of powercap. * * @author Connor Imes * @date 2016-05-12 */ #include #include #include #include #include #include #include "powercap.h" #include "powercap-common.h" #include "powercap-rapl.h" #include "powercap-sysfs.h" #ifndef MAX_NAME_SIZE #define MAX_NAME_SIZE 64 #endif #define CONTROL_TYPE "intel-rapl" #define CONSTRAINT_NAME_LONG "long_term" #define CONSTRAINT_NAME_SHORT "short_term" #define ZONE_NAME_PREFIX_PKG "package" #define ZONE_NAME_CORE "core" #define ZONE_NAME_UNCORE "uncore" #define ZONE_NAME_DRAM "dram" #define ZONE_NAME_PSYS "psys" static powercap_constraint* get_constraint_by_rapl_name(powercap_rapl_zone_files* fds, const uint32_t* zones, uint32_t depth, uint32_t constraint) { assert(fds != NULL); char name[MAX_NAME_SIZE]; if (powercap_sysfs_constraint_get_name(CONTROL_TYPE, zones, depth, constraint, name, sizeof(name)) < 0) { return NULL; } if (!strncmp(name, CONSTRAINT_NAME_LONG, sizeof(CONSTRAINT_NAME_LONG))) { return &fds->constraint_long; } else if (!strncmp(name, CONSTRAINT_NAME_SHORT, sizeof(CONSTRAINT_NAME_SHORT))) { return &fds->constraint_short; } else { LOG(ERROR, "powercap-rapl: Unrecognized constraint name: %s\n", name); errno = EINVAL; } return NULL; } static int open_all(const uint32_t* zones, uint32_t depth, powercap_rapl_zone_files* fds, int ro) { assert(fds != NULL); char buf[PATH_MAX] = { 0 }; powercap_constraint* pc; uint32_t i = 0; if (powercap_zone_open(&fds->zone, buf, sizeof(buf), CONTROL_TYPE, zones, depth, ro)) { LOG(ERROR, "powercap-rapl: %s: %s\n", buf, strerror(errno)); return -errno; } // constraint 0 is supposed to be long_term and constraint 1 (if exists) should be short_term // note: never actually seen this problem, but not 100% sure it can't happen, so check anyway... while (!powercap_sysfs_constraint_exists(CONTROL_TYPE, zones, depth, i)) { if ((pc = get_constraint_by_rapl_name(fds, zones, depth, i)) == NULL) { return -errno; } // "power_limit_uw" is picked arbitrarily, but it is a required file if (pc->power_limit_uw) { if (depth == 1) { LOG(ERROR, "powercap-rapl: Duplicate constraint detected at zone: %"PRIu32"\n", zones[0]); } else { LOG(ERROR, "powercap-rapl: Duplicate constraint detected at zone: %"PRIu32":%"PRIu32"\n", zones[0], zones[1]); } errno = EINVAL; return -errno; } buf[0] = '\0'; if (powercap_constraint_open(pc, buf, sizeof(buf), CONTROL_TYPE, zones, depth, i, ro)) { LOG(ERROR, "powercap-rapl: %s: %s\n", buf, strerror(errno)); return -errno; } i++; } // powercap_sysfs_constraint_exists returns error code when constraint does not exist - make sure it's not our fault assert(errno != EINVAL); assert(errno != ENOBUFS); return 0; } static const powercap_rapl_zone_files* get_files(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone) { assert(pkg != NULL); switch (zone) { case POWERCAP_RAPL_ZONE_PACKAGE: return &pkg->pkg; case POWERCAP_RAPL_ZONE_CORE: return &pkg->core; case POWERCAP_RAPL_ZONE_UNCORE: return &pkg->uncore; case POWERCAP_RAPL_ZONE_DRAM: return &pkg->dram; case POWERCAP_RAPL_ZONE_PSYS: return &pkg->psys; default: // somebody passed a bad zone type LOG(ERROR, "powercap-rapl: Bad powercap_rapl_zone: %d\n", zone); errno = EINVAL; return NULL; } } static const powercap_zone* get_zone_files(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone) { assert(pkg != NULL); const powercap_rapl_zone_files* fds = get_files(pkg, zone); return fds == NULL ? NULL : &fds->zone; } static const powercap_constraint* get_constraint_files(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint) { assert(pkg != NULL); const powercap_rapl_zone_files* fds = get_files(pkg, zone); if (fds == NULL) { return NULL; } switch (constraint) { case POWERCAP_RAPL_CONSTRAINT_LONG: return &fds->constraint_long; case POWERCAP_RAPL_CONSTRAINT_SHORT: return &fds->constraint_short; default: // somebody passed a bad constraint type LOG(ERROR, "powercap-rapl: Bad powercap_rapl_constraint: %d\n", constraint); errno = EINVAL; return NULL; } } static int get_zone_fd(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_zone_file file) { assert(pkg != NULL); const powercap_zone* fds = get_zone_files(pkg, zone); if (fds == NULL) { return -errno; } switch (file) { case POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ: return fds->max_energy_range_uj; case POWERCAP_ZONE_FILE_ENERGY_UJ: return fds->energy_uj; case POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW: return fds->max_power_range_uw; case POWERCAP_ZONE_FILE_POWER_UW: return fds->power_uw; case POWERCAP_ZONE_FILE_ENABLED: return fds->enabled; case POWERCAP_ZONE_FILE_NAME: return fds->name; default: LOG(ERROR, "powercap-rapl: Bad powercap_zone_file: %d\n", file); errno = EINVAL; return -errno; } } static int get_constraint_fd(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, powercap_constraint_file file) { assert(pkg != NULL); const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); if (fds == NULL) { return -errno; } switch (file) { case POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW: return fds->power_limit_uw; case POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US: return fds->time_window_us; case POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW: return fds->max_power_uw; case POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW: return fds->min_power_uw; case POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US: return fds->max_time_window_us; case POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US: return fds->min_time_window_us; case POWERCAP_CONSTRAINT_FILE_NAME: return fds->name; default: LOG(ERROR, "powercap-rapl: Bad powercap_constraint_file: %d\n", file); errno = EINVAL; return -errno; } } static powercap_rapl_zone_files* get_files_by_name(powercap_rapl_pkg* pkg, const uint32_t* zones, uint32_t depth) { assert(pkg != NULL); char name[MAX_NAME_SIZE]; if (powercap_sysfs_zone_get_name(CONTROL_TYPE, zones, depth, name, sizeof(name)) < 0) { return NULL; } if (!strncmp(name, ZONE_NAME_PREFIX_PKG, sizeof(ZONE_NAME_PREFIX_PKG) - 1)) { return &pkg->pkg; } else if (!strncmp(name, ZONE_NAME_CORE, sizeof(ZONE_NAME_CORE))) { return &pkg->core; } else if (!strncmp(name, ZONE_NAME_UNCORE, sizeof(ZONE_NAME_UNCORE))) { return &pkg->uncore; } else if (!strncmp(name, ZONE_NAME_DRAM, sizeof(ZONE_NAME_DRAM))) { return &pkg->dram; } else if (!strncmp(name, ZONE_NAME_PSYS, sizeof(ZONE_NAME_PSYS))) { return &pkg->psys; } else { LOG(ERROR, "powercap-rapl: Unrecognized zone name: %s\n", name); errno = EINVAL; } return NULL; } int powercap_rapl_control_is_supported(void) { int ret = powercap_sysfs_control_type_exists(CONTROL_TYPE); return ret ? (errno == ENOSYS ? 0 : ret) : 1; } int powercap_rapl_control_is_enabled(void) { uint32_t enabled; int ret = powercap_sysfs_control_type_get_enabled(CONTROL_TYPE, &enabled); return ret ? ret : (enabled ? 1 : 0); } int powercap_rapl_control_set_enabled(int val) { return powercap_sysfs_control_type_set_enabled(CONTROL_TYPE, (uint32_t) val); } uint32_t powercap_rapl_get_num_instances(void) { uint32_t n = 0; while (!powercap_sysfs_zone_exists(CONTROL_TYPE, &n, 1)) { n++; } if (!n) { LOG(ERROR, "powercap-rapl: No top-level "CONTROL_TYPE" zones found - is its kernel module loaded?\n"); errno = ENOENT; } return n; } uint32_t powercap_rapl_get_num_packages(void) { return powercap_rapl_get_num_instances(); } int powercap_rapl_init(uint32_t id, powercap_rapl_pkg* pkg, int read_only) { int ret; int err_save; uint32_t zones[2] = { id, 0 }; powercap_rapl_zone_files* files; if (pkg == NULL) { errno = EINVAL; return -errno; } // first need the parent zone if ((files = get_files_by_name(pkg, zones, 1)) == NULL) { return -errno; } // force all fds to 0 so we don't try to operate on invalid descriptors memset(pkg, 0, sizeof(powercap_rapl_pkg)); // first populate parent zone if (!(ret = open_all(zones, 1, files, read_only))) { // get subordinate power zones while(!powercap_sysfs_zone_exists(CONTROL_TYPE, zones, 2) && !ret) { if ((files = get_files_by_name(pkg, zones, 2)) == NULL) { ret = -errno; } else if (files->zone.name) { // zone has already been opened ("name" is picked arbitrarily, but it is a required file) LOG(ERROR, "powercap-rapl: Duplicate zone type detected at %"PRIu32":%"PRIu32"\n", zones[0], zones[1]); errno = EBUSY; ret = -errno; } else { ret = open_all(zones, 2, files, read_only); zones[1]++; } } } if (ret) { err_save = errno; powercap_rapl_destroy(pkg); errno = err_save; } return ret; } static int fds_destroy_all(powercap_rapl_zone_files* files) { assert(files != NULL); int ret = 0; ret |= powercap_zone_close(&files->zone); ret |= powercap_constraint_close(&files->constraint_long); ret |= powercap_constraint_close(&files->constraint_short); return ret; } int powercap_rapl_destroy(powercap_rapl_pkg* pkg) { int ret = 0; if (pkg != NULL) { ret |= fds_destroy_all(&pkg->pkg); ret |= fds_destroy_all(&pkg->core); ret |= fds_destroy_all(&pkg->uncore); ret |= fds_destroy_all(&pkg->dram); ret |= fds_destroy_all(&pkg->psys); } return ret; } int powercap_rapl_is_zone_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone) { // POWERCAP_ZONE_FILE_NAME is picked arbitrarily, but it is a required file return powercap_rapl_is_zone_file_supported(pkg, zone, POWERCAP_ZONE_FILE_NAME); } int powercap_rapl_is_constraint_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint) { // POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW is picked arbitrarily, but it is a required file return powercap_rapl_is_constraint_file_supported(pkg, zone, constraint, POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW); } int powercap_rapl_is_zone_file_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_zone_file file) { int fd; if (pkg == NULL || (fd = get_zone_fd(pkg, zone, file)) < 0) { errno = EINVAL; return -errno; } return fd > 0 ? 1 : 0; } int powercap_rapl_is_constraint_file_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, powercap_constraint_file file) { int fd; if (pkg == NULL || (fd = get_constraint_fd(pkg, zone, constraint, file)) < 0) { errno = EINVAL; return -errno; } return fd > 0 ? 1 : 0; } ssize_t powercap_rapl_get_name(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, char* buf, size_t size) { const powercap_zone* fds = get_zone_files(pkg, zone); return fds == NULL ? -errno : powercap_zone_get_name(fds, buf, size); } int powercap_rapl_is_enabled(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone) { int enabled = -1; int ret; const powercap_zone* fds = get_zone_files(pkg, zone); if (fds == NULL) { enabled = -errno; } else if ((ret = powercap_zone_get_enabled(fds, &enabled))) { enabled = ret; } return enabled; } int powercap_rapl_set_enabled(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, int enabled) { const powercap_zone* fds = get_zone_files(pkg, zone); return fds == NULL ? -errno : powercap_zone_set_enabled(fds, enabled); } int powercap_rapl_get_max_energy_range_uj(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, uint64_t* val) { const powercap_zone* fds = get_zone_files(pkg, zone); return fds == NULL ? -errno : powercap_zone_get_max_energy_range_uj(fds, val); } int powercap_rapl_get_energy_uj(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, uint64_t* val) { const powercap_zone* fds = get_zone_files(pkg, zone); return fds == NULL ? -errno : powercap_zone_get_energy_uj(fds, val); } int powercap_rapl_reset_energy_uj(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone) { const powercap_zone* fds = get_zone_files(pkg, zone); return fds == NULL ? -errno : powercap_zone_reset_energy_uj(fds); } int powercap_rapl_get_max_power_range_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, uint64_t* val) { const powercap_zone* fds = get_zone_files(pkg, zone); return fds == NULL ? -errno : powercap_zone_get_max_power_range_uw(fds, val); } int powercap_rapl_get_power_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, uint64_t* val) { const powercap_zone* fds = get_zone_files(pkg, zone); return fds == NULL ? -errno : powercap_zone_get_power_uw(fds, val); } int powercap_rapl_get_max_power_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_get_max_power_uw(fds, val); } int powercap_rapl_get_min_power_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_get_min_power_uw(fds, val); } int powercap_rapl_get_power_limit_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_get_power_limit_uw(fds, val); } int powercap_rapl_set_power_limit_uw(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t val) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_set_power_limit_uw(fds, val); } int powercap_rapl_get_max_time_window_us(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_get_max_time_window_us(fds, val); } int powercap_rapl_get_min_time_window_us(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_get_min_time_window_us(fds, val); } int powercap_rapl_get_time_window_us(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t* val) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_get_time_window_us(fds, val); } int powercap_rapl_set_time_window_us(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, uint64_t val) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_set_time_window_us(fds, val); } ssize_t powercap_rapl_get_constraint_name(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint, char* buf, size_t size) { const powercap_constraint* fds = get_constraint_files(pkg, zone, constraint); return fds == NULL ? -errno : powercap_constraint_get_name(fds, buf, size); } powercap-0.6.0/src/powercap-sysfs.c000066400000000000000000000247621423746651500173050ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Read/write powercap sysfs files. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include #include #include #include #include #include #include #include /* Main powercap header only used for enums, not functions! */ #include "powercap.h" #include "powercap-common.h" #include "powercap-sysfs.h" static int control_type_read_u64(const char* control_type, uint64_t* val, powercap_control_type_file type) { char path[PATH_MAX]; int ret; int fd; if (!is_valid_control_type(control_type)) { errno = EINVAL; return -errno; } if ((fd = open_control_type_file(path, sizeof(path), control_type, type, O_RDONLY)) < 0) { return -errno; } ret = read_u64(fd, val); close(fd); return ret; } static int zone_read_u64(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val, powercap_zone_file type) { char path[PATH_MAX]; int ret; int fd; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if ((fd = open_zone_file(path, sizeof(path), control_type, zones, depth, type, O_RDONLY)) < 0) { return -errno; } ret = read_u64(fd, val); close(fd); return ret; } static int constraint_read_u64(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val, powercap_constraint_file type) { char path[PATH_MAX]; int ret; int fd; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if ((fd = open_constraint_file(path, sizeof(path), control_type, zones, depth, constraint, type, O_RDONLY)) < 0) { return -errno; } ret = read_u64(fd, val); close(fd); return ret; } static int constraint_write_u64(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t val, powercap_constraint_file type) { char path[PATH_MAX]; int ret; int fd; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if ((fd = open_constraint_file(path, sizeof(path), control_type, zones, depth, constraint, type, O_WRONLY)) < 0) { return -errno; } ret = write_u64(fd, val); close(fd); return ret; } int powercap_sysfs_control_type_exists(const char* control_type) { return powercap_sysfs_zone_exists(control_type, NULL, 0); } int powercap_sysfs_zone_exists(const char* control_type, const uint32_t* zones, uint32_t depth) { char path[PATH_MAX]; struct stat ss; int w; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if ((w = snprintf_base_path(path, sizeof(path), control_type, zones, depth)) < 0) { // POSIX says snprintf should only fail if size > INT_MAX, which it's not, so this code branch should never run // If we're here, we don't even know what the error should be, so assert that errno is set, don't risk returning 0 assert(errno); return -1; } if ((size_t) w >= sizeof(path)) { errno = ENOBUFS; return -errno; } if (stat(path, &ss) || !S_ISDIR(ss.st_mode)) { errno = ENOSYS; return -errno; } return 0; } int powercap_sysfs_constraint_exists(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint) { char path[PATH_MAX]; struct stat ss; int w; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } /* power_limit_uw file must exist */ if ((w = snprintf_constraint_file_path(path, sizeof(path), control_type, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW)) < 0) { // POSIX says snprintf should only fail if size > INT_MAX, which it's not, so this code branch should never run // If we're here, we don't even know what the error should be, so assert that errno is set, don't risk returning 0 assert(errno); return -1; } if ((size_t) w >= sizeof(path)) { errno = ENOBUFS; return -errno; } if (stat(path, &ss) || !S_ISREG(ss.st_mode)) { errno = ENOSYS; return -errno; } return 0; } int powercap_sysfs_control_type_set_enabled(const char* control_type, uint32_t val) { char path[PATH_MAX]; int ret; int fd; if (!is_valid_control_type(control_type)) { errno = EINVAL; return -errno; } if ((fd = open_control_type_file(path, sizeof(path), control_type, POWERCAP_CONTROL_TYPE_FILE_ENABLED, O_WRONLY)) < 0) { return -errno; } ret = write_u64(fd, (uint64_t) val); close(fd); return ret; } int powercap_sysfs_control_type_get_enabled(const char* control_type, uint32_t* val) { uint64_t enabled = 0; int ret; if (!is_valid_control_type(control_type)) { errno = EINVAL; return -errno; } if (val) { if (!(ret = control_type_read_u64(control_type, &enabled, POWERCAP_CONTROL_TYPE_FILE_ENABLED))) { *val = (uint32_t) enabled; } } else { errno = EINVAL; ret = -errno; } return ret; } int powercap_sysfs_zone_get_max_energy_range_uj(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val) { return zone_read_u64(control_type, zones, depth, val, POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ); } int powercap_sysfs_zone_reset_energy_uj(const char* control_type, const uint32_t* zones, uint32_t depth) { char path[PATH_MAX]; int ret; int fd; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if ((fd = open_zone_file(path, sizeof(path), control_type, zones, depth, POWERCAP_ZONE_FILE_ENERGY_UJ, O_WRONLY)) < 0) { return -errno; } ret = write_u64(fd, 0); close(fd); return ret; } int powercap_sysfs_zone_get_energy_uj(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val) { return zone_read_u64(control_type, zones, depth, val, POWERCAP_ZONE_FILE_ENERGY_UJ); } int powercap_sysfs_zone_get_max_power_range_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val) { return zone_read_u64(control_type, zones, depth, val, POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW); } int powercap_sysfs_zone_get_power_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val) { return zone_read_u64(control_type, zones, depth, val, POWERCAP_ZONE_FILE_POWER_UW); } int powercap_sysfs_zone_set_enabled(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t val) { char path[PATH_MAX]; int ret; int fd; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if ((fd = open_zone_file(path, sizeof(path), control_type, zones, depth, POWERCAP_ZONE_FILE_ENABLED, O_WRONLY)) < 0) { return -errno; } ret = write_u64(fd, (uint64_t) val); close(fd); return ret; } int powercap_sysfs_zone_get_enabled(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t* val) { uint64_t enabled = 0; int ret; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if (val) { if (!(ret = zone_read_u64(control_type, zones, depth, &enabled, POWERCAP_ZONE_FILE_ENABLED))) { *val = (uint32_t) enabled; } } else { errno = EINVAL; ret = -errno; } return ret; } ssize_t powercap_sysfs_zone_get_name(const char* control_type, const uint32_t* zones, uint32_t depth, char* buf, size_t size) { char path[PATH_MAX]; ssize_t ret; int fd; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if ((fd = open_zone_file(path, sizeof(path), control_type, zones, depth, POWERCAP_ZONE_FILE_NAME, O_RDONLY)) < 0) { return -errno; } ret = read_string(fd, buf, size); close(fd); return ret; } int powercap_sysfs_constraint_set_power_limit_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t val) { return constraint_write_u64(control_type, zones, depth, constraint, val, POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW); } int powercap_sysfs_constraint_get_power_limit_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val) { return constraint_read_u64(control_type, zones, depth, constraint, val, POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW); } int powercap_sysfs_constraint_set_time_window_us(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t val) { return constraint_write_u64(control_type, zones, depth, constraint, val, POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US); } int powercap_sysfs_constraint_get_time_window_us(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val) { return constraint_read_u64(control_type, zones, depth, constraint, val, POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US); } int powercap_sysfs_constraint_get_max_power_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val) { return constraint_read_u64(control_type, zones, depth, constraint, val, POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW); } int powercap_sysfs_constraint_get_min_power_uw(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val) { return constraint_read_u64(control_type, zones, depth, constraint, val, POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW); } int powercap_sysfs_constraint_get_max_time_window_us(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val) { return constraint_read_u64(control_type, zones, depth, constraint, val, POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US); } int powercap_sysfs_constraint_get_min_time_window_us(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, uint64_t* val) { return constraint_read_u64(control_type, zones, depth, constraint, val, POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US); } ssize_t powercap_sysfs_constraint_get_name(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, char* buf, size_t size) { char path[PATH_MAX]; ssize_t ret; int fd; if (!is_valid_control_type(control_type) || (depth && !zones)) { errno = EINVAL; return -errno; } if ((fd = open_constraint_file(path, sizeof(path), control_type, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_NAME, O_RDONLY)) < 0) { return -errno; } ret = read_string(fd, buf, size); close(fd); return ret; } powercap-0.6.0/src/powercap.c000066400000000000000000000276551423746651500161440ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * I/O operations for powercap sysfs files. * * @author Connor Imes * @date 2016-06-01 */ #include #include #include #include "powercap.h" #include "powercap-common.h" int powercap_control_type_file_get_name(powercap_control_type_file type, char* buf, size_t size) { /* check type in case users pass bad int value instead of enum; int cast silences clang compiler */ if (!buf || !size || (int) type < 0 || (int) type > POWERCAP_CONTROL_TYPE_FILE_ENABLED) { errno = EINVAL; return -errno; } return snprintf_control_type_file(buf, size, type); } int powercap_zone_file_get_name(powercap_zone_file type, char* buf, size_t size) { /* check type in case users pass bad int value instead of enum; int cast silences clang compiler */ if (!buf || !size || (int) type < 0 || (int) type > POWERCAP_ZONE_FILE_NAME) { errno = EINVAL; return -errno; } return snprintf_zone_file(buf, size, type); } int powercap_constraint_file_get_name(powercap_constraint_file type, uint32_t constraint, char* buf, size_t size) { /* check type in case users pass bad int value instead of enum; int cast silences clang compiler */ if (!buf || !size || (int) type < 0 || (int) type > POWERCAP_CONSTRAINT_FILE_NAME) { errno = EINVAL; return -errno; } return snprintf_constraint_file(buf, size, type, constraint); } #if 0 /** * Get the full path to a control type if depth is 0 (in which case zones may be NULL), or a control type's zone. * Return is like snprintf, except if the output was truncated due to the size limit, the return value is still > size, * but not necessarily the number of characters (excluding the terminating null byte) which would have been written to * the final string if enough space had been available. * Returns a negative value in case of other error. */ int powercap_get_path(const char* control_type_name, const uint32_t* zones, uint32_t depth, char* buf, size_t size) { if (!is_valid_control_type(control_type_name) || !buf || !size || (depth && !zones)) { errno = EINVAL; return -errno; } return snprintf_base_path(buf, size, control_type_name, zones, depth); } /** * Get the full path to a control type file. * Return is like snprintf, except if the output was truncated due to the size limit, the return value is still > size, * but not necessarily the number of characters (excluding the terminating null byte) which would have been written to * the final string if enough space had been available. * Returns a negative value in case of other error. */ int powercap_control_type_file_get_path(powercap_control_type_file type, const char* control_type_name, char* buf, size_t size) { /* check type in case users pass bad int value instead of enum; int cast silences clang compiler */ if (!is_valid_control_type(control_type_name) || !buf || !size || (int) type < 0 || (int) type > POWERCAP_CONTROL_TYPE_FILE_ENABLED) { errno = EINVAL; return -errno; } return snprintf_control_type_file_path(buf, size, control_type_name, type); } /** * Get the full path to a zone file. * Return is like snprintf, except if the output was truncated due to the size limit, the return value is still > size, * but not necessarily the number of characters (excluding the terminating null byte) which would have been written to * the final string if enough space had been available. * Returns a negative value in case of other error. */ int powercap_zone_file_get_path(powercap_zone_file type, const char* control_type_name, const uint32_t* zones, uint32_t depth, char* buf, size_t size) { /* check type in case users pass bad int value instead of enum; int cast silences clang compiler */ if (!is_valid_control_type(control_type_name) || !buf || !size || (int) type < 0 || (int) type > POWERCAP_ZONE_FILE_NAME || (depth && !zones)) { errno = EINVAL; return -errno; } return snprintf_zone_file_path(buf, size, control_type_name, zones, depth, type); } /** * Get the full path to a constraint file. * Return is like snprintf, except if the output was truncated due to the size limit, the return value is still > size, * but not necessarily the number of characters (excluding the terminating null byte) which would have been written to * the final string if enough space had been available. * Returns a negative value in case of other error. */ int powercap_constraint_file_get_path(powercap_constraint_file type, const char* control_type_name, const uint32_t* zones, uint32_t depth, uint32_t constraint, char* buf, size_t size) { /* check type in case users pass bad int value instead of enum; int cast silences clang compiler */ if (!is_valid_control_type(control_type_name) || !buf || !size || (int) type < 0 || (int) type > POWERCAP_CONSTRAINT_FILE_NAME || (depth && !zones)) { errno = EINVAL; return -errno; } return snprintf_constraint_file_path(buf, size, control_type_name, zones, depth, constraint, type); } #endif int powercap_control_type_file_open(powercap_control_type* control, powercap_control_type_file type, const char* control_type_name, int flags) { char buf[PATH_MAX]; int fd; /* check type in case users pass bad int value instead of enum; int cast silences clang compiler */ if (!is_valid_control_type(control_type_name) || (int) type < 0 || (int) type > POWERCAP_CONTROL_TYPE_FILE_ENABLED) { errno = EINVAL; return -errno; } fd = open_control_type_file(buf, sizeof(buf), control_type_name, type, flags); if (control) { switch (type) { case POWERCAP_CONTROL_TYPE_FILE_ENABLED: control->enabled = fd; break; default: // unreachable errno = EINVAL; return -errno; } } return fd; } int powercap_zone_file_open(powercap_zone* zone, powercap_zone_file type, const char* control_type_name, const uint32_t* zones, uint32_t depth, int flags) { char buf[PATH_MAX]; int fd; /* check type in case users pass bad int value instead of enum; int cast silences clang compiler */ if (!is_valid_control_type(control_type_name) || (int) type < 0 || (int) type > POWERCAP_ZONE_FILE_NAME || (depth && !zones)) { errno = EINVAL; return -errno; } fd = open_zone_file(buf, sizeof(buf), control_type_name, zones, depth, type, flags); if (zone) { switch (type) { case POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ: zone->max_energy_range_uj = fd; break; case POWERCAP_ZONE_FILE_ENERGY_UJ: zone->energy_uj = fd; break; case POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW: zone->max_power_range_uw = fd; break; case POWERCAP_ZONE_FILE_POWER_UW: zone->power_uw = fd; break; case POWERCAP_ZONE_FILE_ENABLED: zone->enabled = fd; break; case POWERCAP_ZONE_FILE_NAME: zone->name = fd; break; default: // unreachable errno = EINVAL; return -errno; } } return fd; } int powercap_constraint_file_open(powercap_constraint* constraint, powercap_constraint_file type, const char* control_type_name, const uint32_t* zones, uint32_t depth, uint32_t constraint_num, int flags) { char buf[PATH_MAX]; int fd; if (!constraint || !is_valid_control_type(control_type_name) || (int) type < 0 || (int) type > POWERCAP_CONSTRAINT_FILE_NAME || (depth && !zones)) { errno = EINVAL; return -errno; } fd = open_constraint_file(buf, sizeof(buf), control_type_name, zones, depth, constraint_num, type, flags); if (constraint) { switch (type) { case POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW: constraint->power_limit_uw = fd; break; case POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US: constraint->time_window_us = fd; break; case POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW: constraint->max_power_uw = fd; break; case POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW: constraint->min_power_uw = fd; break; case POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US: constraint->max_time_window_us = fd; break; case POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US: constraint->min_time_window_us = fd; break; case POWERCAP_CONSTRAINT_FILE_NAME: constraint->name = fd; break; default: // unreachable errno = EINVAL; return -errno; } } return fd; } #define VERIFY_ARG(arg) \ if (!(arg)) { \ errno = EINVAL; \ return -errno; \ } int powercap_control_type_set_enabled(const powercap_control_type* control_type, int val) { VERIFY_ARG(control_type); return write_u64(control_type->enabled, (uint64_t) val); } int powercap_control_type_get_enabled(const powercap_control_type* control_type, int* val) { uint64_t enabled; int ret; VERIFY_ARG(control_type); VERIFY_ARG(val); if (!(ret = read_u64(control_type->enabled, &enabled))) { *val = enabled ? 1 : 0; } return ret; } int powercap_zone_get_max_energy_range_uj(const powercap_zone* zone, uint64_t* val) { VERIFY_ARG(zone); return read_u64(zone->max_energy_range_uj, val); } int powercap_zone_get_energy_uj(const powercap_zone* zone, uint64_t* val) { VERIFY_ARG(zone); return read_u64(zone->energy_uj, val); } int powercap_zone_reset_energy_uj(const powercap_zone* zone) { VERIFY_ARG(zone); return write_u64(zone->energy_uj, 0); } int powercap_zone_get_max_power_range_uw(const powercap_zone* zone, uint64_t* val) { VERIFY_ARG(zone); return read_u64(zone->max_power_range_uw, val); } int powercap_zone_get_power_uw(const powercap_zone* zone, uint64_t* val) { VERIFY_ARG(zone); return read_u64(zone->power_uw, val); } int powercap_zone_set_enabled(const powercap_zone* zone, int val) { VERIFY_ARG(zone); return write_u64(zone->enabled, (uint64_t) val); } int powercap_zone_get_enabled(const powercap_zone* zone, int* val) { uint64_t enabled; int ret; VERIFY_ARG(zone); VERIFY_ARG(val); if (!(ret = read_u64(zone->enabled, &enabled))) { *val = enabled ? 1 : 0; } return ret; } ssize_t powercap_zone_get_name(const powercap_zone* zone, char* buf, size_t size) { VERIFY_ARG(zone); return read_string(zone->name, buf, size); } int powercap_constraint_set_power_limit_uw(const powercap_constraint* constraint, uint64_t val) { VERIFY_ARG(constraint) return write_u64(constraint->power_limit_uw, val); } int powercap_constraint_get_power_limit_uw(const powercap_constraint* constraint, uint64_t* val) { VERIFY_ARG(constraint) return read_u64(constraint->power_limit_uw, val); } int powercap_constraint_set_time_window_us(const powercap_constraint* constraint, uint64_t val) { VERIFY_ARG(constraint) return write_u64(constraint->time_window_us, val); } int powercap_constraint_get_time_window_us(const powercap_constraint* constraint, uint64_t* val) { VERIFY_ARG(constraint) return read_u64(constraint->time_window_us, val); } int powercap_constraint_get_max_power_uw(const powercap_constraint* constraint, uint64_t* val) { VERIFY_ARG(constraint) return read_u64(constraint->max_power_uw, val); } int powercap_constraint_get_min_power_uw(const powercap_constraint* constraint, uint64_t* val) { VERIFY_ARG(constraint) return read_u64(constraint->min_power_uw, val); } int powercap_constraint_get_max_time_window_us(const powercap_constraint* constraint, uint64_t* val) { VERIFY_ARG(constraint) return read_u64(constraint->max_time_window_us, val); } int powercap_constraint_get_min_time_window_us(const powercap_constraint* constraint, uint64_t* val) { VERIFY_ARG(constraint) return read_u64(constraint->min_time_window_us, val); } ssize_t powercap_constraint_get_name(const powercap_constraint* constraint, char* buf, size_t size) { VERIFY_ARG(constraint) return read_string(constraint->name, buf, size); } powercap-0.6.0/test/000077500000000000000000000000001423746651500143315ustar00rootroot00000000000000powercap-0.6.0/test/CMakeLists.txt000066400000000000000000000014771423746651500171020ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-3-Clause macro(add_unit_test target) add_test(${target} ${target}) endmacro(add_unit_test) add_executable(powercap-common-test powercap-common-test.c ${PROJECT_SOURCE_DIR}/src/powercap-common.c) target_include_directories(powercap-common-test PRIVATE ${PROJECT_SOURCE_DIR}/inc) add_unit_test(powercap-common-test) add_executable(powercap-test powercap-test.c) target_link_libraries(powercap-test PRIVATE powercap) add_unit_test(powercap-test) add_executable(powercap-rapl-test powercap-rapl-test.c) target_link_libraries(powercap-rapl-test PRIVATE powercap) # Requires a real system with root privileges # add_unit_test(powercap-rapl-test) add_executable(powercap-sysfs-test powercap-sysfs-test.c) target_link_libraries(powercap-sysfs-test PRIVATE powercap) add_unit_test(powercap-sysfs-test) powercap-0.6.0/test/powercap-common-test.c000066400000000000000000000132151423746651500205620ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Basic unit tests for powercap-common. */ // force assertions #undef NDEBUG #include #include #include #include "powercap.h" #include "../src/powercap-common.h" #ifdef USE_VIRTUAL_DEVICES #define POWERCAP_PATH "/sys/devices/virtual/powercap" #else #define POWERCAP_PATH "/sys/class/powercap" #endif #define POWERCAP_PATH_LEN (sizeof(POWERCAP_PATH) - 1) #define CONTROL_TYPE "foo" #define CONTROL_TYPE_LEN (sizeof(CONTROL_TYPE) - 1) #define ROOT_LEN (POWERCAP_PATH_LEN + 1 + CONTROL_TYPE_LEN + 1) #define BASE_D1_LEN (ROOT_LEN + CONTROL_TYPE_LEN + 3) #define BASE_D2_LEN (BASE_D1_LEN + CONTROL_TYPE_LEN + 5) static void test_snprintf_base_path(void) { char path[PATH_MAX] = { 0 }; uint32_t zones[PATH_MAX] = { 0 }; // can produce paths that exceed PATH_MAX length int rc; // root path assert(snprintf_base_path(path, sizeof(path), CONTROL_TYPE, NULL, 0) == ROOT_LEN); assert(strncmp(path, POWERCAP_PATH"/"CONTROL_TYPE"/", sizeof(path)) == 0); // depth 1 zones[0] = 0; assert(snprintf_base_path(path, sizeof(path), CONTROL_TYPE, zones, 1) == BASE_D1_LEN); assert(strncmp(path, POWERCAP_PATH"/"CONTROL_TYPE"/"CONTROL_TYPE":0/", sizeof(path)) == 0); // depth 2 zones[0] = 0; zones[1] = 1; assert(snprintf_base_path(path, sizeof(path), CONTROL_TYPE, zones, 2) == BASE_D2_LEN); assert(strncmp(path, POWERCAP_PATH"/"CONTROL_TYPE"/"CONTROL_TYPE":0/"CONTROL_TYPE":0:1/", sizeof(path)) == 0); // too long to fit in buffer rc = snprintf_base_path(path, sizeof(path), CONTROL_TYPE, zones, PATH_MAX); assert(rc >= 0 && (size_t) rc > sizeof(path)); // can't safely cast to size_t without checking >= 0 first } static void test_snprintf_control_type_file(void) { char path[PATH_MAX] = { 0 }; assert(snprintf_control_type_file(path, sizeof(path), POWERCAP_CONTROL_TYPE_FILE_ENABLED) == 7); assert(strncmp(path, "enabled", sizeof(path)) == 0); } static void test_snprintf_zone_file(void) { char path[PATH_MAX] = { 0 }; assert(snprintf_zone_file(path, sizeof(path), POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ) == 19); assert(strncmp(path, "max_energy_range_uj", sizeof(path)) == 0); assert(snprintf_zone_file(path, sizeof(path), POWERCAP_ZONE_FILE_ENERGY_UJ) == 9); assert(strncmp(path, "energy_uj", sizeof(path)) == 0); assert(snprintf_zone_file(path, sizeof(path), POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW) == 18); assert(strncmp(path, "max_power_range_uw", sizeof(path)) == 0); assert(snprintf_zone_file(path, sizeof(path), POWERCAP_ZONE_FILE_POWER_UW) == 8); assert(strncmp(path, "power_uw", sizeof(path)) == 0); assert(snprintf_zone_file(path, sizeof(path), POWERCAP_ZONE_FILE_ENABLED) == 7); assert(strncmp(path, "enabled", sizeof(path)) == 0); assert(snprintf_zone_file(path, sizeof(path), POWERCAP_ZONE_FILE_NAME) == 4); assert(strncmp(path, "name", sizeof(path)) == 0); } static void test_snprintf_constraint_file(void) { char path[PATH_MAX] = { 0 }; assert(snprintf_constraint_file(path, sizeof(path), POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW, 0) == 27); assert(strncmp(path, "constraint_0_power_limit_uw", sizeof(path)) == 0); assert(snprintf_constraint_file(path, sizeof(path), POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US, 0) == 27); assert(strncmp(path, "constraint_0_time_window_us", sizeof(path)) == 0); assert(snprintf_constraint_file(path, sizeof(path), POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW, 0) == 25); assert(strncmp(path, "constraint_0_max_power_uw", sizeof(path)) == 0); assert(snprintf_constraint_file(path, sizeof(path), POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW, 0) == 25); assert(strncmp(path, "constraint_0_min_power_uw", sizeof(path)) == 0); assert(snprintf_constraint_file(path, sizeof(path), POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US, 0) == 31); assert(strncmp(path, "constraint_0_max_time_window_us", sizeof(path)) == 0); assert(snprintf_constraint_file(path, sizeof(path), POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US, 0) == 31); assert(strncmp(path, "constraint_0_min_time_window_us", sizeof(path)) == 0); assert(snprintf_constraint_file(path, sizeof(path), POWERCAP_CONSTRAINT_FILE_NAME, 0) == 17); assert(strncmp(path, "constraint_0_name", sizeof(path)) == 0); } static void test_snprintf_control_type_file_path(void) { char path[PATH_MAX] = { 0 }; assert(snprintf_control_type_file_path(path, sizeof(path), CONTROL_TYPE, POWERCAP_CONTROL_TYPE_FILE_ENABLED) == ROOT_LEN + 7); assert(strncmp(path, POWERCAP_PATH"/"CONTROL_TYPE"/enabled", sizeof(path)) == 0); } static void test_snprintf_zone_file_path(void) { char path[PATH_MAX] = { 0 }; uint32_t zones[1] = { 0 }; // we really just need to test one type assert(snprintf_zone_file_path(path, sizeof(path), CONTROL_TYPE, zones, 1, POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ) == BASE_D1_LEN + 19); assert(strncmp(path, POWERCAP_PATH"/"CONTROL_TYPE"/"CONTROL_TYPE":0/max_energy_range_uj", sizeof(path)) == 0); } static void test_snprintf_constraint_file_path(void) { char path[PATH_MAX] = { 0 }; uint32_t zones[1] = { 0 }; // we really just need to test one type assert(snprintf_constraint_file_path(path, sizeof(path), CONTROL_TYPE, zones, 1, POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW, 0) == BASE_D1_LEN + 27); assert(strncmp(path, POWERCAP_PATH"/"CONTROL_TYPE"/"CONTROL_TYPE":0/constraint_0_power_limit_uw", sizeof(path)) == 0); } int main(void) { // We can really only test the snprintf functions in a unit test, not actual file I/O test_snprintf_base_path(); test_snprintf_control_type_file(); test_snprintf_zone_file(); test_snprintf_constraint_file(); test_snprintf_control_type_file_path(); test_snprintf_zone_file_path(); test_snprintf_constraint_file_path(); return EXIT_SUCCESS; } powercap-0.6.0/test/powercap-rapl-test.c000066400000000000000000000277611423746651500202430ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Basic tests - gets caps and sets them right back. */ #include #include #include #include #include "powercap-rapl.h" static const powercap_rapl_zone ZONES[] = { POWERCAP_RAPL_ZONE_PACKAGE, POWERCAP_RAPL_ZONE_CORE, POWERCAP_RAPL_ZONE_UNCORE, POWERCAP_RAPL_ZONE_DRAM, POWERCAP_RAPL_ZONE_PSYS }; static const uint32_t NZONES = 5; static const char* const ZONE_NAMES[] = { "Package", "Core", "Uncore", "DRAM", "PSys" }; static const powercap_rapl_constraint CONSTRAINTS[] = { POWERCAP_RAPL_CONSTRAINT_LONG, POWERCAP_RAPL_CONSTRAINT_SHORT }; static const uint32_t NCONSTRAINTS = 2; static int test_root(int ro) { int enabled; int supported = powercap_rapl_control_is_supported(); if (supported < 0) { perror("powercap_rapl_control_is_supported"); return -1; } else if (supported == 0) { printf("RAPL not supported\n"); return -1; } enabled = powercap_rapl_control_is_enabled(); if (enabled < 0) { perror("powercap_rapl_control_is_enabled"); return -1; } else { printf("RAPL enabled: %s\n", enabled > 0 ? "yes" : "no"); } if (!ro && powercap_rapl_control_set_enabled(enabled)) { perror("powercap_rapl_control_set_enabled"); } return 0; } static int test_pkg(const powercap_rapl_pkg* p, int ro) { uint32_t i, j; int supported; char name[32]; ssize_t name_ret; int enabled; uint64_t val; int ret = 0; for (i = 0; i < NZONES; i++) { supported = powercap_rapl_is_zone_supported(p, ZONES[i]); if (supported < 0) { perror("powercap_rapl_is_zone_supported"); return -1; } else if (supported == 0) { printf("%s: zone not supported\n", ZONE_NAMES[i]); continue; } supported = powercap_rapl_is_zone_file_supported(p, ZONES[i], POWERCAP_ZONE_FILE_NAME); if (supported < 0) { perror("powercap_rapl_is_zone_file_supported"); return -1; } else if (supported == 0) { printf("%s name: not supported\n", ZONE_NAMES[i]); } else { name_ret = powercap_rapl_get_name(p, ZONES[i], name, sizeof(name)); if (name_ret < 0) { perror("powercap_rapl_get_name"); return -1; } printf("%s name: %s\n", ZONE_NAMES[i], name_ret > 0 ? name : "[None]"); } supported = powercap_rapl_is_zone_file_supported(p, ZONES[i], POWERCAP_ZONE_FILE_ENABLED); if (supported < 0) { perror("powercap_rapl_is_zone_file_supported"); return -1; } else if (supported == 0) { printf("%s enabled: not supported\n", ZONE_NAMES[i]); } else { enabled = powercap_rapl_is_enabled(p, ZONES[i]); if (enabled < 0) { perror("powercap_rapl_is_enabled"); return -1; } printf("%s enabled: %s\n", ZONE_NAMES[i], enabled > 0 ? "yes" : "no"); if (!ro && powercap_rapl_set_enabled(p, ZONES[i], enabled)) { perror("powercap_rapl_set_enabled"); return -1; } } supported = powercap_rapl_is_zone_file_supported(p, ZONES[i], POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ); if (supported < 0) { perror("powercap_rapl_is_zone_file_supported"); return -1; } else if (supported == 0) { printf("%s max_energy_range_uj: not supported\n", ZONE_NAMES[i]); } else { if (powercap_rapl_get_max_energy_range_uj(p, ZONES[i], &val)) { perror("powercap_rapl_get_max_energy_range_uj"); return -1; } printf("%s max_energy_range_uj: %"PRIu64"\n", ZONE_NAMES[i], val); } supported = powercap_rapl_is_zone_file_supported(p, ZONES[i], POWERCAP_ZONE_FILE_ENERGY_UJ); if (supported < 0) { perror("powercap_rapl_is_zone_file_supported"); return -1; } else if (supported == 0) { printf("%s energy_uj: not supported\n", ZONE_NAMES[i]); } else { if (powercap_rapl_get_energy_uj(p, ZONES[i], &val)) { perror("powercap_rapl_get_energy_uj"); return -1; } printf("%s energy_uj: %"PRIu64"\n", ZONE_NAMES[i], val); // TODO: Test powercap_rapl_reset_energy_uj } supported = powercap_rapl_is_zone_file_supported(p, ZONES[i], POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW); if (supported < 0) { perror("powercap_rapl_is_zone_file_supported"); return -1; } else if (supported == 0) { printf("%s max_power_range_uw: not supported\n", ZONE_NAMES[i]); } else { if (powercap_rapl_get_max_power_range_uw(p, ZONES[i], &val)) { perror("powercap_rapl_get_max_power_range_uw"); return -1; } printf("%s max_power_range_uw: %"PRIu64"\n", ZONE_NAMES[i], val); } supported = powercap_rapl_is_zone_file_supported(p, ZONES[i], POWERCAP_ZONE_FILE_POWER_UW); if (supported < 0) { perror("powercap_rapl_is_zone_file_supported"); return -1; } else if (supported == 0) { printf("%s power_uw: not supported\n", ZONE_NAMES[i]); } else { if (powercap_rapl_get_power_uw(p, ZONES[i], &val)) { perror("powercap_rapl_get_power_uw"); return -1; } printf("%s power_uw: %"PRIu64"\n", ZONE_NAMES[i], val); } // test long and short term constraint properties for (j = 0; j < NCONSTRAINTS; j++) { const char* const cnst = CONSTRAINTS[j] == POWERCAP_RAPL_CONSTRAINT_LONG ? "long" : "short"; supported = powercap_rapl_is_constraint_supported(p, ZONES[i], CONSTRAINTS[j]); if (supported < 0) { perror("powercap_rapl_is_constraint_supported"); return -1; } else if (supported == 0) { printf("%s constraint_(%s): not supported\n", ZONE_NAMES[i], cnst); continue; } supported = powercap_rapl_is_constraint_file_supported(p, ZONES[i], CONSTRAINTS[j], POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW); if (supported < 0) { perror("powercap_rapl_is_constraint_file_supported"); return -1; } else if (supported == 0) { printf("%s constraint_(%s)_max_power_uw: not supported\n", ZONE_NAMES[i], cnst); } else { if (powercap_rapl_get_max_power_uw(p, ZONES[i], CONSTRAINTS[j], &val)) { perror("powercap_rapl_get_max_power_uw"); // TODO: powercap_rapl_get_max_power_uw fails and sets errno=ENODATA for power planes on development system... // return -1; } else { printf("%s constraint_(%s)_max_power_uw: %"PRIu64"\n", ZONE_NAMES[i], cnst, val); } } supported = powercap_rapl_is_constraint_file_supported(p, ZONES[i], CONSTRAINTS[j], POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW); if (supported < 0) { perror("powercap_rapl_is_constraint_file_supported"); return -1; } else if (supported == 0) { printf("%s constraint_(%s)_min_power_uw: not supported\n", ZONE_NAMES[i], cnst); } else { if (powercap_rapl_get_min_power_uw(p, ZONES[i], CONSTRAINTS[j], &val)) { perror("powercap_rapl_get_min_power_uw"); return -1; } else { printf("%s constraint_(%s)_min_power_uw: %"PRIu64"\n", ZONE_NAMES[i], cnst, val); } } supported = powercap_rapl_is_constraint_file_supported(p, ZONES[i], CONSTRAINTS[j], POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW); if (supported < 0) { perror("powercap_rapl_is_constraint_file_supported"); return -1; } else if (supported == 0) { printf("%s constraint_(%s)_power_limit_uw: not supported\n", ZONE_NAMES[i], cnst); } else { if (powercap_rapl_get_power_limit_uw(p, ZONES[i], CONSTRAINTS[j], &val)) { perror("powercap_rapl_get_power_limit_uw"); return -1; } else { printf("%s constraint_(%s)_power_limit_uw: %"PRIu64"\n", ZONE_NAMES[i], cnst, val); if (!ro && powercap_rapl_set_power_limit_uw(p, ZONES[i], CONSTRAINTS[j], val)) { perror("powercap_rapl_set_power_limit_uw"); ret = 1; } } } supported = powercap_rapl_is_constraint_file_supported(p, ZONES[i], CONSTRAINTS[j], POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US); if (supported < 0) { perror("powercap_rapl_is_constraint_file_supported"); return -1; } else if (supported == 0) { printf("%s constraint_(%s)_max_time_window_us: not supported\n", ZONE_NAMES[i], cnst); } else { if (powercap_rapl_get_max_time_window_us(p, ZONES[i], CONSTRAINTS[j], &val)) { perror("powercap_rapl_get_max_time_window_us"); return -1; } else { printf("%s constraint_(%s)_max_time_window_us: %"PRIu64"\n", ZONE_NAMES[i], cnst, val); } } supported = powercap_rapl_is_constraint_file_supported(p, ZONES[i], CONSTRAINTS[j], POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US); if (supported < 0) { perror("powercap_rapl_is_constraint_file_supported"); return -1; } else if (supported == 0) { printf("%s constraint_(%s)_min_time_window_us: not supported\n", ZONE_NAMES[i], cnst); } else { if (powercap_rapl_get_min_time_window_us(p, ZONES[i], CONSTRAINTS[j], &val)) { perror("powercap_rapl_get_min_time_window_us"); return -1; } else { printf("%s constraint_(%s)_min_time_window_us: %"PRIu64"\n", ZONE_NAMES[i], cnst, val); } } supported = powercap_rapl_is_constraint_file_supported(p, ZONES[i], CONSTRAINTS[j], POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US); if (supported < 0) { perror("powercap_rapl_is_constraint_file_supported"); return -1; } else if (supported == 0) { printf("%s constraint_(%s)_time_window_us: not supported\n", ZONE_NAMES[i], cnst); } else { if (powercap_rapl_get_time_window_us(p, ZONES[i], CONSTRAINTS[j], &val)) { perror("powercap_rapl_get_time_window_us"); return -1; } else { printf("%s constraint_(%s)_time_window_us: %"PRIu64"\n", ZONE_NAMES[i], cnst, val); if (!ro && powercap_rapl_set_time_window_us(p, ZONES[i], CONSTRAINTS[j], val)) { perror("powercap_rapl_set_time_window_us"); ret = 1; } } } supported = powercap_rapl_is_constraint_file_supported(p, ZONES[i], CONSTRAINTS[j], POWERCAP_CONSTRAINT_FILE_NAME); if (supported < 0) { perror("powercap_rapl_is_constraint_file_supported"); return -1; } else if (supported == 0) { printf("%s constraint_(%s)_name: not supported\n", ZONE_NAMES[i], cnst); } else { name_ret = powercap_rapl_get_constraint_name(p, ZONES[i], CONSTRAINTS[j], name, sizeof(name)); if (name_ret < 0) { perror("powercap_rapl_get_constraint_name"); return -1; } printf("%s constraint_(%s)_name: %s\n", ZONE_NAMES[i], cnst, name_ret > 0 ? name : "[None]"); } } } return ret; } // optional parameter - boolean to enable read/write int main(int argc, char** argv) { uint32_t i; int ret = 0; int ro = 1; uint32_t npackages; powercap_rapl_pkg* pkgs; if (argc > 1) { // a value other than 0 enables read/write ro = !atoi(argv[1]); } if (test_root(ro)) { return -1; } // initialize npackages = powercap_rapl_get_num_instances(); if (npackages == 0) { if (errno) { perror("powercap_rapl_get_num_instances"); } else { fprintf(stderr, "No RAPL zones found\n"); } return EXIT_FAILURE; } pkgs = malloc(npackages * sizeof(powercap_rapl_pkg)); if (pkgs == NULL) { perror("malloc"); return EXIT_FAILURE; } for (i = 0; i < npackages; i++) { if (powercap_rapl_init(i, &pkgs[i], ro)) { perror("powercap_rapl_init"); ret = EXIT_FAILURE; npackages = i; // for correct cleanup count goto cleanup; } } printf("Initialized %"PRIu32" top-level zone instance(s)\n", npackages); // test for (i = 0; i < npackages; i++) { printf("\nTest: %"PRIu32"\n", i); if (test_pkg(&pkgs[i], ro)) { ret |= EXIT_FAILURE; } } cleanup: for (i = 0; i < npackages; i++) { if (powercap_rapl_destroy(&pkgs[i])) { perror("powercap_rapl_destroy"); ret = EXIT_FAILURE; } } free(pkgs); printf("Cleaned up\n"); return ret; } powercap-0.6.0/test/powercap-sysfs-test.c000066400000000000000000000230161423746651500204410ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Tests bad parameters. * No way to test good ones without a functioning powercap implementation, which isn't guaranteed to exist. */ /* force assertions */ #undef NDEBUG #include #include #include #include #include #include "powercap-sysfs.h" /* PATH_MAX should be defined in limits.h */ #ifndef PATH_MAX #pragma message("Warning: PATH_MAX was not defined") #define PATH_MAX 4096 #endif static void test_bad_control_type_exists(void) { char buf_too_big[PATH_MAX + 1]; size_t i; /* bad params */ errno = 0; assert(powercap_sysfs_control_type_exists(NULL) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_control_type_exists("") == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_control_type_exists(".") == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_control_type_exists("/") == -EINVAL); assert(errno == EINVAL); for (i = 0; i < sizeof(buf_too_big); i++) { buf_too_big[i] = 'a'; } buf_too_big[i - 1] = '\0'; errno = 0; assert(powercap_sysfs_control_type_exists(buf_too_big) == -ENOBUFS); assert(errno == ENOBUFS); /* good param, but doesn't exist */ errno = 0; assert(powercap_sysfs_control_type_exists("foo") == -ENOSYS); assert(errno == ENOSYS); } static void test_bad_zone_exists(void) { uint32_t zones[2]; zones[0] = 0; zones[1] = 0; /* good parameters, bad control type */ errno = 0; assert(powercap_sysfs_zone_exists("foo", zones, 2) == -ENOSYS); assert(errno == ENOSYS); /* bad parameters */ errno = 0; assert(powercap_sysfs_zone_exists(NULL, zones, 2) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_exists("foo", NULL, 2) == -EINVAL); assert(errno == EINVAL); } static void test_bad_constraint_exists(void) { uint32_t zones[2]; zones[0] = 0; zones[1] = 0; /* good parameters, bad control type */ errno = 0; assert(powercap_sysfs_constraint_exists("foo", zones, 2, 0) == -ENOSYS); assert(errno == ENOSYS); /* bad parameters */ errno = 0; assert(powercap_sysfs_constraint_exists(NULL, zones, 2, 0) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_constraint_exists("foo", NULL, 2, 0) == -EINVAL); assert(errno == EINVAL); } static void test_get_set_control_type_all_bad(void) { uint32_t val32; /* Good parameters, bad control type */ errno = 0; assert(powercap_sysfs_control_type_get_enabled("foo", &val32) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_control_type_set_enabled("foo", 1) == -ENOENT); assert(errno == ENOENT); /* Bad parameters */ /* get u32 */ errno = 0; assert(powercap_sysfs_control_type_get_enabled(NULL, &val32) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_control_type_get_enabled("foo", NULL) == -EINVAL); assert(errno == EINVAL); /* set u32 */ errno = 0; assert(powercap_sysfs_control_type_set_enabled(NULL, 1) == -EINVAL); assert(errno == EINVAL); } static void test_get_set_zone_all_bad(void) { uint64_t val64; uint32_t val32; char name[32]; uint32_t zones[2]; zones[0] = 0; zones[1] = 0; /* Good parameters, bad control type */ errno = 0; assert(powercap_sysfs_zone_get_max_energy_range_uj("foo", zones, 2, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_zone_get_energy_uj("foo", zones, 2, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_zone_reset_energy_uj("foo", zones, 2) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_zone_get_max_power_range_uw("foo", zones, 2, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_zone_get_power_uw("foo", zones, 2, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_zone_get_enabled("foo", zones, 2, &val32) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_zone_set_enabled("foo", zones, 2, 1) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_zone_get_name("foo", zones, 2, name, sizeof(name)) == -ENOENT); assert(errno == ENOENT); /* Bad parameters */ /* Just test one of each function type */ /* get u64 */ errno = 0; assert(powercap_sysfs_zone_get_max_energy_range_uj(NULL, zones, 2, &val64) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_get_max_energy_range_uj("foo", NULL, 2, &val64) == -EINVAL); assert(errno == EINVAL); #if 0 /* TODO: Can't test NULL value parameters since we can't get past opening the file */ errno = 0; assert(powercap_sysfs_zone_get_max_energy_range_uj("foo", zones, 2, NULL) == -EINVAL); assert(errno == EINVAL); #endif /* set u64 */ errno = 0; assert(powercap_sysfs_zone_reset_energy_uj(NULL, zones, 2) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_reset_energy_uj("foo", NULL, 2) == -EINVAL); assert(errno == EINVAL); /* get u32 */ errno = 0; assert(powercap_sysfs_zone_get_enabled(NULL, zones, 2, &val32) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_get_enabled("foo", NULL, 2, &val32) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_get_enabled("foo", zones, 2, NULL) == -EINVAL); assert(errno == EINVAL); /* set u32 */ errno = 0; assert(powercap_sysfs_zone_set_enabled(NULL, zones, 2, 1) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_set_enabled("foo", NULL, 2, 1) == -EINVAL); assert(errno == EINVAL); /* get string */ errno = 0; assert(powercap_sysfs_zone_get_name(NULL, zones, 2, name, sizeof(name)) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_get_name("foo", NULL, 2, name, sizeof(name)) == -EINVAL); assert(errno == EINVAL); #if 0 /* TODO: Can't test bad name or size parameters since we can't get past opening the file */ errno = 0; assert(powercap_sysfs_zone_get_name("foo", zones, 2, NULL, sizeof(name)) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_get_name("foo", zones, 2, name, 0) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_zone_get_name("foo", zones, 2, name, 1) == -EINVAL); assert(errno == EINVAL); #endif } static void test_get_set_constraint_all_bad(void) { uint64_t val64; char name[32]; uint32_t zones[2]; zones[0] = 0; zones[1] = 0; /* Good parameters, bad control type */ errno = 0; assert(powercap_sysfs_constraint_set_power_limit_uw("foo", zones, 2, 0, 0) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_constraint_get_power_limit_uw("foo", zones, 2, 0, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_constraint_set_time_window_us("foo", zones, 2, 0, 0) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_constraint_get_time_window_us("foo", zones, 2, 0, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_constraint_get_max_power_uw("foo", zones, 2, 0, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_constraint_get_min_power_uw("foo", zones, 2, 0, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_constraint_get_max_time_window_us("foo", zones, 2, 0, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_constraint_get_min_time_window_us("foo", zones, 2, 0, &val64) == -ENOENT); assert(errno == ENOENT); errno = 0; assert(powercap_sysfs_constraint_get_name("foo", zones, 2, 0, name, sizeof(name)) == -ENOENT); assert(errno == ENOENT); /* Bad parameters */ /* Just test one of each function type */ /* set u64 */ errno = 0; assert(powercap_sysfs_constraint_set_power_limit_uw(NULL, zones, 2, 0, 0) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_constraint_set_power_limit_uw("foo", NULL, 2, 0, 0) == -EINVAL); assert(errno == EINVAL); /* get u64 */ errno = 0; assert(powercap_sysfs_constraint_get_power_limit_uw(NULL, zones, 2, 0, &val64) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_constraint_get_power_limit_uw("foo", NULL, 2, 0, &val64) == -EINVAL); assert(errno == EINVAL); #if 0 /* TODO: Can't test NULL value parameters since we can't get past opening the file */ errno = 0; assert(powercap_sysfs_constraint_get_power_limit_uw("foo", zones, 2, 0, NULL) == -EINVAL); assert(errno == EINVAL); #endif /* get string */ errno = 0; assert(powercap_sysfs_constraint_get_name(NULL, zones, 2, 0, name, sizeof(name)) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_constraint_get_name("foo", NULL, 2, 0, name, sizeof(name)) == -EINVAL); assert(errno == EINVAL); errno = 0; #if 0 /* TODO: Can't test bad name or size parameters since we can't get past opening the file */ assert(powercap_sysfs_constraint_get_name("foo", zones, 2, 0, NULL, sizeof(name)) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_constraint_get_name("foo", zones, 2, 0, name, 0) == -EINVAL); assert(errno == EINVAL); errno = 0; assert(powercap_sysfs_constraint_get_name("foo", zones, 2, 0, name, 1) == -EINVAL); assert(errno == EINVAL); #endif } int main(void) { test_bad_control_type_exists(); test_bad_zone_exists(); test_bad_constraint_exists(); test_get_set_control_type_all_bad(); test_get_set_zone_all_bad(); test_get_set_constraint_all_bad(); return EXIT_SUCCESS; } powercap-0.6.0/test/powercap-test.c000066400000000000000000000161701423746651500172770ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Basic unit tests. * Can't actually test the implementation without a system that supports all file types. */ // force assertions #undef NDEBUG #include #include #include #include "powercap.h" #ifdef USE_VIRTUAL_DEVICES #define POWERCAP_PATH "/sys/devices/virtual/powercap" #else #define POWERCAP_PATH "/sys/class/powercap" #endif static void test_powercap_control_type_file_get_name(void) { char buf[24]; assert(powercap_control_type_file_get_name(POWERCAP_CONTROL_TYPE_FILE_ENABLED, buf, sizeof(buf)) > 0); assert(strncmp(buf, "enabled", sizeof(buf)) == 0); } static void test_powercap_zone_file_get_name(void) { char buf[24]; assert(powercap_zone_file_get_name(POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ, buf, sizeof(buf)) > 0); assert(strncmp(buf, "max_energy_range_uj", sizeof(buf)) == 0); assert(powercap_zone_file_get_name(POWERCAP_ZONE_FILE_ENERGY_UJ, buf, sizeof(buf)) > 0); assert(strncmp(buf, "energy_uj", sizeof(buf)) == 0); assert(powercap_zone_file_get_name(POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW, buf, sizeof(buf)) > 0); assert(strncmp(buf, "max_power_range_uw", sizeof(buf)) == 0); assert(powercap_zone_file_get_name(POWERCAP_ZONE_FILE_POWER_UW, buf, sizeof(buf)) > 0); assert(strncmp(buf, "power_uw", sizeof(buf)) == 0); assert(powercap_zone_file_get_name(POWERCAP_ZONE_FILE_ENABLED, buf, sizeof(buf)) > 0); assert(strncmp(buf, "enabled", sizeof(buf)) == 0); assert(powercap_zone_file_get_name(POWERCAP_ZONE_FILE_NAME, buf, sizeof(buf)) > 0); assert(strncmp(buf, "name", sizeof(buf)) == 0); } static void test_powercap_constraint_file_get_name(void) { char buf[32]; assert(powercap_constraint_file_get_name(POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW, 0, buf, sizeof(buf)) > 0); assert(strncmp(buf, "constraint_0_power_limit_uw", sizeof(buf)) == 0); assert(powercap_constraint_file_get_name(POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US, 0, buf, sizeof(buf)) > 0); assert(strncmp(buf, "constraint_0_time_window_us", sizeof(buf)) == 0); assert(powercap_constraint_file_get_name(POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW, 0, buf, sizeof(buf)) > 0); assert(strncmp(buf, "constraint_0_max_power_uw", sizeof(buf)) == 0); assert(powercap_constraint_file_get_name(POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW, 0, buf, sizeof(buf)) > 0); assert(strncmp(buf, "constraint_0_min_power_uw", sizeof(buf)) == 0); assert(powercap_constraint_file_get_name(POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US, 0, buf, sizeof(buf)) > 0); assert(strncmp(buf, "constraint_0_max_time_window_us", sizeof(buf)) == 0); assert(powercap_constraint_file_get_name(POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US, 0, buf, sizeof(buf)) > 0); assert(strncmp(buf, "constraint_0_min_time_window_us", sizeof(buf)) == 0); assert(powercap_constraint_file_get_name(POWERCAP_CONSTRAINT_FILE_NAME, 0, buf, sizeof(buf)) > 0); assert(strncmp(buf, "constraint_0_name", sizeof(buf)) == 0); } #if 0 static void test_powercap_get_path(void) { char buf[4096]; uint32_t zones[2]; assert(powercap_get_path("foo", NULL, 0, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/", sizeof(buf)) == 0); zones[0] = 1; assert(powercap_get_path("foo", zones, 1, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:1/", sizeof(buf)) == 0); zones[1] = 2; assert(powercap_get_path("foo", zones, 2, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:1/foo:1:2/", sizeof(buf)) == 0); // should print zone index values in lower case hexadecimal, not decimal zones[1] = 10; assert(powercap_get_path("foo", zones, 2, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:1/foo:1:a/", sizeof(buf)) == 0); } static void test_powercap_control_type_file_get_path(void) { char buf[4096]; assert(powercap_control_type_file_get_path(POWERCAP_CONTROL_TYPE_FILE_ENABLED, "foo", buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/enabled", sizeof(buf)) == 0); } static void test_powercap_zone_file_get_path(void) { char buf[4096]; uint32_t zones = 5; assert(powercap_zone_file_get_path(POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ, "foo", &zones, 1, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:5/max_energy_range_uj", sizeof(buf)) == 0); assert(powercap_zone_file_get_path(POWERCAP_ZONE_FILE_ENERGY_UJ, "foo", &zones, 1, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:5/energy_uj", sizeof(buf)) == 0); assert(powercap_zone_file_get_path(POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW, "foo", &zones, 1, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:5/max_power_range_uw", sizeof(buf)) == 0); assert(powercap_zone_file_get_path(POWERCAP_ZONE_FILE_POWER_UW, "foo", &zones, 1, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:5/power_uw", sizeof(buf)) == 0); assert(powercap_zone_file_get_path(POWERCAP_ZONE_FILE_ENABLED, "foo", &zones, 1, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:5/enabled", sizeof(buf)) == 0); assert(powercap_zone_file_get_path(POWERCAP_ZONE_FILE_NAME, "foo", &zones, 1, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:5/name", sizeof(buf)) == 0); } static void test_powercap_constraint_file_get_path(void) { char buf[4096]; uint32_t zones = 3; assert(powercap_constraint_file_get_path(POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW, "foo", &zones, 1, 7, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:3/constraint_7_power_limit_uw", sizeof(buf)) == 0); assert(powercap_constraint_file_get_path(POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US, "foo", &zones, 1, 7, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:3/constraint_7_time_window_us", sizeof(buf)) == 0); assert(powercap_constraint_file_get_path(POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW, "foo", &zones, 1, 7, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:3/constraint_7_max_power_uw", sizeof(buf)) == 0); assert(powercap_constraint_file_get_path(POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW, "foo", &zones, 1, 7, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:3/constraint_7_min_power_uw", sizeof(buf)) == 0); assert(powercap_constraint_file_get_path(POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US, "foo", &zones, 1, 7, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:3/constraint_7_max_time_window_us", sizeof(buf)) == 0); assert(powercap_constraint_file_get_path(POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US, "foo", &zones, 1, 7, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:3/constraint_7_min_time_window_us", sizeof(buf)) == 0); assert(powercap_constraint_file_get_path(POWERCAP_CONSTRAINT_FILE_NAME, "foo", &zones, 1, 7, buf, sizeof(buf)) > 0); assert(strncmp(buf, POWERCAP_PATH"/foo/foo:3/constraint_7_name", sizeof(buf)) == 0); } #endif int main(void) { test_powercap_control_type_file_get_name(); test_powercap_zone_file_get_name(); test_powercap_constraint_file_get_name(); #if 0 test_powercap_get_path(); test_powercap_control_type_file_get_path(); test_powercap_zone_file_get_path(); test_powercap_constraint_file_get_path(); #endif return EXIT_SUCCESS; } powercap-0.6.0/utils/000077500000000000000000000000001423746651500145125ustar00rootroot00000000000000powercap-0.6.0/utils/CMakeLists.txt000066400000000000000000000026461423746651500172620ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-3-Clause # Binaries add_executable(powercap-info powercap-info.c util-common.c) target_link_libraries(powercap-info PRIVATE powercap) add_executable(powercap-set powercap-set.c util-common.c) target_link_libraries(powercap-set PRIVATE powercap) install(TARGETS powercap-info powercap-set EXPORT PowercapUtilsTargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Powercap_Utils_Runtime) install(EXPORT PowercapUtilsTargets DESTINATION ${POWERCAP_CMAKE_CONFIG_INSTALL_DIR} NAMESPACE Powercap:: COMPONENT Powercap_Utils_Development) install(FILES man/man1/powercap-info.1 man/man1/powercap-set.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT Powercap_Utils_Runtime) # Deprecated Binaries add_executable(rapl-info rapl-info.c util-common.c) target_compile_definitions(rapl-info PRIVATE POWERCAP_ALLOW_DEPRECATED) target_link_libraries(rapl-info PRIVATE powercap) add_executable(rapl-set rapl-set.c util-common.c) target_compile_definitions(rapl-set PRIVATE POWERCAP_ALLOW_DEPRECATED) target_link_libraries(rapl-set PRIVATE powercap) # Don't export deprecated targets install(TARGETS rapl-info rapl-set DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Powercap_Utils_Runtime) install(FILES man/man1/rapl-info.1 man/man1/rapl-set.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT Powercap_Utils_Runtime) powercap-0.6.0/utils/man/000077500000000000000000000000001423746651500152655ustar00rootroot00000000000000powercap-0.6.0/utils/man/man1/000077500000000000000000000000001423746651500161215ustar00rootroot00000000000000powercap-0.6.0/utils/man/man1/powercap-info.1000066400000000000000000000100341423746651500207520ustar00rootroot00000000000000.TH "POWERCAP-INFO" "1" "2021-12-12" "powercap" "powercap\-info" .SH "NAME" .LP powercap\-info \- get information from the Linux power capping framework .SH "SYNPOSIS" .LP \fBpowercap\-info\fP [\fINAME\fP [\fIOPTION\fP]...] [\fB\-hv\fP] .SH "DESCRIPTION" .LP Prints configurations for powercap control types. .LP Output can be filtered by specifying a control type \fINAME\fP and \fIOPTION\fP flags. .LP A control type \fINAME\fP must not be empty or contain a '.' or '/'. .SH "OPTIONS" .LP .TP \fB\-h,\fR \fB\-\-help\fR Prints the help screen .TP \fB\-v,\fR \fB\-\-verbose\fR Print errors when files cannot be read .TP \fB\-p,\fR \fB\-\-control\-type\fR=\fINAME\fP Deprecated, provide \fINAME\fP as the first positional argument instead. .LP All remaining options below require a control type \fINAME\fP: .TP \fB\-z,\fR \fB\-\-zone=\fR\fIZONE(S)\fP The zone/subzone numbers in the control type's powercap tree (control type's root by default). Separate zones/subzones with a colon. E.g., for zone 0, subzone 2: .br \fB\-z 0:2\fP .br Ending with a colon prevents output for subzones. E.g., for zone 0, but not subzones: .br \fB\-z 0:\fP .TP \fB\-c,\fR \fB\-\-constraint\fR=\fICONSTRAINT\fP The constraint number .TP All remaining options below are mutually exclusive: .TP \fB\-E,\fR \fB\-\-enabled\fR Print control type enabled/disabled status .TP \fB\-n,\fR \fB\-\-nzones\fR Print the number of zones (control type's root by default; within the \-z/\-\-zone level, if set) .LP The following are zone-level arguments and require \-z/\-\-zone: .TP \fB\-N,\fR \fB\-\-nconstraints\fR Print the number of zone constraints .TP \fB\-j,\fR \fB\-\-z\-energy\fR Print zone energy counter .TP \fB\-J,\fR \fB\-\-z\-max\-energy\-range\fR Print zone maximum energy counter range .TP \fB\-w,\fR \fB\-\-z\-power\fR Print zone current power .TP \fB\-W,\fR \fB\-\-z\-max\-power\-range\fR Print zone maximum current power range .TP \fB\-e,\fR \fB\-\-z\-enabled\fR Print zone enabled/disabled status .TP \fB\-x,\fR \fB\-\-z\-name\fR Print zone name .LP The following are constraint-level arguments and require \-z/\-\-zone and \-c/\-\-constraint: .TP \fB\-l,\fR \fB\-\-c\-power\-limit\fR Print constraint power limit .TP \fB\-s,\fR \fB\-\-c\-time\-window\fR Print constraint time window .TP \fB\-U,\fR \fB\-\-c\-max\-power\fR Print constraint maximum allowed power .TP \fB\-u,\fR \fB\-\-c\-min\-power\fR Print constraint minimum allowed power .TP \fB\-T,\fR \fB\-\-c\-max\-time\-window\fR Print constraint maximum allowed time window .TP \fB\-t,\fR \fB\-\-c\-min\-time\-window\fR Print constraint minimum allowed time window .TP \fB\-y,\fR \fB\-\-c\-name\fR Print constraint name .SH "EXAMPLES" .TP \fBpowercap\-info\fP Print all zones for all control types. .TP \fBpowercap\-info intel\-rapl\fP Print all zones for the \fIintel\-rapl\fR control type. .TP \fBpowercap\-info intel\-rapl \-z 0\fP Print only zone 0 for the \fIintel\-rapl\fR control type. .TP \fBpowercap\-info intel\-rapl \-z 0:1\fP Print zone 0, subzone 1 for the \fIintel\-rapl\fR control type. .TP \fBpowercap\-info intel\-rapl \-z 0 \-c 1\fP Print zone 0, constraint 1 for the \fIintel\-rapl\fR control type. .TP \fBpowercap\-info intel\-rapl \-z 0 \-j\fP Print the energy counter for zone 0 for the \fIintel\-rapl\fR control type. .TP \fBpowercap\-info intel\-rapl \-z 1:0 \-c 0 \-l\fP Print the power limit for zone 1, subzone 0, constraint 0 for the \fIintel\-rapl\fR control type. .SH "REMARKS" .LP Some fields are optional and/or may require administrative (super\-user) privileges to read. .br Fields will only be printed if they are available and readable, unless \-v/\-\-verbose is set. .br If no subzone/constraint\-specific outputs are requested, all available zones and constraints will be shown. .LP Energy units: microjoules (uJ) .br Power units: microwatts (uW) .br Time units: microseconds (us) .SH "BUGS" .LP Report bugs upstream at .SH "FILES" .nf \fI/sys/devices/virtual/powercap/*\fP .nf \fI/sys/class/powercap/*\fP .fi .SH "AUTHORS" .nf Connor Imes .fi .SH "SEE ALSO" .BR powercap\-set (1)powercap-0.6.0/utils/man/man1/powercap-set.1000066400000000000000000000052661423746651500206250ustar00rootroot00000000000000.TH "POWERCAP\-SET" "1" "2021-12-12" "powercap" "powercap\-set" .SH "NAME" .LP powercap\-set \- manage power capping devices with the Linux power capping framework .SH "SYNPOSIS" .LP \fBpowercap\-set\fP \fINAME\fP [\fIOPTION\fP]... .SH "DESCRIPTION" .LP Sets configurations for a powercap control type. .LP The control type \fINAME\fP must not be empty or contain a '.' or '/'. .SH "OPTIONS" .LP .TP \fB\-h,\fR \fB\-\-help\fR Prints the help screen .TP \fB\-p,\fR \fB\-\-control\-type\fR=\fINAME\fP Deprecated, provide \fINAME\fP as the first positional argument instead. .TP \fB\-z,\fR \fB\-\-zone=\fR\fIZONE(S)\fP The zone/subzone numbers in the control type's powercap tree. Separate zones/subzones with a colon. E.g., for zone 0, subzone 2: .br \fB\-z 0:2\fP .TP \fB\-c,\fR \fB\-\-constraint\fR=\fICONSTRAINT\fP The constraint number (none by default) .TP \fB\-E,\fR \fB\-\-enabled=1|0\fR Enable/disable a control type .LP The following zone-level arguments may be used together and require \-z/\-\-zone: .TP \fB\-j,\fR \fB\-\-z\-energy\fR Reset zone energy counter .TP \fB\-e,\fR \fB\-\-z\-enabled=1|0\fR Enable/disable a zone .LP The following constraint-level arguments may be used together and require \-z/\-\-zone and \-c/\-\-constraint: .TP \fB\-l,\fR \fB\-\-c\-power\-limit=UW\fR Set constraint power limit .TP \fB\-s,\fR \fB\-\-c\-time\-window=US\fR Set constraint time window .SH "EXAMPLES" .TP \fBpowercap\-set intel\-rapl \-z 0 \-e 1\fP Enable zone 0 for the \fIintel\-rapl\fR control type. .TP \fBpowercap\-set intel\-rapl \-z 0:1 \-e 1\fP Enable zone 0, subzone 1 for the \fIintel\-rapl\fR control type. .TP \fBpowercap\-set intel\-rapl \-z 0 \-c 1 \-l 25000000\fP Set a power cap of 25 Watts (25000000 uW) on zone 0, constraint 1 for the \fIintel\-rapl\fR control type. .TP \fBpowercap\-set intel\-rapl \-z 1:0 \-c 0 \-l 15000000 \-s 976\fP Set a power cap of 15 Watts (15000000 uW) and time window of 976 microseconds on zone 1, subzone 0, constraint 0 for the \fIintel\-rapl\fR control type. .SH "REMARKS" .LP Administrative (root) privileges are usually needed to use \fBpowercap\-set\fR. .LP Setting constraint power cap and/or time limit values may not enable or disable a zone/subzone - set the \-e/-\-z\-enabled flag explicitly. .LP The kernel may round power limits and time windows to discrete values supported by the hardware, e.g., 28 seconds might round to 27983872 microseconds. .LP Power units: microwatts (uW) .br Time units: microseconds (us) .SH "BUGS" .LP Report bugs upstream at .SH "FILES" .nf \fI/sys/devices/virtual/powercap/*\fP .nf \fI/sys/class/powercap/*\fP .fi .SH "AUTHORS" .nf Connor Imes .fi .SH "SEE ALSO" .BR powercap\-info (1)powercap-0.6.0/utils/man/man1/rapl-info.1000066400000000000000000000127521423746651500201010ustar00rootroot00000000000000.TH "RAPL\-INFO" "1" "2021-04-14" "powercap" "rapl\-info" .SH "NAME" .LP rapl\-info \- get RAPL configurations .SH "SYNPOSIS" .LP \fBrapl\-info\fP [\fIOPTION\fP]... .SH "DESCRIPTION" .LP This utility is deprecated, use .BR powercap\-info (1) instead. .LP Prints out Intel Running Average Power Limit (RAPL) configurations. .LP Note that the \-p and \-z options are different from .BR powercap\-info (1). .LP This software requires an Intel processor (Sandy Bridge or newer), Linux kernel 3.13 or newer compiled with \fBCONFIG_POWERCAP\fR and \fBCONFIG_INTEL_RAPL\fR enabled, and the \fBintel_rapl\fR kernel module to be loaded. .SH "OPTIONS" .LP .TP \fB\-h,\fR \fB\-\-help\fR Prints out the help screen .TP \fB\-v,\fR \fB\-\-verbose\fR Print errors when files are not available .TP \fB\-p,\fR \fB\-\-zone\fR=\fIZONE\fP The zone number (none by default; 0 by default if using \-z/\-\-subzone and/or \-c/\-\-constraint). Ending with a colon prevents output for subzones. E.g., for zone 0, but not subzones: .br \fB\-p 0:\fP .TP \fB\-p,\fR \fB\-\-package\fR=\fIPACKAGE\fP Deprecated, use \-\-zone instead .TP \fB\-z,\fR \fB\-\-subzone=\fR\fISUBZONE\fP The subzone number (none by default) .TP \fB\-c,\fR \fB\-\-constraint\fR=\fICONSTRAINT\fP The constraint number (none by default) .TP All remaining options below are mutually exclusive: .TP \fB\-n,\fR \fB\-\-nzones\fR Print the number of zones found, or the number of subzones found if \-p/\-\-zone is set .LP The following are zone-level arguments (\-z/\-\-subzone is optional): .TP \fB\-j,\fR \fB\-\-z\-energy\fR Print zone energy counter .TP \fB\-J,\fR \fB\-\-z\-max\-energy\-range\fR Print zone maximum energy counter range .TP \fB\-w,\fR \fB\-\-z\-power\fR Print zone current power .TP \fB\-W,\fR \fB\-\-z\-max\-power\-range\fR Print zone maximum current power range .TP \fB\-e,\fR \fB\-\-z\-enabled\fR Print zone enable/disabled status .TP \fB\-x,\fR \fB\-\-z\-name\fR Print zone name .LP The following are constraint-level arguments and require \-c/\-\-constraint (\-z/\-\-subzone is optional): .TP \fB\-l,\fR \fB\-\-c\-power\-limit\fR Print constraint power limit .TP \fB\-s,\fR \fB\-\-c\-time\-window\fR Print constraint time window .TP \fB\-U,\fR \fB\-\-c\-max\-power\fR Print constraint maximum allowed power .TP \fB\-u,\fR \fB\-\-c\-min\-power\fR Print constraint minimum allowed power .TP \fB\-T,\fR \fB\-\-c\-max\-time\-window\fR Print constraint maximum allowed time window .TP \fB\-t,\fR \fB\-\-c\-min\-time\-window\fR Print constraint minimum allowed time window .TP \fB\-y,\fR \fB\-\-c\-name\fR Print constraint name .SH "EXAMPLES" .LP Note that \-p/\-\-zone=0 is used by default when also specifying \-z/\-\-subzone and/or \-c/\-\-constraint, allowing for simpler commands on single-socket systems. .TP \fBrapl\-info\fP Print all RAPL zones. .TP \fBrapl\-info \-p 0\fP Print only zone 0, which is usually named \fBpackage\-0\fR. .TP \fBrapl\-info \-p 0 \-z 1\fP Print zone 0, subzone 1, which is usually the \fBuncore\fR or \fBdram\fR subzone of \fBpackage\-0\fR, depending on the system. .TP \fBrapl\-info \-p 0 \-c 1\fP Print zone 0, constraint 1, which is usually the \fBshort_term\fR constraint for \fBpackage\-0\fR. .TP \fBrapl\-info \-p 0 \-j\fP Print the energy counter for zone 0, which is usually named \fBpackage\-0\fR. .TP \fBrapl\-info \-p 1 \-z 0 \-c 0 \-l\fP Print the power limit for zone 1, subzone 0, constraint 0, which is usually the \fBlong_term\fR constraint for the \fBcore\fR subzone of \fBpackage\-1\fR (a multi-socket system). .SH "REMARKS" .LP Some fields are optional and will only be printed if they are available unless \-v/\-\-verbose is set. .br If no zone/constraint-specific outputs are requested, all available zones and constraints will be shown. .LP Energy units: microjoules (uJ) .br Power units: microwatts (uW) .br Time units: microseconds (us) .SH "BUGS" .LP The following are behavioral quirks due to the kernel interface or abnormalities in some hardware. They are not bugs in \fBrapl\-info\fR and should not be reported as such. .LP Values returned by the kernel sometimes lose accuracy from the actual values stored in Model-Specific Registers due to integer rounding. For example, the kernel may return a time window value of 7812 us, when in fact the actual stored value is 7812.5 us. Writing back a value returned by the kernel, e.g., using rapl\-set(1), may cause unexpected changes to its value due to these rounding problems. .LP At the time of this writing, some features in the powercap interface are not supported by RAPL. The following options may result in ENOENT (No such file or directory) errors: \fB\-w/\-\-z\-power\fR \fB\-W/\-\-z\-max\-power\-range\fR \fB\-u/\-\-c\-min\-power\fR \fB\-T/\-\-c\-max\-time\-window\fR \fB\-t/\-\-c\-min\-time\-window\fR .LP On some systems, the constraint max_power_uw file, e.g., constraint_0_max_power_uw, is known to receive an ENODATA (No data available) error from the kernel for subzones. So even though the file exists, a value may not be printed for it. .LP It is possible for packages on multi-socket systems to be indexed out of order by the kernel. For example, the package at index 0 (\fB\-p 0\fR) could actually be named \fBpackage\-1\fR while the package at index 1 (\fB\-p 1\fR) is named \fBpackage\-0\fR. .LP Report bugs upstream at .SH "FILES" .nf \fI/sys/devices/virtual/powercap/intel\-rapl/*\fP .nf \fI/sys/class/powercap/intel\-rapl/*\fP .fi .SH "AUTHORS" .nf Connor Imes .fi .SH "SEE ALSO" .BR powercap\-info (1), .BR powercap\-set (1), .BR rapl\-set (1)powercap-0.6.0/utils/man/man1/rapl-set.1000066400000000000000000000112271423746651500177350ustar00rootroot00000000000000.TH "RAPL\-SET" "1" "2021-04-14" "powercap" "rapl\-set" .SH "NAME" .LP rapl\-set \- set RAPL configurations .SH "SYNPOSIS" .LP \fBrapl\-set\fP [\fIOPTION\fP]... .SH "DESCRIPTION" .LP This utility is deprecated, use .BR powercap\-set (1) instead. .LP Sets Intel Running Average Power Limit (RAPL) configurations. .LP Note that the \-p and \-z options are different from .BR powercap\-set (1). .LP This software requires an Intel processor (Sandy Bridge or newer), Linux kernel 3.13 or newer compiled with \fBCONFIG_POWERCAP\fR and \fBCONFIG_INTEL_RAPL\fR enabled, and the \fBintel_rapl\fR kernel module to be loaded. .SH "OPTIONS" .LP .TP \fB\-h,\fR \fB\-\-help\fR Prints out the help screen .TP \fB\-p,\fR \fB\-\-zone\fR=\fIZONE\fP The zone number (0 by default) .TP \fB\-p,\fR \fB\-\-package\fR=\fIPACKAGE\fP Deprecated, use \-\-zone instead .TP \fB\-z,\fR \fB\-\-subzone=\fR\fISUBZONE\fP The subzone number (none by default) .TP \fB\-c,\fR \fB\-\-constraint\fR=\fICONSTRAINT\fP The constraint number (none by default) .LP The following zone-level arguments may be used together (\-z/\-\-subzone is optional): .TP \fB\-j,\fR \fB\-\-z\-energy\fR Reset zone energy counter .TP \fB\-e,\fR \fB\-\-z\-enabled=1|0\fR Enable/disable a zone .LP The following constraint-level arguments may be used together and require \-c/\-\-constraint (\-z/\-\-subzone is optional): .TP \fB\-l,\fR \fB\-\-c\-power\-limit=UW\fR Set constraint power limit .TP \fB\-s,\fR \fB\-\-c\-time\-window=US\fR Set constraint time window .SH "EXAMPLES" .LP Note that \-p/\-\-zone=0 is used by default, allowing for simpler commands on single-socket systems. .TP \fBrapl\-set \-e 1\fP Enable zone 0 (implicitly), which is usually named \fBpackage\-0\fR. .TP \fBrapl\-set \-p 0 \-e 1\fP Enable zone 0 (explicitly). .TP \fBrapl\-set \-p 0 \-z 1 \-e 1\fP Enable zone 0, subzone 1, which is usually the \fBuncore\fR or \fBdram\fR subzone of \fBpackage\-0\fR, depending on the system. .TP \fBrapl\-set \-p 0 \-c 1 \-l 25000000\fP Set a power cap of 25 Watts (25000000 uW) on zone 0, constraint 1, which is usually the \fBshort_term\fR constraint for \fBpackage\-0\fR. .TP \fBrapl\-set \-p 1 \-z 0 \-c 0 \-l 15000000 \-s 976\fP Set a power cap of 15 Watts (15000000 uW) and time window of 976 microseconds on zone 1, subzone 0, constraint 0, which is usually the \fBlong_term\fR (and only) constraint for the \fBcore\fR subzone of \fBpackage\-1\fR (a multi-socket system). .SH "REMARKS" .LP Administrative (root) privileges are usually needed to use \fBrapl\-set\fR. .LP Setting constraint power cap and/or time limit values does not enable or disable a zone/subzone - the \-e/-\-z\-enabled flag must be set explicitly. .LP Power units: microwatts (uW) .br Time units: microseconds (us) .SH "BUGS" .LP The following are behavioral quirks due to the kernel interface or abnormalities in some hardware. They are not bugs in \fBrapl\-set\fR and should not be reported as such. .LP The kernel is not guaranteed to accept power limit and time window values exactly as specified. Values may be rounded due to how they are encoded in Model-Specific Registers. This rounding error is usually small within normal operating ranges, but can be significant at the extremes. .LP Some systems may not accept time window values correctly, requiring a system reboot to reset the time window to the default value. .LP Values returned by the kernel, e.g., by rapl\-info(1), sometimes lose accuracy from the actual stored value due to integer rounding. For example, the kernel may return a time window value of 7812 us, when in fact the actual stored value is 7812.5 us. Writing back an integer value returned by the kernel may cause unexpected changes to its stored value due to these rounding problems. .LP At the time of this writing, some features in the powercap interface are not supported by RAPL. Resetting a zone energy counter (\-j/\-\-z\-energy) may result in an EACCES (Permission denied) error due to the energy_uj file being read-only. .LP Some systems may not allow disabling package-level zones/constraints. .LP It is possible for packages on multi-socket systems to be indexed out of order by the kernel. For example, the package at index 0 (\fB\-p 0\fR) could actually be named \fBpackage\-1\fR while the package at index 1 (\fB\-p 1\fR) is named \fBpackage\-0\fR. If this matters to the user, it is their responsibility to check before setting values, e.g., using rapl\-info(1). .LP Report bugs upstream at .SH "FILES" .nf \fI/sys/devices/virtual/powercap/intel\-rapl/*\fP .nf \fI/sys/class/powercap/intel\-rapl/*\fP .fi .SH "AUTHORS" .nf Connor Imes .fi .SH "SEE ALSO" .BR powercap\-info (1), .BR powercap\-set (1), .BR rapl\-info (1)powercap-0.6.0/utils/powercap-info.c000066400000000000000000000511731423746651500174360ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Get powercap values. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include #include #include #include #include #include #include "powercap-sysfs.h" #include "util-common.h" #define POWERCAP_PATH "/sys/class/powercap" static void print_parent_headers(const uint32_t* zones, uint32_t depth_start, uint32_t depth, uint32_t indnt) { uint32_t i; uint32_t j; for (i = depth_start; i <= depth; i++) { indent(indnt + i - 1); printf("Zone %"PRIu32, zones[0]); for (j = 1; j < i; j++) { printf(":%"PRIu32, zones[j]); } printf("\n"); } } static void analyze_constraint(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, int verbose, uint32_t indnt) { char name[MAX_NAME_SIZE]; uint64_t val64; ssize_t sret; int ret; indent(indnt + depth); printf("Constraint %"PRIu32"\n", constraint); sret = powercap_sysfs_constraint_get_name(control_type, zones, depth, constraint, name, sizeof(name)); ret = sret > 0 ? 0 : (int) sret; str_or_verbose(verbose, indnt + depth + 1, "name", name, ret); ret = powercap_sysfs_constraint_get_power_limit_uw(control_type, zones, depth, constraint, &val64); u64_or_verbose(verbose, indnt + depth + 1, "power_limit_uw", val64, ret); ret = powercap_sysfs_constraint_get_time_window_us(control_type, zones, depth, constraint, &val64); u64_or_verbose(verbose, indnt + depth + 1, "time_window_us", val64, ret); ret = powercap_sysfs_constraint_get_min_power_uw(control_type, zones, depth, constraint, &val64); u64_or_verbose(verbose, indnt + depth + 1, "min_power_uw", val64, ret); ret = powercap_sysfs_constraint_get_max_power_uw(control_type, zones, depth, constraint, &val64); u64_or_verbose(verbose, indnt + depth + 1, "max_power_uw", val64, ret); ret = powercap_sysfs_constraint_get_min_time_window_us(control_type, zones, depth, constraint, &val64); u64_or_verbose(verbose, indnt + depth + 1, "min_time_window_us", val64, ret); ret = powercap_sysfs_constraint_get_max_time_window_us(control_type, zones, depth, constraint, &val64); u64_or_verbose(verbose, indnt + depth + 1, "max_time_window_us", val64, ret); } static void analyze_zone(const char* control_type, const uint32_t* zones, uint32_t depth, int verbose, uint32_t indnt) { char name[MAX_NAME_SIZE]; uint64_t val64; uint32_t val32; ssize_t sret; int ret; print_parent_headers(zones, depth, depth, indnt); sret = powercap_sysfs_zone_get_name(control_type, zones, depth, name, sizeof(name)); ret = sret > 0 ? 0 : (int) sret; str_or_verbose(verbose, indnt + depth, "name", name, ret); ret = powercap_sysfs_zone_get_enabled(control_type, zones, depth, &val32); u64_or_verbose(verbose, indnt + depth, "enabled", (uint64_t) val32, ret); ret = powercap_sysfs_zone_get_max_energy_range_uj(control_type, zones, depth, &val64); u64_or_verbose(verbose, indnt + depth, "max_energy_range_uj", val64, ret); ret = powercap_sysfs_zone_get_energy_uj(control_type, zones, depth, &val64); u64_or_verbose(verbose, indnt + depth, "energy_uj", val64, ret); ret = powercap_sysfs_zone_get_max_power_range_uw(control_type, zones, depth, &val64); u64_or_verbose(verbose, indnt + depth, "max_power_range_uw", val64, ret); ret = powercap_sysfs_zone_get_power_uw(control_type, zones, depth, &val64); u64_or_verbose(verbose, indnt + depth, "power_uw", val64, ret); for (val32 = 0; !powercap_sysfs_constraint_exists(control_type, zones, depth, val32); val32++) { analyze_constraint(control_type, zones, depth, val32, verbose, indnt); } } static void analyze_control_type(const char* control_type, int verbose, uint32_t indnt) { uint32_t val32; int ret = powercap_sysfs_control_type_get_enabled(control_type, &val32); u64_or_verbose(verbose, indnt, "enabled", (uint64_t) val32, ret); } /* depth must be > 0 */ static void analyze_all_zones_recurse(const char* control_type, uint32_t* zones, uint32_t depth, uint32_t max_depth, int verbose, uint32_t indnt) { if (!powercap_sysfs_zone_exists(control_type, zones, depth)) { /* Analyze this zone */ analyze_zone(control_type, zones, depth, verbose, indnt); if (depth < max_depth) { /* Analyze subzones */ zones[depth] = 0; analyze_all_zones_recurse(control_type, zones, depth + 1, max_depth, verbose, indnt); } /* Analyze next sibling zone */ zones[depth - 1]++; analyze_all_zones_recurse(control_type, zones, depth, max_depth, verbose, indnt); } } static void analyze_control_type_recurse(const char* control_type, uint32_t* zones, uint32_t max_depth, int verbose, uint32_t indnt) { analyze_control_type(control_type, verbose, indnt); analyze_all_zones_recurse(control_type, zones, 1, max_depth, verbose, indnt); } static int analyze_powercap(uint32_t* zones, uint32_t max_depth, int verbose) { struct dirent *dp; DIR *dfd; if ((dfd = opendir(POWERCAP_PATH)) == NULL) { perror(POWERCAP_PATH); return -errno; } while ((dp = readdir(dfd)) != NULL) { if (!strstr(dp->d_name, ".") && !strstr(dp->d_name, ":")) { memset(zones, 0, max_depth * sizeof(*zones)); printf("%s\n", dp->d_name); analyze_control_type_recurse(dp->d_name, zones, max_depth, verbose, 1); } } if (closedir(dfd)) { perror(POWERCAP_PATH); return -errno; } return 0; } static void analyze_zone_recurse(const char* control_type, uint32_t* zones, uint32_t depth, uint32_t max_depth, int verbose, uint32_t indnt) { if (!powercap_sysfs_zone_exists(control_type, zones, depth)) { /* Analyze this zone */ analyze_zone(control_type, zones, depth, verbose, indnt); if (depth < max_depth) { /* Analyze subzones */ zones[depth] = 0; analyze_all_zones_recurse(control_type, zones, depth + 1, max_depth, verbose, indnt); } } } static void print_num_zones(const char* control_type, uint32_t* zones, uint32_t depth) { zones[depth] = 0; while (!powercap_sysfs_zone_exists(control_type, zones, depth + 1)) { zones[depth]++; } printf("%"PRIu32"\n", zones[depth]); } static void print_num_constraints(const char* control_type, uint32_t* zones, uint32_t depth) { uint32_t n = 0; while (!powercap_sysfs_constraint_exists(control_type, zones, depth, n)) { n++; } printf("%"PRIu32"\n", n); } static const char short_options[] = "-hvp:z:c:EnNjJwWexlsUuTty"; static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, {"control-type", required_argument, NULL, 'p'}, {"zone", required_argument, NULL, 'z'}, {"constraint", required_argument, NULL, 'c'}, {"enabled", no_argument, NULL, 'E'}, {"nzones", no_argument, NULL, 'n'}, {"nconstraints", no_argument, NULL, 'N'}, {"z-energy", no_argument, NULL, 'j'}, {"z-max-energy-range", no_argument, NULL, 'J'}, {"z-power", no_argument, NULL, 'w'}, {"z-max-power-range", no_argument, NULL, 'W'}, {"z-enabled", no_argument, NULL, 'e'}, {"z-name", no_argument, NULL, 'x'}, {"c-power-limit", no_argument, NULL, 'l'}, {"c-time-window", no_argument, NULL, 's'}, {"c-max-power", no_argument, NULL, 'U'}, {"c-min-power", no_argument, NULL, 'u'}, {"c-max-time-window", no_argument, NULL, 'T'}, {"c-min-time-window", no_argument, NULL, 't'}, {"c-name", no_argument, NULL, 'y'}, {0, 0, 0, 0} }; static void print_usage(void) { printf("Usage: powercap-info [NAME [OPTION]...] [-hv]\n\n"); printf("Prints configurations for powercap control types.\n"); printf("Output can be filtered by specifying a control type NAME and OPTION flags.\n"); printf("A control type NAME must not be empty or contain a '.' or '/'.\n\n"); printf("Options:\n"); printf(" -h, --help Print this message and exit\n"); printf(" -v, --verbose Print errors when files cannot be read\n"); printf(" -p, --control-type=NAME Deprecated, provide NAME as the first\n"); printf(" positional argument instead\n"); printf("All remaining options below require a control type NAME:\n"); printf(" -z, --zone=ZONE(S) The zone/subzone numbers in the control type's\n"); printf(" powercap tree (control type's root by default)\n"); printf(" Separate zones/subzones with a colon\n"); printf(" E.g., for zone 0, subzone 2: \"-z 0:2\"\n"); printf(" Ending with a colon prevents output for subzones\n"); printf(" E.g., for zone 0, but not subzones: \"-z 0:\"\n"); printf(" -c, --constraint=CONSTRAINT The constraint number\n"); printf("All remaining options below are mutually exclusive:\n"); printf(" -E, --enabled Print control type enabled/disabled status\n"); printf(" -n, --nzones Print the number of zones (control type's root by\n"); printf(" default; within the -z/--zone level, if set)\n"); printf("The following are zone-level arguments and require -z/--zone:\n"); printf(" -N, --nconstraints Print the number of zone constraints\n"); printf(" -j, --z-energy Print zone energy counter\n"); printf(" -J, --z-max-energy-range Print zone maximum energy counter range\n"); printf(" -w, --z-power Print zone current power\n"); printf(" -W, --z-max-power-range Print zone maximum current power range\n"); printf(" -e, --z-enabled Print zone enabled/disabled status\n"); printf(" -x, --z-name Print zone name\n"); printf("The following are constraint-level arguments and require -z/--zone and -c/--constraint:\n"); printf(" -l, --c-power-limit Print constraint power limit\n"); printf(" -s, --c-time-window Print constraint time window\n"); printf(" -U, --c-max-power Print constraint maximum allowed power\n"); printf(" -u, --c-min-power Print constraint minimum allowed power\n"); printf(" -T, --c-max-time-window Print constraint maximum allowed time window\n"); printf(" -t, --c-min-time-window Print constraint minimum allowed time window\n"); printf(" -y, --c-name Print constraint name\n"); printf("\nSome fields are optional and/or may require administrative (super-user) privileges to read.\n"); printf("Fields will only be printed if they are available and readable, unless -v/--verbose is set.\n"); printf("If no zone/constraint-specific outputs are requested, all available zones and constraints will be shown.\n"); printf("\nEnergy units: microjoules (uJ)\n"); printf("Power units: microwatts (uW)\n"); printf("Time units: microseconds (us)\n"); } static void print_common_help(void) { printf("Considerations for common errors:\n"); printf("- Ensure that the control type exists, which may require loading a kernel module\n"); printf("- Some files may simply not exist\n"); } static int verify_control_type_args(const char* control_type, uint32_t depth, u32_param* constraint, int unique_set) { int ret = 0; if (!is_valid_powercap_control_type(control_type)) { fprintf(stderr, "Must specify control type NAME; value must not be empty or contain any '.' or '/' characters\n"); ret = -EINVAL; } else if (unique_set) { switch (unique_set) { case 'E': if (depth || constraint->set) { fprintf(stderr, "Must not specify -z/--zone or -c/--constraint with -E/--enabled\n"); ret = -EINVAL; } break; case 'n': if (constraint->set) { fprintf(stderr, "Must not specify -c/--constraint with -n/--nzones\n"); ret = -EINVAL; } break; case 'N': case 'j': case 'J': case 'w': case 'W': case 'e': case 'x': if (!depth) { fprintf(stderr, "Must specify -z/--zone with zone-level argument\n"); ret = -EINVAL; } else if (constraint->set) { fprintf(stderr, "Must not specify -c/--constraint with zone-level argument\n"); ret = -EINVAL; } break; case 'l': case 's': case 'U': case 'u': case 'T': case 't': case 'y': if (!depth || !constraint->set) { fprintf(stderr, "Must specify -z/--zone and -c/--constraint with constraint-level argument\n"); ret = -EINVAL; } break; } } else if (constraint->set && !depth) { fprintf(stderr, "Must specify -z/--zone with -c/--constraint\n"); ret = -EINVAL; } return ret; } static int print_control_type(const char* control_type, uint32_t* zones, uint32_t depth, uint32_t max_depth, u32_param* constraint, int recurse, int verbose, int unique_set) { uint64_t val64; uint32_t val32; char name[MAX_NAME_SIZE]; int ret = 0; /* Check if control type/zones/constraint exist */ if (powercap_sysfs_control_type_exists(control_type)) { fprintf(stderr, "Control type does not exist\n"); return -EINVAL; } else if (depth && powercap_sysfs_zone_exists(control_type, zones, depth)) { fprintf(stderr, "Zone does not exist\n"); return -EINVAL; } else if (constraint->set && powercap_sysfs_constraint_exists(control_type, zones, depth, constraint->val)) { fprintf(stderr, "Constraint does not exist\n"); return -EINVAL; } /* Perform requested action */ if (unique_set) { switch (unique_set) { case 'E': /* Get control type enabled */ if (!(ret = powercap_sysfs_control_type_get_enabled(control_type, &val32))) { printf("%"PRIu32"\n", val32); } else { perror("Failed to get control type enabled"); } break; case 'n': /* Print number of zones at the specified tree location */ print_num_zones(control_type, zones, depth); break; case 'N': /* Print number of constraints at the specified tree location */ print_num_constraints(control_type, zones, depth); break; case 'j': /* Get zone energy */ if (!(ret = powercap_sysfs_zone_get_energy_uj(control_type, zones, depth, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get zone energy"); } break; case 'J': /* Get zone max energy range */ if (!(ret = powercap_sysfs_zone_get_max_energy_range_uj(control_type, zones, depth, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get zone max energy range"); } break; case 'w': /* Get zone power */ if (!(ret = powercap_sysfs_zone_get_power_uw(control_type, zones, depth, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get zone power"); } break; case 'W': /* Get zone max power range */ if (!(ret = powercap_sysfs_zone_get_max_power_range_uw(control_type, zones, depth, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get zone max power range"); } break; case 'e': /* Get zone enabled */ if (!(ret = powercap_sysfs_zone_get_enabled(control_type, zones, depth, &val32))) { printf("%"PRIu32"\n", val32); } else { perror("Failed to get zone enabled"); } break; case 'x': /* Get zone name */ if (powercap_sysfs_zone_get_name(control_type, zones, depth, name, sizeof(name)) > 0) { printf("%s\n", name); } else { ret = -errno; perror("Failed to get zone name"); } break; case 'l': /* Get constraint power limit */ if (!(ret = powercap_sysfs_constraint_get_power_limit_uw(control_type, zones, depth, constraint->val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint power limit"); } break; case 's': /* Get constraint time window */ if (!(ret = powercap_sysfs_constraint_get_time_window_us(control_type, zones, depth, constraint->val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint time window"); } break; case 'U': /* Get constraint max power */ if (!(ret = powercap_sysfs_constraint_get_max_power_uw(control_type, zones, depth, constraint->val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint max power"); } break; case 'u': /* Get constraint min power */ if (!(ret = powercap_sysfs_constraint_get_min_power_uw(control_type, zones, depth, constraint->val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint min power"); } break; case 'T': /* Get constraint max time window */ if (!(ret = powercap_sysfs_constraint_get_max_time_window_us(control_type, zones, depth, constraint->val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint max time window"); } break; case 't': /* Get constraint min time window */ if (!(ret = powercap_sysfs_constraint_get_min_time_window_us(control_type, zones, depth, constraint->val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint min time window"); } break; case 'y': /* Get constraint name */ if (powercap_sysfs_constraint_get_name(control_type, zones, depth, constraint->val, name, sizeof(name)) > 0) { printf("%s\n", name); } else { ret = -errno; perror("Failed to get constraint name"); } break; } } else if (depth > 0) { /* Print summary of zone or constraint */ if (constraint->set) { /* print constraint */ print_parent_headers(zones, 1, depth, 0); analyze_constraint(control_type, zones, depth, constraint->val, verbose, 0); } else { /* print zone */ print_parent_headers(zones, 1, depth - 1, 0); if (recurse) { analyze_zone_recurse(control_type, zones, depth, max_depth, verbose, 0); } else { analyze_zone(control_type, zones, depth, verbose, 0); } } } else { /* print control type and all zones */ analyze_control_type_recurse(control_type, zones, max_depth, verbose, 0); } return ret; } int main(int argc, char** argv) { const char* control_type = NULL; uint32_t zones[MAX_ZONE_DEPTH] = { 0 }; u32_param constraint = {0, 0}; uint32_t depth = 0; int recurse = 1; int verbose = 0; int unique_set = 0; int c; int cont = 1; int ret = 0; /* Parse command-line arguments */ while (cont) { c = getopt_long(argc, argv, short_options, long_options, NULL); switch (c) { case -1: cont = 0; break; case 'h': print_usage(); return EXIT_SUCCESS; case 'v': verbose = 1; break; case 1: case 'p': if (control_type) { cont = 0; ret = -EINVAL; } control_type = optarg; break; case 'z': recurse = get_recurse(optarg); ret = parse_zones(optarg, zones, MAX_ZONE_DEPTH, &depth, &cont); break; case 'c': ret = set_u32_param(&constraint, optarg, &cont); break; case 'E': case 'n': case 'N': case 'j': case 'J': case 'w': case 'W': case 'e': case 'x': case 'l': case 's': case 'U': case 'u': case 'T': case 't': case 'y': if (unique_set) { fprintf(stderr, "Must not specify multiple mutually exclusive arguments\n"); cont = 0; ret = -EINVAL; break; } unique_set = c; break; case '?': default: cont = 0; ret = -EINVAL; break; } } /* Verify argument combinations */ if (ret) { fprintf(stderr, "Invalid arguments\n"); } else if (control_type) { ret = verify_control_type_args(control_type, depth, &constraint, unique_set); } else if (depth || constraint.set || unique_set) { fprintf(stderr, "Must not specify control type options without NAME\n"); ret = -EINVAL; } if (ret) { print_usage(); return EXIT_FAILURE; } /* Print requested info */ if (control_type) { ret = print_control_type(control_type, zones, depth, MAX_ZONE_DEPTH, &constraint, recurse, verbose, unique_set); } else { ret = analyze_powercap(zones, MAX_ZONE_DEPTH, verbose); } if (ret) { print_common_help(); } return ret ? EXIT_FAILURE : EXIT_SUCCESS; } powercap-0.6.0/utils/powercap-set.c000066400000000000000000000165331423746651500172770ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Set powercap values. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include #include #include #include "powercap-sysfs.h" #include "util-common.h" static const char short_options[] = "-hp:z:c:E:je:l:s:"; static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"control-type", required_argument, NULL, 'p'}, {"zone", required_argument, NULL, 'z'}, {"constraint", required_argument, NULL, 'c'}, {"enabled", required_argument, NULL, 'E'}, {"z-energy", no_argument , NULL, 'j'}, {"z-enabled", required_argument, NULL, 'e'}, {"c-power-limit", required_argument, NULL, 'l'}, {"c-time-window", required_argument, NULL, 's'}, {0, 0, 0, 0} }; static void print_usage(void) { printf("Usage: powercap-set NAME [OPTION]...\n\n"); printf("Sets configurations for a powercap control type.\n"); printf("The control type NAME must not be empty or contain a '.' or '/'.\n\n"); printf("Options:\n"); printf(" -h, --help Print this message and exit\n"); printf(" -p, --control-type=NAME Deprecated, provide NAME as the first\n"); printf(" positional argument instead\n"); printf(" -z, --zone=ZONE(S) The zone/subzone numbers in the control type's\n"); printf(" powercap tree\n"); printf(" Separate zones/subzones with a colon\n"); printf(" E.g., for zone 0, subzone 2: \"-z 0:2\"\n"); printf(" -c, --constraint=CONSTRAINT The constraint number (none by default)\n"); printf(" -E, --enabled=1|0 Enable/disable the control type\n"); printf("The following zone-level arguments may be used together and require -z/--zone:\n"); printf(" -j, --z-energy Reset zone energy counter\n"); printf(" -e, --z-enabled=1|0 Enable/disable a zone\n"); printf("The following constraint-level arguments may be used together and require -z/--zone and -c/--constraint:\n"); printf(" -l, --c-power-limit=UW Set constraint power limit\n"); printf(" -s, --c-time-window=US Set constraint time window\n"); printf("\nPower units: microwatts (uW)\n"); printf("Time units: microseconds (us)\n"); } static void print_common_help(void) { printf("Considerations for common errors:\n"); printf("- Ensure that the control type exists, which may require loading a kernel module\n"); printf("- Ensure that you run with administrative (super-user) privileges\n"); printf("- Enabling/disabling a control type is an optional feature not supported by all control types\n"); printf("- Resetting a zone energy counter is an optional powercap feature not supported by all control types\n"); } int main(int argc, char** argv) { const char* control_type = NULL; u32_param ct_enabled = {0, 0}; uint32_t zones[MAX_ZONE_DEPTH] = { 0 }; uint32_t depth = 0; u32_param constraint = {0, 0}; int reset_energy = 0; u32_param enabled = {0, 0}; u64_param power_limit = {0, 0}; u64_param time_window = {0, 0}; int is_set_zone = 0; int is_set_constraint = 0; int c; int cont = 1; int ret = 0; /* Parse command-line arguments */ while (cont) { c = getopt_long(argc, argv, short_options, long_options, NULL); switch (c) { case -1: cont = 0; break; case 'h': print_usage(); return EXIT_SUCCESS; case 1: case 'p': if (control_type) { cont = 0; ret = -EINVAL; } control_type = optarg; break; case 'E': ret = set_u32_param(&ct_enabled, optarg, &cont); break; case 'z': ret = parse_zones(optarg, zones, MAX_ZONE_DEPTH, &depth, &cont); break; case 'c': ret = set_u32_param(&constraint, optarg, &cont); break; case 'j': if (reset_energy) { cont = 0; ret = -EINVAL; } reset_energy = 1; is_set_zone = 1; break; case 'e': ret = set_u32_param(&enabled, optarg, &cont); is_set_zone = 1; break; case 'l': ret = set_u64_param(&power_limit, optarg, &cont); is_set_constraint = 1; break; case 's': ret = set_u64_param(&time_window, optarg, &cont); is_set_constraint = 1; break; case '?': default: cont = 0; ret = -EINVAL; break; } } /* Verify argument combinations */ if (ret) { fprintf(stderr, "Invalid arguments\n"); } else if (!is_valid_powercap_control_type(control_type)) { fprintf(stderr, "Must specify control type NAME; value must not be empty or contain any '.' or '/' characters\n"); ret = -EINVAL; } else if (!depth && (is_set_zone || is_set_constraint)) { fprintf(stderr, "Must specify -z/--zone with zone-level or constraint-level argument\n"); ret = -EINVAL; } else if (depth && !(is_set_zone || is_set_constraint)) { fprintf(stderr, "Must specify zone-level or constraint-level argument with -z/--zone\n"); ret = -EINVAL; } else if (!constraint.set && is_set_constraint) { fprintf(stderr, "Must specify -c/--constraint with constraint-level argument\n"); ret = -EINVAL; } else if (constraint.set && !is_set_constraint) { fprintf(stderr, "Must specify constraint-level argument with -c/--constraint\n"); ret = -EINVAL; } else if (!ct_enabled.set && !is_set_zone && !is_set_constraint) { fprintf(stderr, "Nothing to do\n"); ret = -EINVAL; } if (ret) { print_usage(); return EXIT_FAILURE; } /* Check if control type/zones/constraint exist */ if (powercap_sysfs_control_type_exists(control_type)) { fprintf(stderr, "Control type does not exist\n"); ret = -EINVAL; } else if (depth && powercap_sysfs_zone_exists(control_type, zones, depth)) { fprintf(stderr, "Zone does not exist\n"); ret = -EINVAL; } else if (constraint.set && powercap_sysfs_constraint_exists(control_type, zones, depth, constraint.val)) { fprintf(stderr, "Constraint does not exist\n"); ret = -EINVAL; } if (ret) { print_common_help(); return EXIT_FAILURE; } /* Perform requested action(s) */ if (ct_enabled.set) { c = powercap_sysfs_control_type_set_enabled(control_type, ct_enabled.val); if (c) { perror("Error setting control type enabled/disabled"); ret |= c; } } if (reset_energy) { c = powercap_sysfs_zone_reset_energy_uj(control_type, zones, depth); if (c) { perror("Error setting zone energy counter"); ret |= c; } } if (enabled.set) { c = powercap_sysfs_zone_set_enabled(control_type, zones, depth, enabled.val); if (c) { perror("Error setting zone enabled/disabled"); ret |= c; } } if (power_limit.set) { c = powercap_sysfs_constraint_set_power_limit_uw(control_type, zones, depth, constraint.val, power_limit.val); if (c) { perror("Error setting constraint power limit"); ret |= c; } } if (time_window.set) { c = powercap_sysfs_constraint_set_time_window_us(control_type, zones, depth, constraint.val, time_window.val); if (c) { perror("Error setting constraint time window"); ret |= c; } } if (ret) { print_common_help(); } return ret ? EXIT_FAILURE : EXIT_SUCCESS; } powercap-0.6.0/utils/rapl-info.c000066400000000000000000000375441423746651500165620ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Get RAPL values. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include #include #include #include "powercap-rapl-sysfs.h" #include "util-common.h" static void print_headers(uint32_t zone, uint32_t do_zone, uint32_t sz, int is_sz) { if (do_zone) { printf("Zone %"PRIu32"\n", zone); } if (is_sz) { indent(1); printf("Subzone %"PRIu32"\n", sz); } } static void analyze_constraint(uint32_t zone, uint32_t sz, int is_sz, uint32_t constraint, int verbose) { char name[MAX_NAME_SIZE]; uint64_t val64; ssize_t sret; int ret; indent((uint32_t) is_sz + 1); printf("Constraint %"PRIu32"\n", constraint); sret = rapl_sysfs_constraint_get_name(zone, sz, is_sz, constraint, name, sizeof(name)); ret = sret > 0 ? 0 : (int) sret; str_or_verbose(verbose, (uint32_t) is_sz + 2, "name", name, ret); ret = rapl_sysfs_constraint_get_power_limit_uw(zone, sz, is_sz, constraint, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 2, "power_limit_uw", val64, ret); ret = rapl_sysfs_constraint_get_time_window_us(zone, sz, is_sz, constraint, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 2, "time_window_us", val64, ret); ret = rapl_sysfs_constraint_get_min_power_uw(zone, sz, is_sz, constraint, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 2, "min_power_uw", val64, ret); ret = rapl_sysfs_constraint_get_max_power_uw(zone, sz, is_sz, constraint, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 2, "max_power_uw", val64, ret); ret = rapl_sysfs_constraint_get_min_time_window_us(zone, sz, is_sz, constraint, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 2, "min_time_window_us", val64, ret); ret = rapl_sysfs_constraint_get_max_time_window_us(zone, sz, is_sz, constraint, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 2, "max_time_window_us", val64, ret); } static void analyze_zone(uint32_t zone, uint32_t sz, int is_sz, int verbose) { char name[MAX_NAME_SIZE]; uint64_t val64; uint32_t val32; ssize_t sret; int ret; print_headers(0, 0, sz, is_sz); sret = rapl_sysfs_zone_get_name(zone, sz, is_sz, name, sizeof(name)); ret = sret > 0 ? 0 : (int) sret; str_or_verbose(verbose, (uint32_t) is_sz + 1, "name", name, ret); ret = rapl_sysfs_zone_get_enabled(zone, sz, is_sz, &val32); u64_or_verbose(verbose, (uint32_t) is_sz + 1, "enabled", (uint64_t) val32, ret); ret = rapl_sysfs_zone_get_max_energy_range_uj(zone, sz, is_sz, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 1, "max_energy_range_uj", val64, ret); ret = rapl_sysfs_zone_get_energy_uj(zone, sz, is_sz, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 1, "energy_uj", val64, ret); ret = rapl_sysfs_zone_get_max_power_range_uw(zone, sz, is_sz, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 1, "max_power_range_uw", val64, ret); ret = rapl_sysfs_zone_get_power_uw(zone, sz, is_sz, &val64); u64_or_verbose(verbose, (uint32_t) is_sz + 1, "power_uw", val64, ret); for (val32 = 0; !rapl_sysfs_constraint_exists(zone, sz, is_sz, val32); val32++) { analyze_constraint(zone, sz, is_sz, val32, verbose); } } static void analyze_zone_recurse(uint32_t zone, int verbose) { uint32_t sz; print_headers(zone, 1, 0, 0); analyze_zone(zone, 0, 0, verbose); for (sz = 0; !rapl_sysfs_zone_exists(zone, sz, 1); sz++) { analyze_zone(zone, sz, 1, verbose); } } static void analyze_all_zones_recurse(int verbose) { uint32_t zone; for (zone = 0; !rapl_sysfs_zone_exists(zone, 0, 0); zone++) { analyze_zone_recurse(zone, verbose); } } static void print_num_zones(void) { uint32_t n = 0; while (!rapl_sysfs_zone_exists(n, 0, 0)) { n++; } printf("%"PRIu32"\n", n); } static void print_num_subzones(uint32_t zone) { uint32_t n = 0; while (!rapl_sysfs_zone_exists(zone, n, 1)) { n++; } printf("%"PRIu32"\n", n); } static const char short_options[] = "hvp:z:c:njJwWexlsUuTty"; static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, {"package", required_argument, NULL, 'p'}, {"zone", required_argument, NULL, 'p'}, {"subzone", required_argument, NULL, 'z'}, {"constraint", required_argument, NULL, 'c'}, {"nzones", no_argument, NULL, 'n'}, {"z-energy", no_argument, NULL, 'j'}, {"z-max-energy-range", no_argument, NULL, 'J'}, {"z-power", no_argument, NULL, 'w'}, {"z-max-power-range", no_argument, NULL, 'W'}, {"z-enabled", no_argument, NULL, 'e'}, {"z-name", no_argument, NULL, 'x'}, {"c-power-limit", no_argument, NULL, 'l'}, {"c-time-window", no_argument, NULL, 's'}, {"c-max-power", no_argument, NULL, 'U'}, {"c-min-power", no_argument, NULL, 'u'}, {"c-max-time-window", no_argument, NULL, 'T'}, {"c-min-time-window", no_argument, NULL, 't'}, {"c-name", no_argument, NULL, 'y'}, {0, 0, 0, 0} }; static void print_usage(void) { printf("\nThis utility is deprecated, use powercap-info instead.\n\n"); printf("Usage: rapl-info [OPTION]...\n"); printf("Options:\n"); printf(" -h, --help Print this message and exit\n"); printf(" -v, --verbose Print errors when files are not available\n"); printf(" -p, --zone=ZONE The zone number (none by default; 0 by default if\n"); printf(" using -z/--subzone and/or -c/--constraint)\n"); printf(" Ending with a colon prevents output for subzones\n"); printf(" E.g., for zone 0, but not subzones: \"-p 0:\"\n"); printf(" --package=PACKAGE Deprecated, use --zone instead\n"); printf(" -z, --subzone=SUBZONE The subzone number (none by default)\n"); printf(" -c, --constraint=CONSTRAINT The constraint number (none by default)\n"); printf("All remaining options below are mutually exclusive:\n"); printf(" -n, --nzones Print the number of zones found, or the number of\n"); printf(" subzones found if -p/--zone is set\n"); printf("The following are zone-level arguments (-z/--subzone is optional):\n"); printf(" -j, --z-energy Print zone energy counter\n"); printf(" -J, --z-max-energy-range Print zone maximum energy counter range\n"); printf(" -w, --z-power Print zone current power\n"); printf(" -W, --z-max-power-range Print zone maximum current power range\n"); printf(" -e, --z-enabled Print zone enabled/disabled status\n"); printf(" -x, --z-name Print zone name\n"); printf("The following are constraint-level arguments and require -c/--constraint (-z/--subzone is optional):\n"); printf(" -l, --c-power-limit Print constraint power limit\n"); printf(" -s, --c-time-window Print constraint time window\n"); printf(" -U, --c-max-power Print constraint maximum allowed power\n"); printf(" -u, --c-min-power Print constraint minimum allowed power\n"); printf(" -T, --c-max-time-window Print constraint maximum allowed time window\n"); printf(" -t, --c-min-time-window Print constraint minimum allowed time window\n"); printf(" -y, --c-name Print constraint name\n"); printf("\nSome fields are optional and will only be printed if they are available unless -v/--verbose is set.\n"); printf("If no zone/constraint-specific outputs are requested, all available zones and constraints will be shown.\n"); printf("\nEnergy units: microjoules (uJ)\n"); printf("Power units: microwatts (uW)\n"); printf("Time units: microseconds (us)\n"); } static void print_common_help(void) { printf("Considerations for common errors:\n"); printf("- Ensure that the intel_rapl kernel module is loaded\n"); printf("- Some files may simply not exist\n"); printf("- On some systems, the kernel always returns an error when reading constraint max power (-U/--c-max-power)\n"); } int main(int argc, char** argv) { u32_param zone = {0, 0}; u32_param subzone = {0, 0}; u32_param constraint = {0, 0}; int recurse = 1; int verbose = 0; int unique_set = 0; int c; int cont = 1; int ret = 0; uint64_t val64; uint32_t val32; char name[MAX_NAME_SIZE]; /* Parse command-line arguments */ while (cont) { c = getopt_long(argc, argv, short_options, long_options, NULL); switch (c) { case -1: cont = 0; break; case 'h': print_usage(); return EXIT_SUCCESS; case 'v': verbose = 1; break; case 'p': recurse = get_recurse(optarg); ret = set_u32_param(&zone, optarg, &cont); break; case 'z': ret = set_u32_param(&subzone, optarg, &cont); break; case 'c': ret = set_u32_param(&constraint, optarg, &cont); break; case 'n': case 'j': case 'J': case 'w': case 'W': case 'e': case 'x': case 'l': case 's': case 'U': case 'u': case 'T': case 't': case 'y': if (unique_set) { fprintf(stderr, "Only one of -n/--nzones, a zone-level argument, or a constraint-level argument is allowed at a time\n"); cont = 0; ret = -EINVAL; break; } unique_set = c; break; case '?': default: cont = 0; ret = -EINVAL; break; } } /* Verify argument combinations */ if (ret) { fprintf(stderr, "Unknown or duplicate arguments\n"); } else { switch (unique_set) { case 'n': if (subzone.set || constraint.set) { fprintf(stderr, "-n/--nzones cannot be used with -z/--subzone or -c/--constraint\n"); ret = -EINVAL; } break; case 'j': case 'J': case 'w': case 'W': case 'e': case 'x': if (constraint.set) { fprintf(stderr, "-c/--constraint cannot be set for zone-level arguments\n"); ret = -EINVAL; } break; case 'l': case 's': case 'U': case 'u': case 'T': case 't': case 'y': if (!constraint.set) { fprintf(stderr, "-c/--constraint must be set for constraint-level arguments\n"); ret = -EINVAL; } break; } } if (ret) { print_usage(); return EXIT_FAILURE; } /* Check if zone/subzone/constraint exist */ if (rapl_sysfs_zone_exists(zone.val, 0, 0)) { fprintf(stderr, "Zone does not exist\n"); ret = -EINVAL; } else if (subzone.set && rapl_sysfs_zone_exists(zone.val, subzone.val, 1)) { fprintf(stderr, "Subzone does not exist\n"); ret = -EINVAL; } else if (constraint.set && rapl_sysfs_constraint_exists(zone.val, subzone.val, subzone.set, constraint.val)) { fprintf(stderr, "Constraint does not exist\n"); ret = -EINVAL; } if (ret) { print_common_help(); return EXIT_FAILURE; } /* Perform requested action */ if (unique_set) { switch (unique_set) { case 'n': /* Print number of zones or subzones */ if (zone.set) { print_num_subzones(zone.val); } else { print_num_zones(); } break; case 'j': /* Get zone energy */ if (!(ret = rapl_sysfs_zone_get_energy_uj(zone.val, subzone.val, subzone.set, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get zone energy"); } break; case 'J': /* Get zone max energy range */ if (!(ret = rapl_sysfs_zone_get_max_energy_range_uj(zone.val, subzone.val, subzone.set, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get zone max energy range"); } break; case 'w': /* Get zone power */ if (!(ret = rapl_sysfs_zone_get_power_uw(zone.val, subzone.val, subzone.set, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get zone power"); } break; case 'W': /* Get zone max power range */ if (!(ret = rapl_sysfs_zone_get_max_power_range_uw(zone.val, subzone.val, subzone.set, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get zone max power range"); } break; case 'e': /* Get zone enabled */ if (!(ret = rapl_sysfs_zone_get_enabled(zone.val, subzone.val, subzone.set, &val32))) { printf("%"PRIu32"\n", val32); } else { perror("Failed to get zone enabled"); } break; case 'x': /* Get zone name */ if (rapl_sysfs_zone_get_name(zone.val, subzone.val, subzone.set, name, sizeof(name)) > 0) { printf("%s\n", name); } else { ret = -errno; perror("Failed to get zone name"); } break; case 'l': /* Get constraint power limit */ if (!(ret = rapl_sysfs_constraint_get_power_limit_uw(zone.val, subzone.val, subzone.set, constraint.val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint power limit"); } break; case 's': /* Get constraint time window */ if (!(ret = rapl_sysfs_constraint_get_time_window_us(zone.val, subzone.val, subzone.set, constraint.val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint time window"); } break; case 'U': /* Get constraint max power */ if (!(ret = rapl_sysfs_constraint_get_max_power_uw(zone.val, subzone.val, subzone.set, constraint.val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint max power"); } break; case 'u': /* Get constraint min power */ if (!(ret = rapl_sysfs_constraint_get_min_power_uw(zone.val, subzone.val, subzone.set, constraint.val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint min power"); } break; case 'T': /* Get constraint max time window */ if (!(ret = rapl_sysfs_constraint_get_max_time_window_us(zone.val, subzone.val, subzone.set, constraint.val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint max time window"); } break; case 't': /* Get constraint min time window */ if (!(ret = rapl_sysfs_constraint_get_min_time_window_us(zone.val, subzone.val, subzone.set, constraint.val, &val64))) { printf("%"PRIu64"\n", val64); } else { perror("Failed to get constraint min time window"); } break; case 'y': /* Get constraint name */ if (rapl_sysfs_constraint_get_name(zone.val, subzone.val, subzone.set, constraint.val, name, sizeof(name)) > 0) { printf("%s\n", name); } else { ret = -errno; perror("Failed to get constraint name"); } break; } } else if (zone.set || subzone.set || constraint.set) { /* Print summary of zone, subzone, or constraint */ if (constraint.set) { /* print constraint */ print_headers(zone.val, 1, subzone.val, subzone.set); analyze_constraint(zone.val, subzone.val, subzone.set, constraint.val, verbose); } else if (subzone.set) { /* print subzone */ print_headers(zone.val, 1, 0, 0); analyze_zone(zone.val, subzone.val, subzone.set, verbose); } else { /* print zone */ if (recurse) { analyze_zone_recurse(zone.val, verbose); } else { analyze_zone(zone.val, 0, 0, verbose); } } } else { /* print all zones */ if ((ret = rapl_sysfs_zone_exists(0, 0, 0))) { fprintf(stderr, "No RAPL zones found\n"); } else { analyze_all_zones_recurse(verbose); } } if (ret) { print_common_help(); } return ret ? EXIT_FAILURE : EXIT_SUCCESS; } powercap-0.6.0/utils/rapl-set.c000066400000000000000000000133341423746651500164110ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Set RAPL values. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include #include #include #include "powercap-rapl-sysfs.h" #include "util-common.h" static const char short_options[] = "hp:z:c:je:l:s:"; static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"package", required_argument, NULL, 'p'}, {"zone", required_argument, NULL, 'p'}, {"subzone", required_argument, NULL, 'z'}, {"constraint", required_argument, NULL, 'c'}, {"z-energy", no_argument , NULL, 'j'}, {"z-enabled", required_argument, NULL, 'e'}, {"c-power-limit", required_argument, NULL, 'l'}, {"c-time-window", required_argument, NULL, 's'}, {0, 0, 0, 0} }; static void print_usage(void) { printf("\nThis utility is deprecated, use powercap-set instead.\n\n"); printf("Usage: rapl-set [OPTION]...\n"); printf("Options:\n"); printf(" -h, --help Print this message and exit\n"); printf(" -p, --zone=ZONE The zone number (0 by default)\n"); printf(" --package=PACKAGE Deprecated, use --zone instead\n"); printf(" -z, --subzone=SUBZONE The subzone number (none by default)\n"); printf(" -c, --constraint=CONSTRAINT The constraint number (none by default)\n"); printf("The following is a zone-level argument (-z/--subzone is optional):\n"); printf(" -j, --z-energy Reset zone energy counter\n"); printf(" -e, --z-enabled=1|0 Enable/disable a zone\n"); printf("The following constraint-level arguments may be used together and require -c/--constraint (-z/--subzone is optional):\n"); printf(" -l, --c-power-limit=UW Set constraint power limit\n"); printf(" -s, --c-time-window=US Set constraint time window\n"); printf("\nPower units: microwatts (uW)\n"); printf("Time units: microseconds (us)\n"); } static void print_common_help(void) { printf("Considerations for common errors:\n"); printf("- Ensure that the intel_rapl kernel module is loaded\n"); printf("- Ensure that you run with administrative (super-user) privileges\n"); printf("- Resetting a zone energy counter is an optional powercap feature and may not be supported by RAPL\n"); } int main(int argc, char** argv) { u32_param zone = {0, 0}; u32_param subzone = {0, 0}; u32_param constraint = {0, 0}; int reset_energy = 0; u32_param enabled = {0, 0}; u64_param power_limit = {0, 0}; u64_param time_window = {0, 0}; int c; int cont = 1; int ret = 0; /* Parse command-line arguments */ while (cont) { c = getopt_long(argc, argv, short_options, long_options, NULL); switch (c) { case -1: cont = 0; break; case 'h': print_usage(); return EXIT_SUCCESS; case 'p': ret = set_u32_param(&zone, optarg, &cont); break; case 'z': ret = set_u32_param(&subzone, optarg, &cont); break; case 'c': ret = set_u32_param(&constraint, optarg, &cont); break; case 'j': if (reset_energy) { cont = 0; ret = -EINVAL; } reset_energy = 1; break; case 'e': ret = set_u32_param(&enabled, optarg, &cont); break; case 'l': ret = set_u64_param(&power_limit, optarg, &cont); break; case 's': ret = set_u64_param(&time_window, optarg, &cont); break; case '?': default: cont = 0; ret = -EINVAL; break; } } /* Verify argument combinations */ if (ret) { fprintf(stderr, "Invalid arguments\n"); } else if (constraint.set && !(power_limit.set || time_window.set)) { fprintf(stderr, "Must set at least one constraint-level argument when using -c/--constraint\n"); ret = -EINVAL; } else if (!constraint.set && (power_limit.set || time_window.set)) { fprintf(stderr, "Must specify -c/--constraint when using constraint-level arguments\n"); ret = -EINVAL; } else if (!(reset_energy || enabled.set || power_limit.set || time_window.set)) { printf("Nothing to do\n"); ret = -EINVAL; } if (ret) { print_usage(); return EXIT_FAILURE; } /* Check if zone/subzone/constraint exist */ if (rapl_sysfs_zone_exists(zone.val, 0, 0)) { fprintf(stderr, "Zone does not exist\n"); ret = -EINVAL; } else if (subzone.set && rapl_sysfs_zone_exists(zone.val, subzone.val, 1)) { fprintf(stderr, "Subzone does not exist\n"); ret = -EINVAL; } else if (constraint.set && rapl_sysfs_constraint_exists(zone.val, subzone.val, subzone.set, constraint.val)) { fprintf(stderr, "Constraint does not exist\n"); ret = -EINVAL; } if (ret) { print_common_help(); return EXIT_FAILURE; } /* Perform requested action(s) */ if (reset_energy) { c = rapl_sysfs_zone_reset_energy_uj(zone.val, subzone.val, subzone.set); if (c) { perror("Error setting energy counter"); ret |= c; } } if (enabled.set) { c = rapl_sysfs_zone_set_enabled(zone.val, subzone.val, subzone.set, enabled.val); if (c) { perror("Error setting enabled/disabled"); ret |= c; } } if (power_limit.set) { c = rapl_sysfs_constraint_set_power_limit_uw(zone.val, subzone.val, subzone.set, constraint.val, power_limit.val); if (c) { perror("Error setting power limit"); ret |= c; } } if (time_window.set) { c = rapl_sysfs_constraint_set_time_window_us(zone.val, subzone.val, subzone.set, constraint.val, time_window.val); if (c) { perror("Error setting time window"); ret |= c; } } if (ret) { print_common_help(); } return ret ? EXIT_FAILURE : EXIT_SUCCESS; } powercap-0.6.0/utils/util-common.c000066400000000000000000000061401423746651500171220ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Common utilities. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include #include #include #include "util-common.h" #define INDENT " " static int fail_invalid(int* cont) { if (cont) { *cont = 0; } return -EINVAL; } static int parse_status(const char* optarg, const char* end, int* cont) { /* Not an empty string, out of range, or having extra characters */ if (optarg == end || errno == ERANGE || end != optarg + strlen(optarg)) { return fail_invalid(cont); } return 0; } static int parse_u32(const char* optarg, uint32_t* val, int* cont) { char* end; errno = 0; *val = strtoul(optarg, &end, 0); return parse_status(optarg, end, cont); } static int parse_u64(const char* optarg, uint64_t* val, int* cont) { char* end; errno = 0; *val = strtoull(optarg, &end, 0); return parse_status(optarg, end, cont); } int set_u32_param(u32_param* p, const char* optarg, int* cont) { if (p->set || !optarg) { return fail_invalid(cont); } p->set = 1; return parse_u32(optarg, &p->val, cont); } int set_u64_param(u64_param* p, const char* optarg, int* cont) { if (p->set || !optarg) { return fail_invalid(cont); } p->set = 1; return parse_u64(optarg, &p->val, cont); } int parse_zones(const char* optarg, uint32_t* zones, uint32_t max_depth, uint32_t* depth, int* cont) { char* z; char* ptr; char* copy; int ret = -EINVAL; /* it's an error if depth is already set (zones were already parsed) */ if (*depth || !optarg) { return fail_invalid(cont); } if ((copy = strdup(optarg))) { z = strtok_r(copy, ":", &ptr); for (*depth = 0; z; (*depth)++) { if (*depth == max_depth) { ret = -ENOBUFS; break; } if ((ret = parse_u32(z, &zones[*depth], cont))) { break; } z = strtok_r(NULL, ":", &ptr); } free(copy); } else { ret = -ENOMEM; } if (ret && cont) { *cont = 0; } return ret; } void indent(uint32_t n) { while (n-- > 0) { printf(INDENT); } } static void maybe_verbose(int verbose, uint32_t in, const char* base) { if (verbose) { indent(in); printf("%s: %s\n", base, strerror(errno)); } } void str_or_verbose(int verbose, uint32_t in, const char* base, const char* val, int retval) { if (retval) { maybe_verbose(verbose, in, base); } else { indent(in); printf("%s: %s\n", base, val); } } void u64_or_verbose(int verbose, uint32_t in, const char* base, uint64_t val, int retval) { if (retval) { maybe_verbose(verbose, in, base); } else { indent(in); printf("%s: %"PRIu64"\n", base, val); } } int is_valid_powercap_control_type(const char* control_type) { return control_type && strlen(control_type) && strcspn(control_type, "./") == strlen(control_type); } int get_recurse(char* optarg) { size_t len; /* Default is to recurse */ int recurse = 1; if (optarg && (len = strlen(optarg)) && optarg[len - 1] == ':') { recurse = 0; /* Remove trailing colon */ optarg[len - 1] = '\0'; } return recurse; } powercap-0.6.0/utils/util-common.h000066400000000000000000000021271423746651500171300ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Common utilities. * * @author Connor Imes * @date 2017-08-24 */ #ifndef _UTIL_COMMON_H #define _UTIL_COMMON_H #ifdef __cplusplus extern "C" { #endif #include #ifndef MAX_ZONE_DEPTH /* A large number */ #define MAX_ZONE_DEPTH 64 #endif // MAX_ZONE_DEPTH #ifndef MAX_NAME_SIZE #define MAX_NAME_SIZE 1024 #endif // MAX_NAME_SIZE typedef struct u32_param { uint32_t val; int set; } u32_param; typedef struct u64_param { uint64_t val; int set; } u64_param; int set_u32_param(u32_param* p, const char* optarg, int* cont); int set_u64_param(u64_param* p, const char* optarg, int* cont); int parse_zones(const char* optarg, uint32_t* zones, uint32_t max_depth, uint32_t* depth, int* cont); void indent(uint32_t n); void str_or_verbose(int verbose, uint32_t in, const char* base, const char* val, int retval); void u64_or_verbose(int verbose, uint32_t in, const char* base, uint64_t val, int retval); int is_valid_powercap_control_type(const char* control_type); int get_recurse(char* optarg); #ifdef __cplusplus } #endif #endif