pax_global_header00006660000000000000000000000064135715026700014520gustar00rootroot0000000000000052 comment=ad05da76ca84d3c5277d932a32d15fd7c709aa7d powercap-0.2.0/000077500000000000000000000000001357150267000133375ustar00rootroot00000000000000powercap-0.2.0/.gitignore000066400000000000000000000000121357150267000153200ustar00rootroot00000000000000_build *~ powercap-0.2.0/.travis.yml000066400000000000000000000011731357150267000154520ustar00rootroot00000000000000os: - linux language: c compiler: - gcc - clang script: - mkdir _build - cd _build # Test build with stricter flags - export CFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector -g3 -pedantic -W -Wall -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wendif-labels -Wfloat-equal -Wformat=2 -Wformat-nonliteral -Winline -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wno-unused-parameter -Wpointer-arith -Wshadow -Wstrict-prototypes -Wstack-protector -Wswitch -Wundef -Wwrite-strings -std=c99" - cmake .. -DCMAKE_C_FLAGS="$CFLAGS" - cmake --build . - ctest --verbose powercap-0.2.0/AUTHORS000066400000000000000000000000771357150267000144130ustar00rootroot00000000000000Connor Imes powercap-0.2.0/CMakeLists.txt000066400000000000000000000053401357150267000161010ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-3-Clause cmake_minimum_required(VERSION 2.8.5) project(powercap) set(VERSION_MAJOR 0) set(VERSION_MINOR 2) set(VERSION_PATCH 0) set(PROJECT_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c99 -D_GNU_SOURCE") include(GNUInstallDirs) # See powercap-common.h for enumeration set(POWERCAP_LOG_LEVEL 2 CACHE STRING "Set the log level: 0=DEBUG, 1=INFO, 2=WARN (default), 3=ERROR, 4=OFF") include_directories(${PROJECT_SOURCE_DIR}/inc) add_subdirectory(utils) # 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_compile_definitions(powercap PRIVATE POWERCAP_LOG_LEVEL=${POWERCAP_LOG_LEVEL}) if (BUILD_SHARED_LIBS) set_target_properties(powercap PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${VERSION_MAJOR}) endif() # Tests add_executable(powercap-test test/powercap-test.c) target_link_libraries(powercap-test powercap) add_executable(powercap-rapl-test test/powercap-rapl-test.c) target_link_libraries(powercap-rapl-test powercap) add_executable(powercap-sysfs-test test/powercap-sysfs-test.c) target_link_libraries(powercap-sysfs-test powercap) enable_testing() macro(add_unit_test target) add_test(${target} ${EXECUTABLE_OUTPUT_PATH}/${target}) endmacro(add_unit_test) add_unit_test(powercap-test) # Requires a real system with root privileges # add_unit_test(powercap-rapl-test) add_unit_test(powercap-sysfs-test) # 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 install(TARGETS powercap DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES inc/powercap.h inc/powercap-sysfs.h inc/powercap-rapl.h inc/powercap-rapl-sysfs.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) install(DIRECTORY ${CMAKE_BINARY_DIR}/pkgconfig/ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) # 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) powercap-0.2.0/LICENSE000066400000000000000000000027551357150267000143550ustar00rootroot00000000000000Copyright (c) 2016-2019, 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.2.0/README.md000066400000000000000000000166751357150267000146350ustar00rootroot00000000000000# 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 zone/constraint-specific configurations * `rapl-info` - view Intel RAPL hierarchies or zone/constraint-specific configurations * `rapl-set` - set Intel RAPL 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 ## 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. If the `intel_rapl` kernel module is not loaded at startup, run with proper privileges: ```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 are the `powercap-sysfs.h` and `powercap-rapl-sysfs.h` interfaces for reading/writing to sysfs without the need to maintain state. These are 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_packages(); if (count == 0) { // none found (maybe the kernel module isn't loaded?) perror("powercap_rapl_get_num_packages") 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 package 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.2.0/RELEASES.md000066400000000000000000000037161357150267000150730ustar00rootroot00000000000000# Release Notes ## [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.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 [#1]: https://github.com/powercap/powercap/issues/1 powercap-0.2.0/cmake_uninstall.cmake.in000066400000000000000000000020121357150267000201120ustar00rootroot00000000000000if(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.2.0/inc/000077500000000000000000000000001357150267000141105ustar00rootroot00000000000000powercap-0.2.0/inc/powercap-rapl-sysfs.h000066400000000000000000000203241357150267000202030ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * 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 */ #ifndef _RAPL_SYSFS_H #define _RAPL_SYSFS_H #ifdef __cplusplus extern "C" { #endif #include #include /** * 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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.2.0/inc/powercap-rapl.h000066400000000000000000000200041357150267000170310ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * A simple interface for configuring RAPL using the intel_rapl kernel module. * 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" /** * 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; /** * 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_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.2.0/inc/powercap-sysfs.h000066400000000000000000000173341357150267000172560ustar00rootroot00000000000000/* * 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); /** * 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.2.0/inc/powercap.h000066400000000000000000000117611357150267000161070ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * A simple interface for configuring powercaps using sysfs. * 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 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; /** * 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 zone file type. * Returns the number of characters written excluding the terminating null byte, or a negative value in case of error. */ int powercap_zone_file_get_name(powercap_zone_file type, char* buf, size_t size); /** * Get the filename for a constraint file type. * Returns the number of characters written excluding the terminating null byte, or a negative value in case of error. */ int powercap_constraint_file_get_name(powercap_constraint_file type, uint32_t constraint, char* buf, size_t size); /** * 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.2.0/pkgconfig.in000066400000000000000000000005001357150267000156310ustar00rootroot00000000000000prefix=${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.2.0/src/000077500000000000000000000000001357150267000141265ustar00rootroot00000000000000powercap-0.2.0/src/powercap-common.c000066400000000000000000000144241357150267000174050ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Common functions. * * @author Connor Imes * @date 2017-08-24 */ #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_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 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(buf, size, "%s", ZONE_FILE[type]); } int 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(buf, size, "constraint_%"PRIu32"_%s", constraint, CONSTRAINT_FILE_SUFFIX[type]); } /* Returns 0 on error or if no more buffer space, with errno set */ static size_t snprintf_ret_to_size_t(int ret, size_t max_size) { if (ret < 0) { /* shouldn't happen */ if (!errno) { errno = EINVAL; } return 0; } if (ret == 0 || (size_t) ret >= max_size) { errno = ENOBUFS; return 0; } return (size_t) ret; } /* Returns 0 on failure like insufficient buffer size */ static size_t append_zone_dir(const char* control_type, const uint32_t* zones, uint32_t depth, char* path, size_t size) { size_t written; size_t n; uint32_t i; if ((written = snprintf_ret_to_size_t(snprintf(path, size - 1, "%s", control_type), size - 1))) { for (i = 0; i < depth; i++) { if (!(n = snprintf_ret_to_size_t(snprintf(path + written, size - written - 1, ":%x", zones[i]), size - written - 1))) { return 0; } written += n; } path[written++] = '/'; path[written] = '\0'; } return written; } size_t get_base_path(const char* control_type, const uint32_t* zones, uint32_t depth, char* path, size_t size) { size_t written; size_t n; uint32_t i; /* simple names only, trying to look outside the powercap directory is not allowed */ if (!control_type || !strlen(control_type) || strcspn(control_type, "./") != strlen(control_type) || (depth && !zones)) { errno = EINVAL; return 0; } if ((written = snprintf_ret_to_size_t(snprintf(path, size, POWERCAP_PATH"/%s/", control_type), size))) { for (i = 1; i <= depth; i++) { if (!(n = append_zone_dir(control_type, zones, i, path + written, size - written))) { return 0; } written += n; } } return written; } size_t get_zone_file_path(const char* control_type, const uint32_t* zones, uint32_t depth, powercap_zone_file type, char* path, size_t size) { size_t written; int n; if ((written = get_base_path(control_type, zones, depth, path, size))) { n = zone_file_get_name(type, path + written, size - written); if (!snprintf_ret_to_size_t(n, size - written)) { return 0; } written += (size_t) n; } return written; } size_t get_constraint_file_path(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type, char* path, size_t size) { size_t written; int n; if ((written = get_base_path(control_type, zones, depth, path, size))) { n = constraint_file_get_name(type, constraint, path + written, size - written); if (!snprintf_ret_to_size_t(n, size - written)) { return 0; } written += (size_t) n; } return written; } int open_zone_file(const char* control_type, const uint32_t* zones, uint32_t depth, powercap_zone_file type, int flags) { char path[PATH_MAX]; if (!get_zone_file_path(control_type, zones, depth, type, path, sizeof(path))) { return -errno; } return open(path, flags); } int open_constraint_file(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type, int flags) { char path[PATH_MAX]; if (!get_constraint_file_path(control_type, zones, depth, constraint, type, path, sizeof(path))) { return -errno; } return open(path, flags); } powercap-0.2.0/src/powercap-common.h000066400000000000000000000062761357150267000174200ustar00rootroot00000000000000/* * 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); /* Return is like snprintf, or negative error code if parameters are bad */ int zone_file_get_name(powercap_zone_file type, char* buf, size_t size); /* Return is like snprintf, or negative error code if parameters are bad */ int constraint_file_get_name(powercap_constraint_file type, uint32_t constraint, char* buf, size_t size); /* * Returns 0 on failure like insufficient buffer size or if control_type is NULL. * zones can be NULL only if depth is 0; path must not be NULL. */ size_t get_base_path(const char* control_type, const uint32_t* zones, uint32_t depth, char* path, size_t size); /* Returns 0 on failure like insufficient buffer size */ size_t get_zone_file_path(const char* control_type, const uint32_t* zones, uint32_t depth, powercap_zone_file type, char* path, size_t size); /* Returns 0 on failure like insufficient buffer size */ size_t get_constraint_file_path(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type, char* path, size_t size); /* Return fd on success, negative error code if path is too large, -1 on open failure */ int open_zone_file(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(const char* control_type, const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint_file type, int flags); #pragma GCC visibility pop #ifdef __cplusplus } #endif #endif powercap-0.2.0/src/powercap-rapl-sysfs.c000066400000000000000000000110511357150267000202110ustar00rootroot00000000000000/* * 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 rapl_sysfs_zone_exists(zone, 0, 0); } int rapl_sysfs_sz_exists(uint32_t zone, uint32_t sz) { return rapl_sysfs_zone_exists(zone, sz, 1); } 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.2.0/src/powercap-rapl.c000066400000000000000000000456341357150267000170620ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * RAPL implementation of powercap. * * @author Connor Imes * @date 2016-05-12 */ #include #include #include #include #include #include #include #include #include "powercap.h" #include "powercap-common.h" #include "powercap-rapl.h" #include "powercap-rapl-sysfs.h" #define CONTROL_TYPE "intel-rapl" #define CONSTRAINT_NUM_LONG 0 #define CONSTRAINT_NUM_SHORT 1 #define CONSTRAINT_NAME_LONG "long_term" #define CONSTRAINT_NAME_SHORT "short_term" #define PP_NAME_CORE "core" #define PP_NAME_UNCORE "uncore" #define PP_NAME_DRAM "dram" #define PP_NAME_PSYS "psys" static int rapl_open_zone_file(const uint32_t* zones, uint32_t depth, powercap_zone_file type, int flags, int* fd) { assert(fd != NULL); char buf[PATH_MAX]; if ((*fd = open_zone_file(CONTROL_TYPE, zones, depth, type, flags)) < 0) { // for logging purposes only get_zone_file_path(CONTROL_TYPE, zones, depth, type, buf, sizeof(buf)); if (errno == ENOENT) { // No such file or directory LOG(DEBUG, "rapl_open_zone_file: access: %s: %s\n", buf, strerror(errno)); *fd = 0; } else if (errno == EACCES && type == POWERCAP_ZONE_FILE_ENERGY_UJ) { // special case for energy_uj (it's actually read-only for RAPL) errno = 0; *fd = open_zone_file(CONTROL_TYPE, zones, depth, type, O_RDONLY); if (*fd < 0) { LOG(ERROR, "rapl_open_zone_file: open (RO): %s: %s\n", buf, strerror(errno)); } } else { LOG(ERROR, "rapl_open_zone_file: open: %s: %s\n", buf, strerror(errno)); } } return *fd < 0 ? -errno : 0; } static int rapl_open_constraint_file(const uint32_t* zones, uint32_t depth, powercap_constraint_file type, uint32_t constraint, int flags, int* fd) { assert(fd != NULL); char buf[PATH_MAX]; if ((*fd = open_constraint_file(CONTROL_TYPE, zones, depth, constraint, type, flags)) < 0) { // for logging purposes only get_constraint_file_path(CONTROL_TYPE, zones, depth, constraint, type, buf, sizeof(buf)); if (errno == ENOENT) { // No such file or directory LOG(DEBUG, "rapl_open_constraint_file: access: %s: %s\n", buf, strerror(errno)); *fd = 0; } else { LOG(ERROR, "rapl_open_constraint_file: open: %s: %s\n", buf, strerror(errno)); } } return *fd < 0 ? -errno : 0; } static int open_zone(const uint32_t* zones, uint32_t depth, powercap_zone* fds, int ro) { assert(fds != NULL); return rapl_open_zone_file(zones, depth, POWERCAP_ZONE_FILE_MAX_ENERGY_RANGE_UJ, O_RDONLY, &fds->max_energy_range_uj) || rapl_open_zone_file(zones, depth, POWERCAP_ZONE_FILE_ENERGY_UJ, ro ? O_RDONLY : O_RDWR, &fds->energy_uj) || rapl_open_zone_file(zones, depth, POWERCAP_ZONE_FILE_MAX_POWER_RANGE_UW, O_RDONLY, &fds->max_power_range_uw) || rapl_open_zone_file(zones, depth, POWERCAP_ZONE_FILE_POWER_UW, O_RDONLY, &fds->power_uw) || rapl_open_zone_file(zones, depth, POWERCAP_ZONE_FILE_ENABLED, ro ? O_RDONLY : O_RDWR, &fds->enabled) || rapl_open_zone_file(zones, depth, POWERCAP_ZONE_FILE_NAME, O_RDONLY, &fds->name); } static int open_constraint(const uint32_t* zones, uint32_t depth, uint32_t constraint, powercap_constraint* fds, int ro) { assert(fds != NULL); return rapl_open_constraint_file(zones, depth, POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW, constraint, ro ? O_RDONLY : O_RDWR, &fds->power_limit_uw) || rapl_open_constraint_file(zones, depth, POWERCAP_CONSTRAINT_FILE_TIME_WINDOW_US, constraint, ro ? O_RDONLY : O_RDWR, &fds->time_window_us) || rapl_open_constraint_file(zones, depth, POWERCAP_CONSTRAINT_FILE_MAX_POWER_UW, constraint, O_RDONLY, &fds->max_power_uw) || rapl_open_constraint_file(zones, depth, POWERCAP_CONSTRAINT_FILE_MIN_POWER_UW, constraint, O_RDONLY, &fds->min_power_uw) || rapl_open_constraint_file(zones, depth, POWERCAP_CONSTRAINT_FILE_MAX_TIME_WINDOW_US, constraint, O_RDONLY, &fds->max_time_window_us) || rapl_open_constraint_file(zones, depth, POWERCAP_CONSTRAINT_FILE_MIN_TIME_WINDOW_US, constraint, O_RDONLY, &fds->min_time_window_us) || rapl_open_constraint_file(zones, depth, POWERCAP_CONSTRAINT_FILE_NAME, constraint, O_RDONLY, &fds->name); } static int is_wrong_constraint(const powercap_constraint* fds, const char* expected_name) { assert(fds != NULL); assert(expected_name != NULL); char buf[32]; // assume constraint is wrong unless we can prove it's correct return powercap_constraint_get_name(fds, buf, sizeof(buf)) <= 0 || strncmp(buf, expected_name, sizeof(buf)) != 0; } static int open_all(uint32_t id, uint32_t pp, int is_pp, powercap_rapl_zone_files* fds, int ro) { assert(fds != NULL); powercap_constraint tmp; uint32_t zones[2]; uint32_t depth; zones[0] = id; zones[1] = pp; depth = is_pp ? 2 : 1; if (open_zone(zones, depth, &fds->zone, ro) || open_constraint(zones, depth, CONSTRAINT_NUM_LONG, &fds->constraint_long, ro) || open_constraint(zones, depth, CONSTRAINT_NUM_SHORT, &fds->constraint_short, ro)) { return 1; } // verify that constraints aren't reversed // note: never actually seen this problem, but not 100% sure it can't happen, so check anyway... if (is_wrong_constraint(&fds->constraint_long, CONSTRAINT_NAME_LONG) && is_wrong_constraint(&fds->constraint_short, CONSTRAINT_NAME_SHORT)) { LOG(WARN, "open_all: long and short term constraints are out of order for zone ID: %"PRIu32"\n", id); memcpy(&tmp, &fds->constraint_short, sizeof(powercap_constraint)); memcpy(&fds->constraint_short, &fds->constraint_long, sizeof(powercap_constraint)); memcpy(&fds->constraint_long, &tmp, sizeof(powercap_constraint)); } 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, "get_files: 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, "get_constraint_files: 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, "get_zone_fd: 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, "get_constraint_fd: Bad powercap_constraint_file: %d\n", file); errno = EINVAL; return -errno; } } static uint32_t get_num_power_planes(uint32_t id) { uint32_t sz = 0; while (!rapl_sysfs_zone_exists(id, sz, 1)) { sz++; } return sz; } static ssize_t get_pp_type(uint32_t id, uint32_t pp, powercap_rapl_zone* zone) { assert(zone != NULL); char name[8]; ssize_t ret; if ((ret = rapl_sysfs_zone_get_name(id, pp, 1, name, sizeof(name))) < 0) { /* Casting to int causes uninitialized warning in calling function, so we return ssize_t */ return ret; } if (!strncmp(name, PP_NAME_CORE, sizeof(PP_NAME_CORE))) { *zone = POWERCAP_RAPL_ZONE_CORE; } else if (!strncmp(name, PP_NAME_UNCORE, sizeof(PP_NAME_UNCORE))) { *zone = POWERCAP_RAPL_ZONE_UNCORE; } else if (!strncmp(name, PP_NAME_DRAM, sizeof(PP_NAME_DRAM))) { *zone = POWERCAP_RAPL_ZONE_DRAM; } else if (!strncmp(name, PP_NAME_PSYS, sizeof(PP_NAME_PSYS))) { *zone = POWERCAP_RAPL_ZONE_PSYS; } else { errno = EINVAL; return -errno; } return 0; } uint32_t powercap_rapl_get_num_packages(void) { uint32_t n = 0; while (!rapl_sysfs_zone_exists(n, 0, 0)) { n++; } if (!n) { LOG(ERROR, "powercap_rapl_get_num_packages: No top-level zones found - is the intel_rapl kernel module loaded?\n"); errno = ENOENT; } return n; } int powercap_rapl_init(uint32_t id, powercap_rapl_pkg* pkg, int read_only) { int ret; ssize_t sret; int err_save; uint32_t i; uint32_t npp; powercap_rapl_zone type; if (pkg == NULL) { errno = EINVAL; 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 zone and package power zone if (!(ret = open_all(id, 0, 0, &pkg->pkg, read_only))) { // get a count of subordinate power zones in this package npp = get_num_power_planes(id); // now get all power zones for (i = 0; i < npp && !ret; i++) { if ((sret = get_pp_type(id, i, &type))) { ret = (int) sret; break; } switch (type) { case POWERCAP_RAPL_ZONE_CORE: ret = open_all(id, i, 1, &pkg->core, read_only); break; case POWERCAP_RAPL_ZONE_UNCORE: ret = open_all(id, i, 1, &pkg->uncore, read_only); break; case POWERCAP_RAPL_ZONE_DRAM: ret = open_all(id, i, 1, &pkg->dram, read_only); break; case POWERCAP_RAPL_ZONE_PSYS: ret = open_all(id, i, 1, &pkg->psys, read_only); break; case POWERCAP_RAPL_ZONE_PACKAGE: default: assert(0); break; } } } if (ret) { err_save = errno; powercap_rapl_destroy(pkg); errno = err_save; } return ret; } static int powercap_rapl_close(int fd) { return (fd > 0 && close(fd)) ? -errno : 0; } static int fds_destroy_zone(powercap_zone* fds) { assert(fds != NULL); int ret = 0; ret |= powercap_rapl_close(fds->max_energy_range_uj); ret |= powercap_rapl_close(fds->energy_uj); ret |= powercap_rapl_close(fds->max_power_range_uw); ret |= powercap_rapl_close(fds->power_uw); ret |= powercap_rapl_close(fds->enabled); ret |= powercap_rapl_close(fds->name); return ret; } static int fds_destroy_zone_constraint(powercap_constraint* fds) { assert(fds != NULL); int ret = 0; ret |= powercap_rapl_close(fds->power_limit_uw); ret |= powercap_rapl_close(fds->time_window_us); ret |= powercap_rapl_close(fds->max_power_uw); ret |= powercap_rapl_close(fds->min_power_uw); ret |= powercap_rapl_close(fds->max_time_window_us); ret |= powercap_rapl_close(fds->min_time_window_us); ret |= powercap_rapl_close(fds->name); return ret; } static int fds_destroy_all(powercap_rapl_zone_files* files) { assert(files != NULL); int ret = 0; ret |= fds_destroy_zone(&files->zone); ret |= fds_destroy_zone_constraint(&files->constraint_long); ret |= fds_destroy_zone_constraint(&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) { // long constraint is always required for zones return powercap_rapl_is_constraint_supported(pkg, zone, POWERCAP_RAPL_CONSTRAINT_LONG); } int powercap_rapl_is_constraint_supported(const powercap_rapl_pkg* pkg, powercap_rapl_zone zone, powercap_rapl_constraint constraint) { // power limit is always required for constraints 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.2.0/src/powercap-sysfs.c000066400000000000000000000162371357150267000172700ustar00rootroot00000000000000/* * 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 /* Main powercap header only used for enums, not functions! */ #include "powercap.h" #include "powercap-common.h" #include "powercap-sysfs.h" static int zone_read_u64(const char* control_type, const uint32_t* zones, uint32_t depth, uint64_t* val, powercap_zone_file type) { int ret; int fd; if ((fd = open_zone_file(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) { int ret; int fd; if ((fd = open_constraint_file(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) { int ret; int fd; if ((fd = open_constraint_file(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; if (!get_base_path(control_type, zones, depth, path, sizeof(path))) { 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; /* power_limit_uw file must exist */ if (!get_constraint_file_path(control_type, zones, depth, constraint, POWERCAP_CONSTRAINT_FILE_POWER_LIMIT_UW, path, sizeof(path))) { return -errno; } if (stat(path, &ss) || !S_ISREG(ss.st_mode)) { errno = ENOSYS; return -errno; } return 0; } 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) { int ret; int fd; if ((fd = open_zone_file(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) { int ret; int fd; if ((fd = open_zone_file(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 (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) { ssize_t ret; int fd; if ((fd = open_zone_file(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) { ssize_t ret; int fd; if ((fd = open_constraint_file(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.2.0/src/powercap.c000066400000000000000000000067201357150267000161170ustar00rootroot00000000000000/* * 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_zone_file_get_name(powercap_zone_file type, char* buf, size_t size) { return zone_file_get_name(type, buf, size); } int powercap_constraint_file_get_name(powercap_constraint_file type, uint32_t constraint, char* buf, size_t size) { return constraint_file_get_name(type, constraint, buf, size); } #define VERIFY_ARG(arg) \ if (!(arg)) { \ errno = EINVAL; \ return -errno; \ } 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.2.0/test/000077500000000000000000000000001357150267000143165ustar00rootroot00000000000000powercap-0.2.0/test/powercap-rapl-test.c000066400000000000000000000300461357150267000202160ustar00rootroot00000000000000/* * 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; // optional parameter - boolean to enable read/write int main(int argc, char** argv) { uint32_t i, j; int ret = 0; int ro = 1; if (argc > 1) { // a value other than 0 enables read/write ro = !atoi(argv[1]); } // initialize uint32_t npackages = powercap_rapl_get_num_packages(); if (npackages == 0) { if (errno) { perror("powercap_rapl_get_num_packages"); } else { fprintf(stderr, "No RAPL packages found\n"); } return EXIT_FAILURE; } powercap_rapl_pkg* 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" package(s)\n", npackages); // test functionality for all zones for a single package powercap_rapl_pkg* p = &pkgs[0]; for (i = 0; i < NZONES; i++) { int supported; char name[32]; ssize_t name_ret; int enabled; uint64_t val; supported = powercap_rapl_is_zone_supported(p, ZONES[i]); if (supported < 0) { perror("powercap_rapl_is_zone_supported"); ret = EXIT_FAILURE; goto cleanup; } else if (supported == 0) { printf("Zone %s: 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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... // ret = EXIT_FAILURE; // goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } 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"); ret = EXIT_FAILURE; goto cleanup; } printf("%s constraint_(%s)_name: %s\n", ZONE_NAMES[i], cnst, name_ret > 0 ? name : "[None]"); } } } 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.2.0/test/powercap-sysfs-test.c000066400000000000000000000214001357150267000204210ustar00rootroot00000000000000/* * 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_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_zone_all_bad(); test_get_set_constraint_all_bad(); return EXIT_SUCCESS; } powercap-0.2.0/test/powercap-test.c000066400000000000000000000052461357150267000172660ustar00rootroot00000000000000/* * 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" 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); } int main(void) { test_powercap_zone_file_get_name(); test_powercap_constraint_file_get_name(); return EXIT_SUCCESS; } powercap-0.2.0/utils/000077500000000000000000000000001357150267000144775ustar00rootroot00000000000000powercap-0.2.0/utils/CMakeLists.txt000066400000000000000000000011551357150267000172410ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-3-Clause # Binaries add_executable(powercap-info powercap-info.c util-common.c) target_link_libraries(powercap-info powercap) add_executable(powercap-set powercap-set.c util-common.c) target_link_libraries(powercap-set powercap) add_executable(rapl-info rapl-info.c util-common.c) target_link_libraries(rapl-info powercap) add_executable(rapl-set rapl-set.c util-common.c) target_link_libraries(rapl-set powercap) # Install install(TARGETS powercap-info powercap-set rapl-info rapl-set DESTINATION ${CMAKE_INSTALL_BINDIR}) install(DIRECTORY man/ DESTINATION ${CMAKE_INSTALL_MANDIR}) powercap-0.2.0/utils/man/000077500000000000000000000000001357150267000152525ustar00rootroot00000000000000powercap-0.2.0/utils/man/man1/000077500000000000000000000000001357150267000161065ustar00rootroot00000000000000powercap-0.2.0/utils/man/man1/powercap-info.1000066400000000000000000000074571357150267000207560ustar00rootroot00000000000000.TH "POWERCAP-INFO" "1" "2018-11-04" "powercap" "powercap\-info" .SH "NAME" .LP powercap\-info \- get information from the Linux power capping framework .SH "SYNPOSIS" .LP \fBpowercap\-info \-p\fP \fINAME\fP [\fIOPTION\fP]... .SH "DESCRIPTION" .LP Prints configurations for a powercap control type. .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 are not available .TP \fB\-p,\fR \fB\-\-control\-type\fR=\fINAME\fP [REQUIRED] The powercap control type name. Must not be empty or contain a '.' or '/'. .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\-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\-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 \-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" .LP These examples use Intel RAPL, for which the control type is \fBintel\-rapl\fR. .TP \fBpowercap\-info \-p intel\-rapl\fP Print all RAPL zones. .TP \fBpowercap\-info \-p intel\-rapl \-z 0\fP Print only zone 0, which is usually named \fBpackage\-0\fR. .TP \fBpowercap\-info \-p intel\-rapl \-z 0: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 \fBpowercap\-info \-p intel\-rapl \-z 0 \-c 1\fP Print zone 0, constraint 1, which is usually the \fBshort_term\fR constraint for \fBpackage\-0\fR. .TP \fBpowercap\-info \-p intel\-rapl \-z 0 \-j\fP Print the energy counter for zone 0, which is usually named \fBpackage\-0\fR. .TP \fBpowercap\-info \-p intel\-rapl \-z 1: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 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), .BR rapl\-info (1), .BR rapl\-set (1)powercap-0.2.0/utils/man/man1/powercap-set.1000066400000000000000000000056031357150267000206050ustar00rootroot00000000000000.TH "POWERCAP\-SET" "1" "2018-11-04" "powercap" "powercap\-set" .SH "NAME" .LP powercap\-set \- manage power capping devices with the Linux power capping framework .SH "SYNPOSIS" .LP \fBpowercap\-set \-p\fP \fINAME\fP \fB\-z\fP \fIZONE(S)\fP [\fIOPTION\fP]... .SH "DESCRIPTION" .LP Sets configurations for a powercap control type. .SH "OPTIONS" .LP .TP \fB\-h,\fR \fB\-\-help\fR Prints the help screen .TP \fB\-p,\fR \fB\-\-control\-type\fR=\fINAME\fP [REQUIRED] The powercap control type name. Must not be empty or contain a '.' or '/'. .TP \fB\-z,\fR \fB\-\-zone=\fR\fIZONE(S)\fP [REQUIRED] 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) .LP The following zone-level arguments may be used together: .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: .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 These examples use Intel RAPL, for which the control type is \fBintel\-rapl\fR. .TP \fBpowercap\-set \-p intel\-rapl \-z 0 \-e 1\fP Enable zone 0, which is usually named \fBpackage\-0\fR. .TP \fBpowercap\-set \-p intel\-rapl \-z 0: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 \fBpowercap\-set \-p intel\-rapl \-z 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 \fBpowercap\-set \-p 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, 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 \fBpowercap\-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 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), .BR rapl\-info (1), .BR rapl\-set (1)powercap-0.2.0/utils/man/man1/rapl-info.1000066400000000000000000000126461357150267000200700ustar00rootroot00000000000000.TH "RAPL\-INFO" "1" "2019-11-27" "powercap" "rapl\-info" .SH "NAME" .LP rapl\-info \- get RAPL configurations .SH "SYNPOSIS" .LP \fBrapl\-info\fP [\fIOPTION\fP]... .SH "DESCRIPTION" .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.2.0/utils/man/man1/rapl-set.1000066400000000000000000000111241357150267000177160ustar00rootroot00000000000000.TH "RAPL\-SET" "1" "2019-11-27" "powercap" "rapl\-set" .SH "NAME" .LP rapl\-set \- set RAPL configurations .SH "SYNPOSIS" .LP \fBrapl\-set\fP [\fIOPTION\fP]... .SH "DESCRIPTION" .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.2.0/utils/powercap-info.c000066400000000000000000000417731357150267000174300ustar00rootroot00000000000000/* * SPDX-License-Identifier: BSD-3-Clause * * Get powercap values. * * @author Connor Imes * @date 2017-08-24 */ #include #include #include #include #include #include "powercap-sysfs.h" #include "util-common.h" static void print_parent_headers(const uint32_t* zones, uint32_t depth_start, uint32_t depth) { uint32_t i; uint32_t j; for (i = depth_start; i <= depth; i++) { indent(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) { char name[MAX_NAME_SIZE]; uint64_t val64; ssize_t sret; int ret; indent(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, depth + 1, "name", name, ret); ret = powercap_sysfs_constraint_get_power_limit_uw(control_type, zones, depth, constraint, &val64); u64_or_verbose(verbose, 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, 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, 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, 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, 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, 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) { char name[MAX_NAME_SIZE]; uint64_t val64; uint32_t val32; ssize_t sret; int ret; print_parent_headers(zones, depth, depth); sret = powercap_sysfs_zone_get_name(control_type, zones, depth, name, sizeof(name)); ret = sret > 0 ? 0 : (int) sret; str_or_verbose(verbose, depth, "name", name, ret); ret = powercap_sysfs_zone_get_enabled(control_type, zones, depth, &val32); u64_or_verbose(verbose, depth, "enabled", (uint64_t) val32, ret); ret = powercap_sysfs_zone_get_max_energy_range_uj(control_type, zones, depth, &val64); u64_or_verbose(verbose, depth, "max_energy_range_uj", val64, ret); ret = powercap_sysfs_zone_get_energy_uj(control_type, zones, depth, &val64); u64_or_verbose(verbose, depth, "energy_uj", val64, ret); ret = powercap_sysfs_zone_get_max_power_range_uw(control_type, zones, depth, &val64); u64_or_verbose(verbose, depth, "max_power_range_uw", val64, ret); ret = powercap_sysfs_zone_get_power_uw(control_type, zones, depth, &val64); u64_or_verbose(verbose, 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); } } /* 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) { if (!powercap_sysfs_zone_exists(control_type, zones, depth)) { /* Analyze this zone */ analyze_zone(control_type, zones, depth, verbose); if (depth < max_depth) { /* Analyze subzones */ zones[depth] = 0; analyze_all_zones_recurse(control_type, zones, depth + 1, max_depth, verbose); } /* Analyze next sibling zone */ zones[depth - 1]++; analyze_all_zones_recurse(control_type, zones, depth, max_depth, verbose); } } static void analyze_zone_recurse(const char* control_type, uint32_t* zones, uint32_t depth, uint32_t max_depth, int verbose) { if (!powercap_sysfs_zone_exists(control_type, zones, depth)) { /* Analyze this zone */ analyze_zone(control_type, zones, depth, verbose); if (depth < max_depth) { /* Analyze subzones */ zones[depth] = 0; analyze_all_zones_recurse(control_type, zones, depth + 1, max_depth, verbose); } } } 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 const char short_options[] = "hvp:z:c:njJwWexlsUuTty"; 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'}, {"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("Usage: powercap-info -p NAME [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, --control-type=NAME [REQUIRED] The powercap control type name\n"); printf(" Must not be empty or contain a '.' or '/'\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(" -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(" -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 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 control type exists (may require loading a kernel module, e.g., intel_rapl)\n"); printf("- Some files may simply not exist\n"); } 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; 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': 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 '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, "Invalid arguments\n"); ret = -EINVAL; } else if (!is_valid_control_type(control_type)) { fprintf(stderr, "Must specify -p/--control-type; value must not be empty or contain any '.' or '/' characters\n"); ret = -EINVAL; } else if (!depth && constraint.set) { fprintf(stderr, "Must specify -z/--zone with -c/--constraint\n"); ret = -EINVAL; } else if (unique_set) { if (unique_set == 'n') { if (constraint.set) { fprintf(stderr, "-n/--nzones cannot be used with -c/--constraint\n"); ret = -EINVAL; } } else if (!depth) { fprintf(stderr, "-z/--zone must be set for zone-level and constraint-level arguments\n"); ret = -EINVAL; } else { switch (unique_set) { case 'n': /* special case handled above */ 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 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 */ if (unique_set) { switch (unique_set) { case 'n': /* Print number of zones at the specified tree location */ print_num_zones(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); analyze_constraint(control_type, zones, depth, constraint.val, verbose); } else { /* print zone */ print_parent_headers(zones, 1, depth - 1); if (recurse) { analyze_zone_recurse(control_type, zones, depth, MAX_ZONE_DEPTH, verbose); } else { analyze_zone(control_type, zones, depth, verbose); } } } else { /* print all zones */ analyze_all_zones_recurse(control_type, zones, 1, MAX_ZONE_DEPTH, verbose); } if (ret) { print_common_help(); } return ret ? EXIT_FAILURE : EXIT_SUCCESS; } powercap-0.2.0/utils/powercap-set.c000066400000000000000000000144151357150267000172610ustar00rootroot00000000000000/* * 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: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'}, {"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 -p NAME -z ZONE(S) [OPTION]...\n"); printf("Options:\n"); printf(" -h, --help Print this message and exit\n"); printf(" -p, --control-type=NAME [REQUIRED] The powercap control type name\n"); printf(" Must not be empty or contain a '.' or '/'\n"); printf(" -z, --zone=ZONE(S) [REQUIRED] The zone/subzone numbers in the\n"); printf(" control type's 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("The following zone-level arguments may be used together:\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:\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 (may require loading a kernel module, e.g., intel_rapl)\n"); printf("- Ensure that you run with administrative (super-user) privileges\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; 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 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': if (control_type) { cont = 0; ret = -EINVAL; } control_type = optarg; 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; 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 (!is_valid_control_type(control_type)) { fprintf(stderr, "Must specify -p/--control-type; value must not be empty or contain any '.' or '/' characters\n"); ret = -EINVAL; } else if (!depth) { fprintf(stderr, "Must specify -z/--zone\n"); ret = -EINVAL; } 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) { if (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)) { 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 (reset_energy) { c = powercap_sysfs_zone_reset_energy_uj(control_type, zones, depth); if (c) { perror("Error setting energy counter"); ret |= c; } } if (enabled.set) { c = powercap_sysfs_zone_set_enabled(control_type, zones, depth, enabled.val); if (c) { perror("Error setting 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 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 time window"); ret |= c; } } if (ret) { print_common_help(); } return ret ? EXIT_FAILURE : EXIT_SUCCESS; } powercap-0.2.0/utils/rapl-info.c000066400000000000000000000372001357150267000165340ustar00rootroot00000000000000/* * 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(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, is_sz + 2, "name", name, ret); ret = rapl_sysfs_constraint_get_power_limit_uw(zone, sz, is_sz, constraint, &val64); u64_or_verbose(verbose, 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, 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, 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, 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, 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, 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, is_sz + 1, "name", name, ret); ret = rapl_sysfs_zone_get_enabled(zone, sz, is_sz, &val32); u64_or_verbose(verbose, 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, 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, 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, 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, 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("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.2.0/utils/rapl-set.c000066400000000000000000000132231357150267000163730ustar00rootroot00000000000000/* * 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("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.2.0/utils/util-common.c000066400000000000000000000061271357150267000171140ustar00rootroot00000000000000/* * 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_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.2.0/utils/util-common.h000066400000000000000000000021141357150267000171110ustar00rootroot00000000000000/* * 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 64 #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_control_type(const char* control_type); int get_recurse(char* optarg); #ifdef __cplusplus } #endif #endif