// SPDX-License-Identifier: GPL-2.0-only /* * (C) 2016 SUSE Software Solutions GmbH * Thomas Renninger <trenn@suse.de> */ #if defined(__i386__) || defined(__x86_64__) #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <time.h> #include <string.h> #include <pci/pci.h> #include "idle_monitor/cpupower-monitor.h" #include "helpers/helpers.h" #include "powercap.h" #define MAX_RAPL_ZONES 10 int rapl_zone_count; cstate_t rapl_zones[MAX_RAPL_ZONES]; struct powercap_zone *rapl_zones_pt[MAX_RAPL_ZONES] = { 0 }; unsigned long long rapl_zone_previous_count[MAX_RAPL_ZONES]; unsigned long long rapl_zone_current_count[MAX_RAPL_ZONES]; unsigned long long rapl_max_count; static int rapl_get_count_uj(unsigned int id, unsigned long long *count, unsigned int cpu) { if (rapl_zones_pt[id] == NULL) /* error */ return -1; *count = rapl_zone_current_count[id] - rapl_zone_previous_count[id]; return 0; } static int powercap_count_zones(struct powercap_zone *zone) { uint64_t val; int uj; if (rapl_zone_count >= MAX_RAPL_ZONES) return -1; if (!zone->has_energy_uj) return 0; printf("%s\n", zone->sys_name); uj = powercap_get_energy_uj(zone, &val); printf("%d\n", uj); strncpy(rapl_zones[rapl_zone_count].name, zone->name, CSTATE_NAME_LEN - 1); strcpy(rapl_zones[rapl_zone_count].desc, ""); rapl_zones[rapl_zone_count].id = rapl_zone_count; rapl_zones[rapl_zone_count].range = RANGE_MACHINE; rapl_zones[rapl_zone_count].get_count = rapl_get_count_uj; rapl_zones_pt[rapl_zone_count] = zone; rapl_zone_count++; return 0; } static int rapl_start(void) { int i, ret; uint64_t uj_val; for (i = 0; i < rapl_zone_count; i++) { ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val); if (ret) return ret; rapl_zone_previous_count[i] = uj_val; } return 0; } static int rapl_stop(void) { int i; uint64_t uj_val; for (i = 0; i < rapl_zone_count; i++) { int ret; ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val); if (ret) return ret; rapl_zone_current_count[i] = uj_val; if (rapl_max_count < uj_val) rapl_max_count = uj_val - rapl_zone_previous_count[i]; } return 0; } struct cpuidle_monitor *rapl_register(void) { struct powercap_zone *root_zone; char line[MAX_LINE_LEN] = ""; int ret, val; ret = powercap_get_driver(line, MAX_LINE_LEN); if (ret < 0) { dprint("No powercapping driver loaded\n"); return NULL; } dprint("Driver: %s\n", line); ret = powercap_get_enabled(&val); if (ret < 0) return NULL; if (!val) { dprint("Powercapping is disabled\n"); return NULL; } dprint("Powercap domain hierarchy:\n\n"); root_zone = powercap_init_zones(); if (root_zone == NULL) { dprint("No powercap info found\n"); return NULL; } powercap_walk_zones(root_zone, powercap_count_zones); rapl_monitor.hw_states_num = rapl_zone_count; return &rapl_monitor; } struct cpuidle_monitor rapl_monitor = { .name = "RAPL", .hw_states = rapl_zones, .hw_states_num = 0, .start = rapl_start, .stop = rapl_stop, .do_register = rapl_register, .flags.needs_root = 0, .overflow_s = 60 * 60 * 24 * 100, /* To be implemented */ }; #endif