aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/power/cpupower/utils/idle_monitor/rapl_monitor.c
blob: 46153f1291c3d23fcecb995f674f97b08c69bbe3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// 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