1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * (C) 2016 SUSE Software Solutions GmbH 4 * 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 10 22 23 int rapl_zone_count; 24 cstate_t rapl_zones[MAX_RAPL_ZONES]; 25 struct powercap_zone *rapl_zones_pt[MAX_RAPL_ZONES] = { 0 }; 26 27 unsigned long long rapl_zone_previous_count[MAX_RAPL_ZONES]; 28 unsigned long long rapl_zone_current_count[MAX_RAPL_ZONES]; 29 unsigned long long rapl_max_count; 30 31 static 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 43 static 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 69 static 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 84 static 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 102 struct 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 137 struct 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 #endif 149