Linux 6.7-rc7
[linux-modified.git] / tools / power / cpupower / utils / idle_monitor / rapl_monitor.c
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