diff --git a/host-configs/lassen-4.14.0-ppc64le-gcc@8.3.1.cmake b/host-configs/lassen-4.14.0-ppc64le-gcc@8.3.1.cmake index a7075e308..6eb17eaa0 100644 --- a/host-configs/lassen-4.14.0-ppc64le-gcc@8.3.1.cmake +++ b/host-configs/lassen-4.14.0-ppc64le-gcc@8.3.1.cmake @@ -26,3 +26,5 @@ set(VARIORUM_WITH_NVIDIA_GPU OFF CACHE BOOL "") set(VARIORUM_DEBUG OFF CACHE BOOL "") set(BUILD_TESTS ON CACHE BOOL "") + +set(CMAKE_SHARED_LINKER_FLAGS "-lpthread" CACHE PATH "") diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index 2cc9acb3d..123e3edbf 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -16,6 +16,7 @@ set(BASIC_EXAMPLES variorum-cap-socket-power-limit-example variorum-disable-turbo-example variorum-enable-turbo-example + variorum-get-energy-json-example variorum-get-frequency-json-example variorum-get-node-power-domain-info-json-example variorum-get-power-json-example @@ -39,6 +40,7 @@ set(BASIC_EXAMPLES variorum-print-topology-example variorum-print-turbo-example variorum-print-verbose-counters-example + variorum-print-verbose-energy-example variorum-print-verbose-frequency-example variorum-print-verbose-gpu-utilization-example variorum-print-verbose-power-example diff --git a/src/examples/variorum-get-energy-json-example.c b/src/examples/variorum-get-energy-json-example.c new file mode 100644 index 000000000..e3550408a --- /dev/null +++ b/src/examples/variorum-get-energy-json-example.c @@ -0,0 +1,89 @@ +// Copyright 2019-2023 Lawrence Livermore National Security, LLC and other +// Variorum Project Developers. See the top-level LICENSE file for details. +// +// SPDX-License-Identifier: MIT + +#include +#include +#include + +#include +#include + +#ifdef SECOND_RUN +static inline double do_work(int input) +{ + int i; + double result = (double)input; + + for (i = 0; i < 100000; i++) + { + result += i * result; + } + + return result; +} +#endif + +int main(int argc, char **argv) +{ + int ret; + char *s = NULL; +#ifdef SECOND_RUN + int i; + int size = 1E4; + volatile double x = 0.0; +#endif + + const char *usage = "Usage: %s [-h] [-v]\n"; + int opt; + while ((opt = getopt(argc, argv, "hv")) != -1) + { + switch (opt) + { + case 'h': + printf(usage, argv[0]); + return 0; + case 'v': + printf("%s\n", variorum_get_current_version()); + return 0; + default: + fprintf(stderr, usage, argv[0]); + return -1; + } + } + + ret = variorum_get_energy_json(&s); + if (ret != 0) + { + printf("First run: JSON get energy failed!\n"); + free(s); + exit(-1); + } + + /* Print the entire JSON object */ + puts(s); + +#ifdef SECOND_RUN + for (i = 0; i < size; i++) + { + x += do_work(i); + } + printf("Final result: %f\n", x); + ret = variorum_get_energy_json(&s); + if (ret != 0) + { + printf("Second run: JSON get energy failed!\n"); + free(s); + exit(-1); + } + + /* Print the entire JSON object */ + puts(s); +#endif + + /* Deallocate the string */ + free(s); + + return ret; +} diff --git a/src/examples/variorum-print-energy-example.c b/src/examples/variorum-print-energy-example.c index 4b6decaa4..b1b746920 100644 --- a/src/examples/variorum-print-energy-example.c +++ b/src/examples/variorum-print-energy-example.c @@ -5,6 +5,7 @@ #include #include +#include #include @@ -30,10 +31,21 @@ int main(int argc, char **argv) } } + // First call to variorum_print_energy should print zero. ret = variorum_print_energy(); if (ret != 0) { - printf("Print core and Socket energy failed!\n"); + printf("Print core and socket energy failed!\n"); + return ret; + } + + sleep(2); + + // Second call to variorum_print_energy should print a valid value. + ret = variorum_print_energy(); + if (ret != 0) + { + printf("Print core and socket energy failed!\n"); + return ret; } - return ret; } diff --git a/src/examples/variorum-print-verbose-energy-example.c b/src/examples/variorum-print-verbose-energy-example.c new file mode 100644 index 000000000..70a2dff5d --- /dev/null +++ b/src/examples/variorum-print-verbose-energy-example.c @@ -0,0 +1,49 @@ +// Copyright 2019-2023 Lawrence Livermore National Security, LLC and other +// Variorum Project Developers. See the top-level LICENSE file for details. +// +// SPDX-License-Identifier: MIT + +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + int ret; + + const char *usage = "Usage: %s [-h] [-v]\n"; + int opt; + while ((opt = getopt(argc, argv, "hv")) != -1) + { + switch (opt) + { + case 'h': + printf(usage, argv[0]); + return 0; + case 'v': + printf("%s\n", variorum_get_current_version()); + return 0; + default: + fprintf(stderr, usage, argv[0]); + return -1; + } + } + + ret = variorum_print_verbose_energy(); + if (ret != 0) + { + printf("Print core and socket energy failed!\n"); + return ret; + } + + sleep(2); + + ret = variorum_print_verbose_energy(); + if (ret != 0) + { + printf("Print core and socket energy failed!\n"); + return ret; + } +} diff --git a/src/variorum/AMD/epyc.c b/src/variorum/AMD/epyc.c index 899159c83..06f508b04 100644 --- a/src/variorum/AMD/epyc.c +++ b/src/variorum/AMD/epyc.c @@ -367,7 +367,8 @@ static struct EPYC_19h_offsets msrs = .msr_pkg_energy_stat = 0xC001029B }; -int amd_cpu_epyc_print_energy() + +int amd_cpu_epyc_print_energy(int long_ver) { char *val = getenv("VARIORUM_LOG"); if (val != NULL && atoi(val) == 1) @@ -376,7 +377,7 @@ int amd_cpu_epyc_print_energy() } int ret; - if (!esmi_init()) + if (!esmi_init() && long_ver == 0) { int i; uint64_t energy; diff --git a/src/variorum/IBM/Power9.c b/src/variorum/IBM/Power9.c index 133d7e63e..17ffa2387 100644 --- a/src/variorum/IBM/Power9.c +++ b/src/variorum/IBM/Power9.c @@ -16,6 +16,15 @@ #include #endif +/* Figure out the right spot for this at some point */ +pthread_mutex_t mlock; +struct thread_args th_args; +pthread_attr_t mattr; +pthread_t mthread; + +/* For the get_energy sampling thread */ +static int active_sampling = 0; + int ibm_cpu_p9_get_power(int long_ver) { char *val = ("VARIORUM_LOG"); @@ -469,7 +478,7 @@ int ibm_cpu_p9_get_node_thermal_json(json_t *get_thermal_obj) int rc; int bytes; unsigned iter = 0; - unsigned nsockets; + unsigned nsockets = 0; #ifdef VARIORUM_WITH_IBM_CPU variorum_get_topology(&nsockets, NULL, NULL, P_IBM_CPU_IDX); @@ -597,7 +606,7 @@ int ibm_cpu_p9_get_node_frequency_json(json_t *get_frequency_obj_json) int rc; int bytes; unsigned iter = 0; - unsigned nsockets; + unsigned nsockets = 0; #ifdef VARIORUM_WITH_IBM_CPU variorum_get_topology(&nsockets, NULL, NULL, P_IBM_CPU_IDX); @@ -644,3 +653,203 @@ int ibm_cpu_p9_get_node_frequency_json(json_t *get_frequency_obj_json) close(fd); return 0; } + +int ibm_cpu_p9_get_energy(int long_ver) +{ + static int init = 0; + char hostname[1024]; + static struct timeval start; + struct timeval now; + + gethostname(hostname, 1024); + + if (!init) + { + init = 1; + gettimeofday(&start, NULL); + + if (long_ver == 0) + { + printf("_IBMENERGY Host AccumulatedEnergy_J Timestamp_sec\n"); + } + } + + /* Enter the function the first time */ + if (active_sampling == 0) + { + active_sampling = 1; + + gettimeofday(&now, NULL); + + /* Sampling interval is hardcoded at 250ms */ + th_args.sample_interval = 250; + th_args.energy_acc = 0; + + if (long_ver) + { + printf("_IBMENERGY Host: %s, Accumulated Energy: %lu J, Timestamp: %lf sec\n", + hostname, th_args.energy_acc, + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); + } + else + { + /* The first call should print zero as energy. */ + printf("%s %s %lu %lf\n", + "_IBMENERGY", hostname, th_args.energy_acc, + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); + } + + /* Start power measurement thread. */ + pthread_attr_init(&mattr); + pthread_attr_setdetachstate(&mattr, PTHREAD_CREATE_DETACHED); + pthread_mutex_init(&mlock, NULL); + pthread_create(&mthread, &mattr, power_measurement, NULL); + } + else + { + /* Stop power measurement thread. */ + active_sampling = 0; + + gettimeofday(&now, NULL); + + pthread_attr_destroy(&mattr); + + pthread_mutex_lock(&mlock); + if (long_ver) + { + printf("_IBMENERGY Host: %s, Accumulated Energy: %lu J, Timestamp: %lf sec\n", + hostname, th_args.energy_acc, + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); + } + else + { + printf("%s %s %lu %lf\n", + "_IBMENERGY", hostname, th_args.energy_acc, + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); + } + pthread_mutex_unlock(&mlock); + } + + return 0; +} + +unsigned long take_measurement(int fd) +{ + unsigned long power_sample = 0; + + char *val = ("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + void *buf; + int rc; + int bytes; + unsigned iter = 0; + + /* We assume that socket 0 on IBM Power9 reports total system power */ + lseek(fd, iter * OCC_SENSOR_DATA_BLOCK_SIZE, SEEK_SET); + + buf = malloc(OCC_SENSOR_DATA_BLOCK_SIZE); + + if (!buf) + { + printf("Failed to allocate\n"); + return -1; + } + + for (rc = bytes = 0; bytes < OCC_SENSOR_DATA_BLOCK_SIZE; bytes += rc) + { + rc = read(fd, buf + bytes, OCC_SENSOR_DATA_BLOCK_SIZE - bytes); + if (!rc || rc < 0) + { + break; + } + } + + if (bytes != OCC_SENSOR_DATA_BLOCK_SIZE) + { + printf("Failed to read data\n"); + free(buf); + return -1; + } + + power_sample = get_node_power(buf); + + free(buf); + return power_sample; +} + +void *power_measurement(void *arg) +{ + struct mstimer timer; + unsigned long curr_measurement; + int fd; + + /* Open inband_sensors file */ + fd = open("/sys/firmware/opal/exports/occ_inband_sensors", O_RDONLY); + if (fd < 0) + { + printf("Failed to open occ_inband_sensors file\n"); + } + else + { + init_msTimer(&timer, th_args.sample_interval); + + timer_sleep(&timer); + while (active_sampling) + { + /* Accummulate energy */ + pthread_mutex_lock(&mlock); + curr_measurement = take_measurement(fd); + th_args.energy_acc += curr_measurement * th_args.sample_interval; + pthread_mutex_unlock(&mlock); + timer_sleep(&timer); + } + /* Close inband_sensors file */ + close(fd); + } + return arg; +} + +int ibm_cpu_p9_get_node_energy_json(json_t *get_energy_obj) +{ + /* Enter the function the first time */ + if (active_sampling == 0) + { + active_sampling = 1; + + /* Sampling interval is hardcoded at 250ms */ + th_args.sample_interval = 250; + th_args.energy_acc = 0; + + /* Only set node_energy for now */ + json_object_set_new(get_energy_obj, "energy_node_joules", + json_integer(th_args.energy_acc)); + + /* Start power measurement thread. */ + pthread_attr_init(&mattr); + pthread_attr_setdetachstate(&mattr, PTHREAD_CREATE_DETACHED); + pthread_mutex_init(&mlock, NULL); + pthread_create(&mthread, &mattr, power_measurement, NULL); + } + else + { + /* Stop power measurement thread. */ + active_sampling = 0; + + /* Commenting out for now, results in invalid pointer and stack trace */ + pthread_attr_destroy(&mattr); + + pthread_mutex_lock(&mlock); + + /* Only set node_energy for now */ + json_object_set_new(get_energy_obj, "energy_node_joules", + json_integer(th_args.energy_acc)); + + pthread_mutex_unlock(&mlock); + } + + return 0; +} diff --git a/src/variorum/IBM/Power9.h b/src/variorum/IBM/Power9.h index 6ac3170e8..290a4c0c0 100644 --- a/src/variorum/IBM/Power9.h +++ b/src/variorum/IBM/Power9.h @@ -7,11 +7,24 @@ #define POWER9_H_INCLUDE #include +#include + +#include + +struct thread_args +{ + unsigned long sample_interval; + unsigned long energy_acc; +}; int ibm_cpu_p9_get_power( int long_ver ); +int ibm_cpu_p9_get_energy( + int long_ver +); + int ibm_cpu_p9_get_power_limits( int long_ver ); @@ -48,4 +61,17 @@ int ibm_cpu_p9_get_node_frequency_json( json_t *get_frequency_obj_json ); +/* Sampling functions for get_energy thread implementation */ +void *power_measurement( + void *arg +); + +unsigned long take_measurement( + int fd +); + +int ibm_cpu_p9_get_node_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/IBM/config_ibm.c b/src/variorum/IBM/config_ibm.c index 8c2160cf6..a0d236a04 100644 --- a/src/variorum/IBM/config_ibm.c +++ b/src/variorum/IBM/config_ibm.c @@ -36,9 +36,11 @@ int set_ibm_func_ptrs(int idx) g_platform[idx].variorum_get_power_json = ibm_cpu_p9_get_power_json; g_platform[idx].variorum_get_node_power_domain_info_json = ibm_cpu_p9_get_node_power_domain_info_json; + g_platform[idx].variorum_print_energy = ibm_cpu_p9_get_energy; g_platform[idx].variorum_get_thermals_json = ibm_cpu_p9_get_node_thermal_json; g_platform[idx].variorum_get_frequency_json = ibm_cpu_p9_get_node_frequency_json; + g_platform[idx].variorum_get_energy_json = ibm_cpu_p9_get_node_energy_json; } else { diff --git a/src/variorum/IBM/ibm_power_features.c b/src/variorum/IBM/ibm_power_features.c index 31c195067..b2e3f8df8 100644 --- a/src/variorum/IBM/ibm_power_features.c +++ b/src/variorum/IBM/ibm_power_features.c @@ -106,6 +106,37 @@ unsigned long read_sensor(const struct occ_sensor_data_header *hb, return 0; } +uint64_t get_node_power(const void *buf) +{ + int i; + struct occ_sensor_data_header *hb; + struct occ_sensor_name *md; + // Power in watts. + uint64_t pwrsys = 0; + + hb = (struct occ_sensor_data_header *)(uint64_t)buf; + md = (struct occ_sensor_name *)((uint64_t)hb + be32toh(hb->names_offset)); + + for (i = 0; i < be16toh(hb->nr_sensors); i++) + { + uint32_t offset = be32toh(md[i].reading_offset); + uint32_t scale = be32toh(md[i].scale_factor); + uint64_t sample = 0; + + // We are not reading counters here because power data doesn't need counter. + if (md[i].structure_type == OCC_SENSOR_READING_FULL) + { + sample = read_sensor(hb, offset, SENSOR_SAMPLE); + } + + if (strcmp(md[i].name, "PWRSYS") == 0) + { + pwrsys = (uint64_t)(sample * TO_FP(scale)); + } + } + return (pwrsys); +} + void print_power_sensors(int chipid, int long_ver, FILE *output, const void *buf) { diff --git a/src/variorum/IBM/ibm_power_features.h b/src/variorum/IBM/ibm_power_features.h index 1f414d99e..406da0285 100644 --- a/src/variorum/IBM/ibm_power_features.h +++ b/src/variorum/IBM/ibm_power_features.h @@ -177,4 +177,8 @@ void json_get_frequency_sensors( const void *buf ); +uint64_t get_node_power( + const void *buf +); + #endif diff --git a/src/variorum/Intel/Intel_06_2A.c b/src/variorum/Intel/Intel_06_2A.c index a3fdb6d74..ee5a775c6 100644 --- a/src/variorum/Intel/Intel_06_2A.c +++ b/src/variorum/Intel/Intel_06_2A.c @@ -552,3 +552,38 @@ int intel_cpu_fm_06_2a_get_frequencies(void) return 0; } + +int intel_cpu_fm_06_2a_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int intel_cpu_fm_06_2a_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_2A.h b/src/variorum/Intel/Intel_06_2A.h index 9808e35cf..72d174b28 100644 --- a/src/variorum/Intel/Intel_06_2A.h +++ b/src/variorum/Intel/Intel_06_2A.h @@ -106,6 +106,10 @@ int intel_cpu_fm_06_2a_get_power( int long_ver ); +int intel_cpu_fm_06_2a_get_energy( + int long_ver +); + int intel_cpu_fm_06_2a_enable_turbo( void ); @@ -150,4 +154,8 @@ int intel_cpu_fm_06_2a_get_clocks_json( json_t *get_clock_obj_json ); +int intel_cpu_fm_06_2a_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/Intel_06_2D.c b/src/variorum/Intel/Intel_06_2D.c index a75099081..4f32be87e 100644 --- a/src/variorum/Intel/Intel_06_2D.c +++ b/src/variorum/Intel/Intel_06_2D.c @@ -557,3 +557,38 @@ int intel_cpu_fm_06_2d_get_frequencies(void) return 0; } + +int intel_cpu_fm_06_2d_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int intel_cpu_fm_06_2d_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_2D.h b/src/variorum/Intel/Intel_06_2D.h index f17459aad..773870bde 100644 --- a/src/variorum/Intel/Intel_06_2D.h +++ b/src/variorum/Intel/Intel_06_2D.h @@ -108,6 +108,10 @@ int intel_cpu_fm_06_2d_get_power( int long_ver ); +int intel_cpu_fm_06_2d_get_energy( + int long_ver +); + int intel_cpu_fm_06_2d_enable_turbo( void ); @@ -152,4 +156,8 @@ int intel_cpu_fm_06_2d_get_clocks_json( json_t *get_clock_obj_json ); +int intel_cpu_fm_06_2d_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/Intel_06_3E.c b/src/variorum/Intel/Intel_06_3E.c index d56114533..2057dd37b 100644 --- a/src/variorum/Intel/Intel_06_3E.c +++ b/src/variorum/Intel/Intel_06_3E.c @@ -580,3 +580,38 @@ int intel_cpu_fm_06_3e_get_frequencies(void) return 0; } + +int intel_cpu_fm_06_3e_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int intel_cpu_fm_06_3e_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_3E.h b/src/variorum/Intel/Intel_06_3E.h index 2450a282f..9ba077670 100644 --- a/src/variorum/Intel/Intel_06_3E.h +++ b/src/variorum/Intel/Intel_06_3E.h @@ -109,6 +109,10 @@ int intel_cpu_fm_06_3e_get_power( int long_ver ); +int intel_cpu_fm_06_3e_get_energy( + int long_ver +); + int intel_cpu_fm_06_3e_enable_turbo( void ); @@ -153,4 +157,8 @@ int intel_cpu_fm_06_3e_get_clocks_json( json_t *get_clock_obj_json ); +int intel_cpu_fm_06_3e_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/Intel_06_3F.c b/src/variorum/Intel/Intel_06_3F.c index 1731c6672..3a1c897a3 100644 --- a/src/variorum/Intel/Intel_06_3F.c +++ b/src/variorum/Intel/Intel_06_3F.c @@ -14,10 +14,6 @@ #include #include -#ifdef LIBJUSTIFY_FOUND -#include -#endif - static struct haswell_3f_offsets msrs = { .msr_platform_info = 0xCE, @@ -547,3 +543,38 @@ int intel_cpu_fm_06_3f_get_frequencies(void) &msrs.msr_config_tdp_level1, &msrs.msr_config_tdp_level2); return 0; } + +int intel_cpu_fm_06_3f_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int intel_cpu_fm_06_3f_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_3F.h b/src/variorum/Intel/Intel_06_3F.h index 2fd83cd98..7ca75f2d2 100644 --- a/src/variorum/Intel/Intel_06_3F.h +++ b/src/variorum/Intel/Intel_06_3F.h @@ -111,6 +111,10 @@ int intel_cpu_fm_06_3f_get_power( int long_ver ); +int intel_cpu_fm_06_3f_get_energy( + int long_ver +); + int intel_cpu_fm_06_3f_enable_turbo( void ); @@ -155,4 +159,8 @@ int intel_cpu_fm_06_3f_get_clocks_json( json_t *get_clock_obj_json ); +int intel_cpu_fm_06_3f_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/Intel_06_4F.c b/src/variorum/Intel/Intel_06_4F.c index f2a3f2b1a..51512afeb 100644 --- a/src/variorum/Intel/Intel_06_4F.c +++ b/src/variorum/Intel/Intel_06_4F.c @@ -569,3 +569,38 @@ int intel_cpu_fm_06_4f_get_frequencies(void) &msrs.msr_config_tdp_level1, &msrs.msr_config_tdp_level2); return 0; } + +int intel_cpu_fm_06_4f_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int intel_cpu_fm_06_4f_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_4F.h b/src/variorum/Intel/Intel_06_4F.h index 802f40829..1c6e041f3 100644 --- a/src/variorum/Intel/Intel_06_4F.h +++ b/src/variorum/Intel/Intel_06_4F.h @@ -111,6 +111,10 @@ int intel_cpu_fm_06_4f_get_power( int long_ver ); +int intel_cpu_fm_06_4f_get_energy( + int long_ver +); + int intel_cpu_fm_06_4f_enable_turbo( void ); @@ -155,4 +159,8 @@ int intel_cpu_fm_06_4f_get_clocks_json( json_t *get_clock_obj_json ); +int intel_cpu_fm_06_4f_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/Intel_06_55.c b/src/variorum/Intel/Intel_06_55.c index 7a3ec5553..f6a520547 100644 --- a/src/variorum/Intel/Intel_06_55.c +++ b/src/variorum/Intel/Intel_06_55.c @@ -504,3 +504,38 @@ int intel_cpu_fm_06_55_get_frequencies(void) &msrs.msr_config_tdp_level1, &msrs.msr_config_tdp_level2); return 0; } + +int intel_cpu_fm_06_55_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int intel_cpu_fm_06_55_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_55.h b/src/variorum/Intel/Intel_06_55.h index a911231a3..8f044667b 100644 --- a/src/variorum/Intel/Intel_06_55.h +++ b/src/variorum/Intel/Intel_06_55.h @@ -111,6 +111,9 @@ int intel_cpu_fm_06_55_get_power( int long_ver ); +int intel_cpu_fm_06_55_get_energy( + int long_ver); + int intel_cpu_fm_06_55_poll_power( FILE *output ); @@ -147,4 +150,8 @@ int intel_cpu_fm_06_55_get_clocks_json( json_t *get_clock_obj_json ); +int intel_cpu_fm_06_55_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/Intel_06_6A.c b/src/variorum/Intel/Intel_06_6A.c index 4461de28e..e20956b2e 100644 --- a/src/variorum/Intel/Intel_06_6A.c +++ b/src/variorum/Intel/Intel_06_6A.c @@ -163,3 +163,38 @@ int intel_cpu_fm_06_6a_get_node_power_domain_info_json(char return 0; } + +int intel_cpu_fm_06_6a_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int intel_cpu_fm_06_6a_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_6A.h b/src/variorum/Intel/Intel_06_6A.h index 7bb5da6d1..8e92d51c0 100644 --- a/src/variorum/Intel/Intel_06_6A.h +++ b/src/variorum/Intel/Intel_06_6A.h @@ -40,6 +40,10 @@ int intel_cpu_fm_06_6a_get_power( int long_ver ); +int intel_cpu_fm_06_6a_get_energy( + int long_ver +); + int intel_cpu_fm_06_6a_get_features( void ); @@ -52,4 +56,8 @@ int intel_cpu_fm_06_6a_get_node_power_domain_info_json( char **get_domain_obj_str ); +int intel_cpu_fm_06_6a_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/Intel_06_8F.c b/src/variorum/Intel/Intel_06_8F.c index 3ef9a62bf..54196eb2b 100644 --- a/src/variorum/Intel/Intel_06_8F.c +++ b/src/variorum/Intel/Intel_06_8F.c @@ -186,3 +186,38 @@ int fm_06_8f_monitoring(FILE *output) msrs.ia32_mperf, msrs.ia32_time_stamp_counter); return 0; } + +int fm_06_8f_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int fm_06_8f_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_8F.h b/src/variorum/Intel/Intel_06_8F.h index 875738c5e..4754cd3ca 100644 --- a/src/variorum/Intel/Intel_06_8F.h +++ b/src/variorum/Intel/Intel_06_8F.h @@ -53,6 +53,10 @@ int fm_06_8f_get_power( int long_ver ); +int fm_06_8f_get_energy( + int long_ver +); + int fm_06_8f_get_features( void ); @@ -69,4 +73,8 @@ int fm_06_8f_monitoring( FILE *output ); +int fm_06_8f_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/Intel_06_9E.c b/src/variorum/Intel/Intel_06_9E.c index 5afa7cd4f..2de1bdc3d 100644 --- a/src/variorum/Intel/Intel_06_9E.c +++ b/src/variorum/Intel/Intel_06_9E.c @@ -489,3 +489,38 @@ int intel_cpu_fm_06_9e_get_frequencies(void) &msrs.msr_config_tdp_level1, &msrs.msr_config_tdp_level2); return 0; } + +int intel_cpu_fm_06_9e_get_energy(int long_ver) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + if (long_ver == 0) + { + print_energy_data(stdout, msrs.msr_rapl_power_unit, msrs.msr_pkg_energy_status, + msrs.msr_dram_energy_status); + } + else if (long_ver == 1) + { + print_verbose_energy_data(stdout, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + } + return 0; +} + +int intel_cpu_fm_06_9e_get_energy_json(json_t *get_energy_obj) +{ + char *val = getenv("VARIORUM_LOG"); + if (val != NULL && atoi(val) == 1) + { + printf("Running %s\n", __FUNCTION__); + } + + json_get_energy_data(get_energy_obj, msrs.msr_rapl_power_unit, + msrs.msr_pkg_energy_status, msrs.msr_dram_energy_status); + + return 0; +} diff --git a/src/variorum/Intel/Intel_06_9E.h b/src/variorum/Intel/Intel_06_9E.h index 015567c52..c25378ff1 100644 --- a/src/variorum/Intel/Intel_06_9E.h +++ b/src/variorum/Intel/Intel_06_9E.h @@ -111,6 +111,10 @@ int intel_cpu_fm_06_9e_get_power( int long_ver ); +int intel_cpu_fm_06_9e_get_energy( + int long_ver +); + int intel_cpu_fm_06_9e_poll_power( FILE *output ); @@ -143,4 +147,8 @@ int intel_cpu_fm_06_9e_get_clocks_json( json_t *get_clock_obj_json ); +int intel_cpu_fm_06_9e_get_energy_json( + json_t *get_energy_obj +); + #endif diff --git a/src/variorum/Intel/config_intel.c b/src/variorum/Intel/config_intel.c index 5347943c3..9c6985a73 100644 --- a/src/variorum/Intel/config_intel.c +++ b/src/variorum/Intel/config_intel.c @@ -80,6 +80,7 @@ int set_intel_func_ptrs(int idx) g_platform[idx].variorum_print_counters = intel_cpu_fm_06_2a_get_counters; g_platform[idx].variorum_print_frequency = intel_cpu_fm_06_2a_get_clocks; g_platform[idx].variorum_print_power = intel_cpu_fm_06_2a_get_power; + g_platform[idx].variorum_print_energy = intel_cpu_fm_06_2a_get_energy; g_platform[idx].variorum_print_turbo = intel_cpu_fm_06_2a_get_turbo_status; g_platform[idx].variorum_enable_turbo = intel_cpu_fm_06_2a_enable_turbo; g_platform[idx].variorum_disable_turbo = intel_cpu_fm_06_2a_disable_turbo; @@ -111,6 +112,7 @@ int set_intel_func_ptrs(int idx) g_platform[idx].variorum_print_counters = intel_cpu_fm_06_2d_get_counters; g_platform[idx].variorum_print_frequency = intel_cpu_fm_06_2d_get_clocks; g_platform[idx].variorum_print_power = intel_cpu_fm_06_2d_get_power; + g_platform[idx].variorum_print_energy = intel_cpu_fm_06_2d_get_energy; g_platform[idx].variorum_print_turbo = intel_cpu_fm_06_2d_get_turbo_status; g_platform[idx].variorum_enable_turbo = intel_cpu_fm_06_2d_enable_turbo; g_platform[idx].variorum_disable_turbo = intel_cpu_fm_06_2d_disable_turbo; @@ -143,6 +145,7 @@ int set_intel_func_ptrs(int idx) g_platform[idx].variorum_print_counters = intel_cpu_fm_06_3e_get_counters; g_platform[idx].variorum_print_frequency = intel_cpu_fm_06_3e_get_clocks; g_platform[idx].variorum_print_power = intel_cpu_fm_06_3e_get_power; + g_platform[idx].variorum_print_energy = intel_cpu_fm_06_3e_get_energy; g_platform[idx].variorum_print_turbo = intel_cpu_fm_06_3e_get_turbo_status; g_platform[idx].variorum_enable_turbo = intel_cpu_fm_06_3e_enable_turbo; g_platform[idx].variorum_disable_turbo = intel_cpu_fm_06_3e_disable_turbo; @@ -175,6 +178,7 @@ int set_intel_func_ptrs(int idx) g_platform[idx].variorum_print_counters = intel_cpu_fm_06_3f_get_counters; g_platform[idx].variorum_print_frequency = intel_cpu_fm_06_3f_get_clocks; g_platform[idx].variorum_print_power = intel_cpu_fm_06_3f_get_power; + g_platform[idx].variorum_print_energy = intel_cpu_fm_06_3f_get_energy; g_platform[idx].variorum_print_turbo = intel_cpu_fm_06_3f_get_turbo_status; g_platform[idx].variorum_enable_turbo = intel_cpu_fm_06_3f_enable_turbo; g_platform[idx].variorum_disable_turbo = intel_cpu_fm_06_3f_disable_turbo; @@ -192,6 +196,8 @@ int set_intel_func_ptrs(int idx) intel_cpu_fm_06_3f_get_frequencies; g_platform[idx].variorum_get_thermals_json = intel_cpu_fm_06_3f_get_thermals_json; + g_platform[idx].variorum_get_energy_json = + intel_cpu_fm_06_3f_get_energy_json; } // Broadwell 06_4F else if (*g_platform[idx].arch_id == FM_06_4F) @@ -205,6 +211,7 @@ int set_intel_func_ptrs(int idx) g_platform[idx].variorum_print_counters = intel_cpu_fm_06_4f_get_counters; g_platform[idx].variorum_print_frequency = intel_cpu_fm_06_4f_get_clocks; g_platform[idx].variorum_print_power = intel_cpu_fm_06_4f_get_power; + g_platform[idx].variorum_print_energy = intel_cpu_fm_06_4f_get_energy; g_platform[idx].variorum_print_turbo = intel_cpu_fm_06_4f_get_turbo_status; g_platform[idx].variorum_enable_turbo = intel_cpu_fm_06_4f_enable_turbo; g_platform[idx].variorum_disable_turbo = intel_cpu_fm_06_4f_disable_turbo; @@ -224,6 +231,8 @@ int set_intel_func_ptrs(int idx) intel_cpu_fm_06_4f_get_thermals_json; g_platform[idx].variorum_get_frequency_json = intel_cpu_fm_06_3f_get_clocks_json; + g_platform[idx].variorum_get_energy_json = + intel_cpu_fm_06_4f_get_energy_json; } // Skylake 06_55 else if (*g_platform[idx].arch_id == FM_06_55) @@ -237,6 +246,7 @@ int set_intel_func_ptrs(int idx) g_platform[idx].variorum_print_counters = intel_cpu_fm_06_55_get_counters; g_platform[idx].variorum_print_frequency = intel_cpu_fm_06_55_get_clocks; g_platform[idx].variorum_print_power = intel_cpu_fm_06_55_get_power; + g_platform[idx].variorum_print_energy = intel_cpu_fm_06_55_get_energy; //g_platform[idx].variorum_print_turbo = intel_cpu_fm_06_55_get_turbo_status; //g_platform[idx].variorum_enable_turbo = intel_cpu_fm_06_55_enable_turbo; //g_platform[idx].variorum_disable_turbo = intel_cpu_fm_06_55_disable_turbo; @@ -256,6 +266,8 @@ int set_intel_func_ptrs(int idx) intel_cpu_fm_06_55_get_thermals_json; g_platform[idx].variorum_get_frequency_json = intel_cpu_fm_06_55_get_clocks_json; + g_platform[idx].variorum_get_energy_json = + intel_cpu_fm_06_55_get_energy_json; } // Kaby Lake 06_9E else if (*g_platform[idx].arch_id == FM_06_9E) @@ -269,6 +281,7 @@ int set_intel_func_ptrs(int idx) g_platform[idx].variorum_print_counters = intel_cpu_fm_06_9e_get_counters; g_platform[idx].variorum_print_frequency = intel_cpu_fm_06_9e_get_clocks; g_platform[idx].variorum_print_power = intel_cpu_fm_06_9e_get_power; + g_platform[idx].variorum_print_energy = intel_cpu_fm_06_9e_get_energy; //g_platform[idx].variorum_print_turbo = intel_cpu_fm_06_9e_get_turbo_status; //g_platform[idx].variorum_enable_turbo = intel_cpu_fm_06_9e_enable_turbo; //g_platform[idx].variorum_disable_turbo = intel_cpu_fm_06_9e_disable_turbo; @@ -294,6 +307,7 @@ int set_intel_func_ptrs(int idx) intel_cpu_fm_06_6a_get_power_limits; g_platform[idx].variorum_print_features = intel_cpu_fm_06_6a_get_features; g_platform[idx].variorum_print_power = intel_cpu_fm_06_6a_get_power; + g_platform[idx].variorum_print_energy = intel_cpu_fm_06_6a_get_energy; } // Sapphire Rapids 06_8F else if (*g_platform[idx].arch_id == FM_06_8F) @@ -301,6 +315,7 @@ int set_intel_func_ptrs(int idx) g_platform[idx].variorum_print_power_limit = fm_06_8f_get_power_limits; g_platform[idx].variorum_print_features = fm_06_8f_get_features; g_platform[idx].variorum_print_power = fm_06_8f_get_power; + g_platform[idx].variorum_print_energy = fm_06_8f_get_energy; g_platform[idx].variorum_get_power_json = fm_06_8f_get_power_json; g_platform[idx].variorum_get_node_power_domain_info_json = diff --git a/src/variorum/Intel/intel_power_features.c b/src/variorum/Intel/intel_power_features.c index 85a5b59f5..d69bb67ab 100644 --- a/src/variorum/Intel/intel_power_features.c +++ b/src/variorum/Intel/intel_power_features.c @@ -1129,6 +1129,18 @@ void print_verbose_power_data(FILE *writedest, off_t msr_rapl_unit, fprintf(writedest, "pkg%d_bits = %8.4lx pkg%d_joules= %8.4f\n", i, *rapl->pkg_bits[i], i, rapl->pkg_joules[i]); #endif +#ifdef LIBJUSTIFY_FOUND + cprintf(writedest, + "_PACKAGE_ENERGY_STATUS Offset: 0x%lx, Host: %s, Socket: %d, Bits: 0x%lx, Energy: %lf J, Power: %lf W, Elapsed: %lf sec, Timestamp: %lf sec\n", + msr_pkg_energy_status, hostname, i, *rapl->pkg_bits[i], rapl->pkg_joules[i], + rapl->pkg_watts[i], rapl->elapsed, + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); + cprintf(writedest, + "_DRAM_ENERGY_STATUS Offset: 0x%lx, Host: %s, Socket: %d, Bits: 0x%lx, Energy: %lf J, Power: %lf W, Elapsed: %lf sec, Timestamp: %lf sec\n", + msr_dram_energy_status, hostname, i, *rapl->dram_bits[i], rapl->dram_joules[i], + rapl->dram_watts[i], rapl->elapsed, + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); +#else fprintf(writedest, "_PACKAGE_ENERGY_STATUS Offset: 0x%lx, Host: %s, Socket: %d, Bits: 0x%lx, Energy: %lf J, Power: %lf W, Elapsed: %lf sec, Timestamp: %lf sec\n", msr_pkg_energy_status, hostname, i, *rapl->pkg_bits[i], rapl->pkg_joules[i], @@ -1139,6 +1151,7 @@ void print_verbose_power_data(FILE *writedest, off_t msr_rapl_unit, msr_dram_energy_status, hostname, i, *rapl->dram_bits[i], rapl->dram_joules[i], rapl->dram_watts[i], rapl->elapsed, now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); +#endif } } @@ -1599,3 +1612,152 @@ void get_all_power_data(FILE *writedest, off_t msr_pkg_power_limit, fprintf(writedest, "\n"); #endif } + +void print_energy_data(FILE *writedest, off_t msr_rapl_unit, + off_t msr_pkg_energy_status, off_t msr_dram_energy_status) +{ + static int init = 0; + static struct rapl_data *rapl = NULL; + static struct timeval start; + unsigned nsockets = 0; + struct timeval now; + char hostname[1024]; + unsigned i; + + gethostname(hostname, 1024); +#ifdef VARIORUM_WITH_INTEL_CPU + variorum_get_topology(&nsockets, NULL, NULL, P_INTEL_CPU_IDX); +#endif + + get_power(msr_rapl_unit, msr_pkg_energy_status, msr_dram_energy_status); + + if (!init) + { + gettimeofday(&start, NULL); +#if LIBJUSTIFY_FOUND + cprintf(writedest, "_PACKAGE_ENERGY_STATUS Offset Host Socket Bits Energy_J\n"); +#else + fprintf(writedest, "_PACKAGE_ENERGY_STATUS Offset Host Socket Bits Energy_J\n"); +#endif + rapl_storage(&rapl); + } + gettimeofday(&now, NULL); + for (i = 0; i < nsockets; i++) + { +#if LIBJUSTIFY_FOUND + cprintf(writedest, "_PACKAGE_ENERGY_STATUS %lx %s %d 0x%lx %lf\n", + msr_pkg_energy_status, hostname, i, *rapl->pkg_bits[i], rapl->pkg_joules[i]); +#else + fprintf(writedest, "_PACKAGE_ENERGY_STATUS %lx %s %d 0x%lx %lf\n", + msr_pkg_energy_status, hostname, i, *rapl->pkg_bits[i], rapl->pkg_joules[i]); +#endif + } + + if (!init) + { +#if LIBJUSTIFY_FOUND + cprintf(writedest, "_DRAM_ENERGY_STATUS Offset Host Socket Bits Energy_J\n"); +#else + fprintf(writedest, "_DRAM_ENERGY_STATUS Offset Host Socket Bits Energy_J\n"); +#endif + init = 1; + } + for (i = 0; i < nsockets; i++) + { +#if LIBJUSTIFY_FOUND + cprintf(writedest, "_DRAM_ENERGY_STATUS %lx %s %d 0x%lx %lf\n", + msr_dram_energy_status, hostname, i, *rapl->dram_bits[i], rapl->dram_joules[i]); +#else + fprintf(writedest, "_DRAM_ENERGY_STATUS %lx %s %d 0x%lx %lf\n", + msr_dram_energy_status, hostname, i, *rapl->dram_bits[i], rapl->dram_joules[i]); +#endif + } +} + +void print_verbose_energy_data(FILE *writedest, off_t msr_rapl_unit, + off_t msr_pkg_energy_status, off_t msr_dram_energy_status) +{ + static int init = 0; + static struct rapl_data *rapl = NULL; + static struct timeval start; + unsigned nsockets = 0; + struct timeval now; + char hostname[1024]; + unsigned i; + + gethostname(hostname, 1024); +#ifdef VARIORUM_WITH_INTEL_CPU + variorum_get_topology(&nsockets, NULL, NULL, P_INTEL_CPU_IDX); +#endif + + get_power(msr_rapl_unit, msr_pkg_energy_status, msr_dram_energy_status); + + if (!init) + { + init = 1; + gettimeofday(&start, NULL); + rapl_storage(&rapl); + } + gettimeofday(&now, NULL); + for (i = 0; i < nsockets; i++) + { +#if LIBJUSTIFY_FOUND + cprintf(writedest, + "_PACKAGE_ENERGY_STATUS Offset: 0x%lx, Host: %s, Socket: %d, Bits: 0x%lx, Energy: %lf J, Timestamp: %lf sec\n", + msr_pkg_energy_status, hostname, i, *rapl->pkg_bits[i], rapl->pkg_joules[i], + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); + cprintf(writedest, + "_DRAM_ENERGY_STATUS Offset: 0x%lx, Host: %s, Socket: %d, Bits: 0x%lx, Energy: %lf J, Timestamp: %lf sec\n", + msr_dram_energy_status, hostname, i, *rapl->dram_bits[i], rapl->dram_joules[i], + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); +#else + fprintf(writedest, + "_PACKAGE_ENERGY_STATUS Offset: 0x%lx, Host: %s, Socket: %d, Bits: 0x%lx, Energy: %lf J, Timestamp: %lf sec\n", + msr_pkg_energy_status, hostname, i, *rapl->pkg_bits[i], rapl->pkg_joules[i], + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); + fprintf(writedest, + "_DRAM_ENERGY_STATUS Offset: 0x%lx, Host: %s, Socket: %d, Bits: 0x%lx, Energy: %lf J, Timestamp: %lf sec\n", + msr_dram_energy_status, hostname, i, *rapl->dram_bits[i], rapl->dram_joules[i], + now.tv_sec - start.tv_sec + (now.tv_usec - start.tv_usec) / 1000000.0); +#endif + } +} + +void json_get_energy_data(json_t *get_energy_obj, off_t msr_rapl_unit, + off_t msr_pkg_energy_status, off_t msr_dram_energy_status) +{ + static int init = 0; + static struct rapl_data *rapl = NULL; + unsigned nsockets = 0; + unsigned i; + double node_energy = 0.0; + +#ifdef VARIORUM_WITH_INTEL_CPU + variorum_get_topology(&nsockets, NULL, NULL, P_INTEL_CPU_IDX); +#endif + + get_power(msr_rapl_unit, msr_pkg_energy_status, msr_dram_energy_status); + if (!init) + { + rapl_storage(&rapl); + } + + for (i = 0; i < nsockets; i++) + { + char socketid[12]; + snprintf(socketid, 12, "socket_%d", i); + + json_t *socket_obj = json_object(); + json_object_set_new(get_energy_obj, socketid, socket_obj); + + json_object_set_new(socket_obj, "energy_cpu_joules", + json_real(rapl->pkg_joules[i])); + json_object_set_new(socket_obj, "energy_mem_joules", + json_real(rapl->dram_joules[i])); + node_energy += rapl->pkg_joules[i] + rapl->dram_joules[i]; + } + + // Set the node energy key with energy node value. + json_object_set_new(get_energy_obj, "energy_node_joules", + json_real(node_energy)); +} diff --git a/src/variorum/Intel/intel_power_features.h b/src/variorum/Intel/intel_power_features.h index 872902a26..a4f001bb1 100644 --- a/src/variorum/Intel/intel_power_features.h +++ b/src/variorum/Intel/intel_power_features.h @@ -289,6 +289,20 @@ void print_verbose_power_data( off_t msr_dram_energy_status ); +void print_energy_data( + FILE *writedest, + off_t msr_rapl_unit, + off_t msr_pkg_energy_status, + off_t msr_dram_energy_status +); + +void print_verbose_energy_data( + FILE *writedest, + off_t msr_rapl_unit, + off_t msr_pkg_energy_status, + off_t msr_dram_energy_status +); + void json_get_power_data( json_t *get_power_obj, off_t msr_power_limit, @@ -358,6 +372,13 @@ int delta_rapl_data( off_t msr_rapl_unit ); +void json_get_energy_data( + json_t *get_energy_obj, + off_t msr_rapl_unit, + off_t msr_pkg_energy_status, + off_t msr_dram_energy_status +); + #endif ///* intel_power_features.h */ diff --git a/src/variorum/config_architecture.c b/src/variorum/config_architecture.c index 2d5c07172..6b7e4c6a7 100644 --- a/src/variorum/config_architecture.c +++ b/src/variorum/config_architecture.c @@ -361,6 +361,7 @@ void variorum_init_func_ptrs() g_platform[i].variorum_print_energy = NULL; g_platform[i].variorum_get_thermals_json = NULL; g_platform[i].variorum_get_frequency_json = NULL; + g_platform[i].variorum_get_energy_json = NULL; } } diff --git a/src/variorum/config_architecture.h b/src/variorum/config_architecture.h index 406c53161..f9f694c19 100644 --- a/src/variorum/config_architecture.h +++ b/src/variorum/config_architecture.h @@ -276,7 +276,12 @@ struct platform /// @brief Function pointer to print energy for all cores and sockets. /// /// @return Error code. - int (*variorum_print_energy)(void); + int (*variorum_print_energy)(int long_ver); + + /// @brief Function pointer to get JSON object for energy information + /// + /// @return Error code. + int (*variorum_get_energy_json)(json_t *get_energy_obj); /// @brief Identifier for architecture. uint64_t *arch_id; diff --git a/src/variorum/variorum.c b/src/variorum/variorum.c index d19025eb4..764b0488d 100644 --- a/src/variorum/variorum.c +++ b/src/variorum/variorum.c @@ -1576,26 +1576,190 @@ int variorum_print_energy(void) { int err = 0; int i; + int has_cpu = 0; + int has_gpu = 0; err = variorum_enter(__FILE__, __FUNCTION__, __LINE__); if (err) { return -1; } - for (i = 0; i < P_NUM_PLATFORMS; i++) + + // If we have a GPU-only build, we should exit with a helpful message. + // If we have a CPU-only or CPU+GPU multi-platform build, we should print + // the node-level energy. + // First check if we have a CPU platform, then check for a GPU platform + +#if defined(VARIORUM_WITH_INTEL_CPU) || defined(VARIORUM_WITH_AMD_CPU) || defined(VARIORUM_WITH_IBM_CPU) + has_cpu = 1; +#endif +#if defined(VARIORUM_WITH_NVIDIA_GPU) || defined(VARIORUM_WITH_AMD_GPU) || defined(VARIORUM_WITH_INTEL_GPU) + has_gpu = 1; +#endif + + // CPU-only or multi-platform build + if ((has_cpu && has_gpu) || (has_cpu)) { - if (g_platform[i].variorum_print_energy == NULL) + for (i = 0; i < P_NUM_PLATFORMS; i++) { - variorum_error_handler("Feature not yet implemented or is not supported", - VARIORUM_ERROR_FEATURE_NOT_IMPLEMENTED, getenv("HOSTNAME"), __FILE__, - __FUNCTION__, __LINE__); - return 0; + if (g_platform[i].variorum_print_energy == NULL) + { + variorum_error_handler("Feature not yet implemented or is not supported", + VARIORUM_ERROR_FEATURE_NOT_IMPLEMENTED, getenv("HOSTNAME"), __FILE__, + __FUNCTION__, __LINE__); + return 0; + } + err = g_platform[i].variorum_print_energy(0); + if (err) + { + return -1; + } } - err = g_platform[i].variorum_print_energy(); - if (err) + } + else + { + // We have a GPU-only build, currently doesn't support get_energy + variorum_error_handler("Feature not yet implemented or is not supported", + VARIORUM_ERROR_FEATURE_NOT_IMPLEMENTED, getenv("HOSTNAME"), __FILE__, + __FUNCTION__, __LINE__); + return 0; + } + err = variorum_exit(__FILE__, __FUNCTION__, __LINE__); + + if (err) + { + return -1; + } + return err; +} + +int variorum_print_verbose_energy(void) +{ + int err = 0; + int i; + int has_cpu = 0; + int has_gpu = 0; + err = variorum_enter(__FILE__, __FUNCTION__, __LINE__); + if (err) + { + return -1; + } + + // If we have a GPU-only build, we should exit with a helpful message. + // If we have a CPU-only or CPU+GPU multi-platform build, we should print + // the node-level energy. + // First check if we have a CPU platform, then check for a GPU platform + +#if defined(VARIORUM_WITH_INTEL_CPU) || defined(VARIORUM_WITH_AMD_CPU) || defined(VARIORUM_WITH_IBM_CPU) + has_cpu = 1; +#endif +#if defined(VARIORUM_WITH_NVIDIA_GPU) || defined(VARIORUM_WITH_AMD_GPU) || defined(VARIORUM_WITH_INTEL_GPU) + has_gpu = 1; +#endif + + // CPU-only or multi-platform build + if ((has_cpu && has_gpu) || (has_cpu)) + { + for (i = 0; i < P_NUM_PLATFORMS; i++) { - return -1; + if (g_platform[i].variorum_print_energy == NULL) + { + variorum_error_handler("Feature not yet implemented or is not supported", + VARIORUM_ERROR_FEATURE_NOT_IMPLEMENTED, getenv("HOSTNAME"), __FILE__, + __FUNCTION__, __LINE__); + return 0; + } + err = g_platform[i].variorum_print_energy(1); + if (err) + { + return -1; + } } } + else + { + // We have a GPU-only build, currently doesn't support get_energy + variorum_error_handler("Feature not yet implemented or is not supported", + VARIORUM_ERROR_FEATURE_NOT_IMPLEMENTED, getenv("HOSTNAME"), __FILE__, + __FUNCTION__, __LINE__); + return 0; + } + err = variorum_exit(__FILE__, __FUNCTION__, __LINE__); + if (err) + { + return -1; + } + return err; +} + +int variorum_get_energy_json(char **get_energy_obj_str) +{ + int err = 0; + int i; + int has_cpu = 0; + int has_gpu = 0; + char hostname[1024]; + uint64_t ts; + struct timeval tv; + gethostname(hostname, 1024); + gettimeofday(&tv, NULL); + + err = variorum_enter(__FILE__, __FUNCTION__, __LINE__); + if (err) + { + return -1; + } + + json_t *get_energy_obj = json_object(); + json_t *node_obj = json_object(); + json_object_set_new(get_energy_obj, hostname, node_obj); + + ts = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec; + json_object_set_new(node_obj, "timestamp", json_integer(ts)); + + // If we have a GPU-only build, we should exit with a helpful message. + // If we have a CPU-only or CPU+GPU multi-platform build, we should print + // the node-level energy. + // First check if we have a CPU platform, then check for a GPU platform + +#if defined(VARIORUM_WITH_INTEL_CPU) || defined(VARIORUM_WITH_AMD_CPU) || defined(VARIORUM_WITH_IBM_CPU) + has_cpu = 1; +#endif +#if defined(VARIORUM_WITH_NVIDIA_GPU) || defined(VARIORUM_WITH_AMD_GPU) || defined(VARIORUM_WITH_INTEL_GPU) + has_gpu = 1; +#endif + + // CPU-only or multi-platform build + if ((has_cpu && has_gpu) || (has_cpu)) + { + for (i = 0; i < P_NUM_PLATFORMS; i++) + { + if (g_platform[i].variorum_get_energy_json == NULL) + { + variorum_error_handler("Feature not yet implemented or is not supported", + VARIORUM_ERROR_FEATURE_NOT_IMPLEMENTED, + getenv("HOSTNAME"), __FILE__, + __FUNCTION__, __LINE__); + } + err = g_platform[i].variorum_get_energy_json(node_obj); + if (err) + { + printf("Error with variorum get frequency json platform %d\n", i); + } + *get_energy_obj_str = json_dumps(get_energy_obj, JSON_INDENT(4)); + } + } + else + { + // We have a GPU-only build, currently doesn't support get_energy + variorum_error_handler("Feature not yet implemented or is not supported", + VARIORUM_ERROR_FEATURE_NOT_IMPLEMENTED, getenv("HOSTNAME"), __FILE__, + __FUNCTION__, __LINE__); + *get_energy_obj_str = json_dumps(get_energy_obj, JSON_INDENT(4)); + return 0; + } + + json_decref(get_energy_obj); + err = variorum_exit(__FILE__, __FUNCTION__, __LINE__); if (err) { diff --git a/src/variorum/variorum.h b/src/variorum/variorum.h index 378468ea6..58d86fbcf 100644 --- a/src/variorum/variorum.h +++ b/src/variorum/variorum.h @@ -477,11 +477,37 @@ int variorum_print_available_frequencies(void); /// /// @supparch /// - AMD EPYC Milan +/// - IBM Power9 +/// - Intel Sandy Bridge +/// - Intel Ivy Bridge +/// - Intel Haswell +/// - Intel Broadwell +/// - Intel Skylake +/// - Intel Kaby Lake +/// - Intel Cascade Lake +/// - Intel Cooper Lake /// /// @return 0 if successful or if feature has not been implemented or is /// not supported, otherwise -1 int variorum_print_energy(void); +/// @brief Print verbose format of core and socket energy if available. +/// +/// @supparch +/// - IBM Power9 +/// - Intel Sandy Bridge +/// - Intel Ivy Bridge +/// - Intel Haswell +/// - Intel Broadwell +/// - Intel Skylake +/// - Intel Kaby Lake +/// - Intel Cascade Lake +/// - Intel Cooper Lake +/// +/// @return 0 if successful or if feature has not been implemented or is +/// not supported, otherwise -1 +int variorum_print_verbose_energy(void); + /***************************/ /* Enable/Disable Features */ /***************************/ @@ -672,6 +698,27 @@ int variorum_get_thermals_json(char **get_thermal_obj_str); /// check for NULL strings. int variorum_get_frequency_json(char **get_frequency_obj_str); +/// @brief Populate a string in JSON format with node level energy information +/// +/// @supparch +/// - IBM Power9 +/// - Intel Sandy Bridge +/// - Intel Ivy Bridge +/// - Intel Haswell +/// - Intel Broadwell +/// - Intel Skylake +/// - Intel Kaby Lake +/// - Intel Cascade Lake +/// - Intel Cooper Lake +/// +/// @param [out] get_energy_obj_str String (passed by reference) containing +/// the node-level energy information. +/// +/// @return 0 if successful, otherwise -1. Note that feature not implemented +/// returns a -1 for the JSON APIs so that users don't have to explicitly +/// check for NULL strings. +int variorum_get_energy_json(char **get_energy_obj_str); + /// @brief Returns Variorum version as a constant string. /// /// @supparch