149 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * (C) 2016 SUSE Software Solutions GmbH4 * Thomas Renninger <trenn@suse.de>5 */6 7#if defined(__i386__) || defined(__x86_64__)8 9#include <stdio.h>10#include <stdlib.h>11#include <stdint.h>12#include <time.h>13#include <string.h>14 15#include <pci/pci.h>16 17#include "idle_monitor/cpupower-monitor.h"18#include "helpers/helpers.h"19#include "powercap.h"20 21#define MAX_RAPL_ZONES 1022 23int rapl_zone_count;24cstate_t rapl_zones[MAX_RAPL_ZONES];25struct powercap_zone *rapl_zones_pt[MAX_RAPL_ZONES] = { 0 };26 27unsigned long long rapl_zone_previous_count[MAX_RAPL_ZONES];28unsigned long long rapl_zone_current_count[MAX_RAPL_ZONES];29unsigned long long rapl_max_count;30 31static int rapl_get_count_uj(unsigned int id, unsigned long long *count,32 unsigned int cpu)33{34 if (rapl_zones_pt[id] == NULL)35 /* error */36 return -1;37 38 *count = rapl_zone_current_count[id] - rapl_zone_previous_count[id];39 40 return 0;41}42 43static int powercap_count_zones(struct powercap_zone *zone)44{45 uint64_t val;46 int uj;47 48 if (rapl_zone_count >= MAX_RAPL_ZONES)49 return -1;50 51 if (!zone->has_energy_uj)52 return 0;53 54 printf("%s\n", zone->sys_name);55 uj = powercap_get_energy_uj(zone, &val);56 printf("%d\n", uj);57 58 strncpy(rapl_zones[rapl_zone_count].name, zone->name, CSTATE_NAME_LEN - 1);59 strcpy(rapl_zones[rapl_zone_count].desc, "");60 rapl_zones[rapl_zone_count].id = rapl_zone_count;61 rapl_zones[rapl_zone_count].range = RANGE_MACHINE;62 rapl_zones[rapl_zone_count].get_count = rapl_get_count_uj;63 rapl_zones_pt[rapl_zone_count] = zone;64 rapl_zone_count++;65 66 return 0;67}68 69static int rapl_start(void)70{71 int i, ret;72 uint64_t uj_val;73 74 for (i = 0; i < rapl_zone_count; i++) {75 ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val);76 if (ret)77 return ret;78 rapl_zone_previous_count[i] = uj_val;79 }80 81 return 0;82}83 84static int rapl_stop(void)85{86 int i;87 uint64_t uj_val;88 89 for (i = 0; i < rapl_zone_count; i++) {90 int ret;91 92 ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val);93 if (ret)94 return ret;95 rapl_zone_current_count[i] = uj_val;96 if (rapl_max_count < uj_val)97 rapl_max_count = uj_val - rapl_zone_previous_count[i];98 }99 return 0;100}101 102struct cpuidle_monitor *rapl_register(void)103{104 struct powercap_zone *root_zone;105 char line[MAX_LINE_LEN] = "";106 int ret, val;107 108 ret = powercap_get_driver(line, MAX_LINE_LEN);109 if (ret < 0) {110 dprint("No powercapping driver loaded\n");111 return NULL;112 }113 114 dprint("Driver: %s\n", line);115 ret = powercap_get_enabled(&val);116 if (ret < 0)117 return NULL;118 if (!val) {119 dprint("Powercapping is disabled\n");120 return NULL;121 }122 123 dprint("Powercap domain hierarchy:\n\n");124 root_zone = powercap_init_zones();125 126 if (root_zone == NULL) {127 dprint("No powercap info found\n");128 return NULL;129 }130 131 powercap_walk_zones(root_zone, powercap_count_zones);132 rapl_monitor.hw_states_num = rapl_zone_count;133 134 return &rapl_monitor;135}136 137struct cpuidle_monitor rapl_monitor = {138 .name = "RAPL",139 .hw_states = rapl_zones,140 .hw_states_num = 0,141 .start = rapl_start,142 .stop = rapl_stop,143 .do_register = rapl_register,144 .flags.needs_root = 0,145 .overflow_s = 60 * 60 * 24 * 100, /* To be implemented */146};147 148#endif149