Linux Audio

Check our new training course

Loading...
  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
 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#endif