Imported Upstream version 2.5
[platform/upstream/powertop.git] / src / cpu / rapl / rapl_interface.cpp
1 /* rapl_interface.cpp: rapl interface for power top implementation
2  *
3  * Copyright (C) 2012 Intel Corporation. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License version
7  * 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  *
20  * Author Name <Srinivas.Pandruvada@linux.intel.com>
21  *
22  */
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <math.h>
30 #include "lib.h"
31 #include "rapl_interface.h"
32
33 #ifdef DEBUG
34 #define RAPL_DBG_PRINT printf
35 #define RAPL_ERROR_PRINT printf
36 #else
37 #define RAPL_DBG_PRINT(...)     ((void) 0)
38 #define RAPL_ERROR_PRINT(...) ((void) 0)
39 #endif
40 #define RAPL_INFO_PRINT printf
41
42 #define MAX_TEMP_STR_SIZE       20
43
44 // RAPL interface
45 #define MSR_RAPL_POWER_UNIT     0x606
46 #define MSR_PKG_POWER_LIMIT     0x610
47
48 #define MSR_PKG_ENERY_STATUS    0x611
49 #define MSR_PKG_POWER_INFO      0x614
50 #define MSR_PKG_PERF_STATUS     0x613
51
52 #define MSR_DRAM_POWER_LIMIT    0x618
53 #define MSR_DRAM_ENERY_STATUS   0x619
54 #define MSR_DRAM_PERF_STATUS    0x61B
55 #define MSR_DRAM_POWER_INFO     0x61c
56
57 #define MSR_PP0_POWER_LIMIT     0x638
58 #define MSR_PP0_ENERY_STATUS    0x639
59 #define MSR_PP0_POLICY          0x63A
60 #define MSR_PP0_PERF_STATUS     0x63B
61
62 #define MSR_PP1_POWER_LIMIT     0x640
63 #define MSR_PP1_ENERY_STATUS    0x641
64 #define MSR_PP1_POLICY          0x642
65
66 #define PKG_DOMAIN_PRESENT      0x01
67 #define DRAM_DOMAIN_PRESENT     0x02
68 #define PP0_DOMAIN_PRESENT      0x04
69 #define PP1_DOMAIN_PRESENT      0x08
70
71 c_rapl_interface::c_rapl_interface(int cpu) :
72         measurment_interval(def_sampling_interval),
73         first_cpu(cpu),
74         last_pkg_energy_status(0.0),
75         last_dram_energy_status(0.0),
76         last_pp0_energy_status(0.0),
77         last_pp1_energy_status(0.0)
78 {
79         uint64_t value;
80         int ret;
81
82         RAPL_INFO_PRINT("RAPL device for cpu %d\n", cpu);
83
84         rapl_domains = 0;
85         // presence of each domain
86         // Check presence of PKG domain
87         ret = read_msr(first_cpu, MSR_PKG_ENERY_STATUS, &value);
88         if (ret > 0) {
89                 rapl_domains |= PKG_DOMAIN_PRESENT;
90                 RAPL_DBG_PRINT("Domain : PKG present\n");
91         } else {
92                 RAPL_DBG_PRINT("Domain : PKG Not present\n");
93         }
94
95         // Check presence of DRAM domain
96         ret = read_msr(first_cpu, MSR_DRAM_ENERY_STATUS, &value);
97         if (ret > 0) {
98                 rapl_domains |= DRAM_DOMAIN_PRESENT;
99                 RAPL_DBG_PRINT("Domain : DRAM present\n");
100         } else {
101                 RAPL_DBG_PRINT("Domain : DRAM Not present\n");
102         }
103
104         // Check presence of PP0 domain
105         ret = read_msr(first_cpu, MSR_PP0_ENERY_STATUS, &value);
106         if (ret > 0) {
107                 rapl_domains |= PP0_DOMAIN_PRESENT;
108                 RAPL_DBG_PRINT("Domain : PP0 present\n");
109         } else {
110                 RAPL_DBG_PRINT("Domain : PP0 Not present\n");
111         }
112
113         // Check presence of PP1 domain
114         ret = read_msr(first_cpu, MSR_PP1_ENERY_STATUS, &value);
115         if (ret > 0) {
116                 rapl_domains |= PP1_DOMAIN_PRESENT;
117                 RAPL_DBG_PRINT("Domain : PP1 present\n");
118         } else {
119                 RAPL_DBG_PRINT("Domain : PP1 Not present\n");
120         }
121
122         power_units = get_power_unit();
123         energy_status_units = get_energy_status_unit();
124         time_units = get_time_unit();
125
126         RAPL_DBG_PRINT("RAPL Domain mask: %x\n", rapl_domains);
127 }
128
129 bool c_rapl_interface::pkg_domain_present()
130 {
131         if ((rapl_domains & PKG_DOMAIN_PRESENT)) {
132                 return true;
133         }
134
135         return false;
136 }
137
138 bool c_rapl_interface::dram_domain_present()
139 {
140         if ((rapl_domains & DRAM_DOMAIN_PRESENT)) {
141                 return true;
142         }
143
144         return false;
145 }
146
147 bool c_rapl_interface::pp0_domain_present()
148 {
149         if ((rapl_domains & PP0_DOMAIN_PRESENT)) {
150                 return true;
151         }
152
153         return false;
154 }
155
156 bool c_rapl_interface::pp1_domain_present()
157 {
158         if ((rapl_domains & PP1_DOMAIN_PRESENT)) {
159                 return true;
160         }
161
162         return false;
163 }
164
165 int c_rapl_interface::read_msr(int cpu, unsigned int idx, uint64_t *val)
166 {
167         return ::read_msr(cpu, idx, val);
168 }
169
170 int c_rapl_interface::write_msr(int cpu, unsigned int idx, uint64_t val)
171 {
172         return ::write_msr(cpu, idx, val);
173 }
174
175 int c_rapl_interface::get_rapl_power_unit(uint64_t *value)
176 {
177         int ret;
178
179         ret = read_msr(first_cpu, MSR_RAPL_POWER_UNIT, value);
180
181         return ret;
182 }
183
184 double c_rapl_interface::get_power_unit()
185 {
186         int ret;
187         uint64_t value;
188
189         ret = get_rapl_power_unit(&value);
190         if(ret < 0)
191         {
192                 return ret;
193         }
194
195         return (double) 1/pow((double)2, (double)(value & 0xf));
196 }
197
198 double c_rapl_interface::get_energy_status_unit()
199 {
200         int ret;
201         uint64_t value;
202
203         ret = get_rapl_power_unit(&value);
204         if(ret < 0)
205         {
206                 return ret;
207         }
208
209         return (double)1/ pow((double)2, (double)((value & 0x1f00) >> 8));
210 }
211
212 double c_rapl_interface::get_time_unit()
213 {
214         int ret;
215         uint64_t value;
216
217         ret = get_rapl_power_unit(&value);
218         if(ret < 0)
219         {
220                 return ret;
221         }
222
223         return (double)1 / pow((double)2, (double)((value & 0xf0000) >> 16));
224 }
225
226 int c_rapl_interface::get_pkg_energy_status(double *status)
227 {
228         int ret;
229         uint64_t value;
230
231         if (!pkg_domain_present()) {
232                 return -1;
233         }
234
235         ret = read_msr(first_cpu, MSR_PKG_ENERY_STATUS, &value);
236         if(ret < 0)
237         {
238                 RAPL_ERROR_PRINT("get_pkg_energy_status failed\n");
239                 return ret;
240         }
241
242         *status = (double) (value & 0xffffffff) * get_energy_status_unit();
243
244         return ret;
245 }
246
247 int c_rapl_interface::get_pkg_power_info(double *thermal_spec_power,
248                         double *max_power, double *min_power, double *max_time_window)
249 {
250         int ret;
251         uint64_t value;
252
253         if (!pkg_domain_present()) {
254                 return -1;
255         }
256         ret = read_msr(first_cpu, MSR_PKG_POWER_INFO, &value);
257         if(ret < 0)
258         {
259                 RAPL_ERROR_PRINT("get_pkg_power_info failed\n");
260                 return ret;
261         }
262         *thermal_spec_power =  (value & 0x7FFF) * power_units;
263         *min_power =  ((value & 0x7FFF0000) >> 16) * power_units;
264         *max_power =  ((value & 0x7FFF00000000) >> 32) * power_units;
265         *max_time_window = ((value & 0x3f000000000000)>>48) * time_units;
266
267         return ret;
268 }
269
270 int c_rapl_interface::get_pkg_power_limit(uint64_t *value)
271 {
272         int ret;
273
274         if (!pkg_domain_present()) {
275                 return -1;
276         }
277
278         ret = read_msr(first_cpu, MSR_PKG_POWER_LIMIT, value);
279         if(ret < 0)
280         {
281                 RAPL_ERROR_PRINT("get_pkg_power_limit failed\n");
282                 return ret;
283         }
284
285         return ret;
286 }
287
288 int c_rapl_interface::set_pkg_power_limit(uint64_t value)
289 {
290         int ret;
291
292         if (!pkg_domain_present()) {
293                 return -1;
294         }
295
296         ret = write_msr(first_cpu, MSR_PKG_POWER_LIMIT, value);
297         if(ret < 0)
298         {
299                 RAPL_ERROR_PRINT("set_pkg_power_limit failed\n");
300                 return ret;
301         }
302
303         return ret;
304 }
305
306 int c_rapl_interface::get_dram_energy_status(double *status)
307 {
308         int ret;
309         uint64_t value;
310
311         if (!dram_domain_present()) {
312                 return -1;
313         }
314
315         ret = read_msr(first_cpu, MSR_DRAM_ENERY_STATUS, &value);
316         if(ret < 0)
317         {
318                 RAPL_ERROR_PRINT("get_dram_energy_status failed\n");
319                 return ret;
320         }
321
322         *status = (double) (value & 0xffffffff) * get_energy_status_unit();
323
324         return ret;
325 }
326
327 int c_rapl_interface::get_dram_power_info(double *thermal_spec_power,
328                         double *max_power, double *min_power, double *max_time_window)
329 {
330         int ret;
331         uint64_t value;
332
333         if (!dram_domain_present()) {
334                 return -1;
335         }
336         ret = read_msr(first_cpu, MSR_DRAM_POWER_INFO, &value);
337         if(ret < 0)
338         {
339                 RAPL_ERROR_PRINT("get_dram_power_info failed\n");
340                 return ret;
341         }
342
343         *thermal_spec_power =  (value & 0x7FFF) * power_units;
344         *min_power =  ((value & 0x7FFF0000) >> 16) * power_units;
345         *max_power =  ((value & 0x7FFF00000000) >> 32) * power_units;
346         *max_time_window = ((value & 0x3f000000000000)>>48) * time_units;
347
348         return ret;
349 }
350
351 int c_rapl_interface::get_dram_power_limit(uint64_t *value)
352 {
353         int ret;
354
355         if (!dram_domain_present()) {
356                 return -1;
357         }
358
359         ret = read_msr(first_cpu, MSR_DRAM_POWER_LIMIT, value);
360         if(ret < 0)
361         {
362                 RAPL_ERROR_PRINT("get_dram_power_limit failed\n");
363                 return ret;
364         }
365
366         return ret;
367 }
368
369 int c_rapl_interface::set_dram_power_limit(uint64_t value)
370 {
371         int ret;
372
373         if (!dram_domain_present()) {
374                 return -1;
375         }
376
377         ret = write_msr(first_cpu, MSR_DRAM_POWER_LIMIT, value);
378         if(ret < 0)
379         {
380                 RAPL_ERROR_PRINT("set_dram_power_limit failed\n");
381                 return ret;
382         }
383
384         return ret;
385 }
386
387 int c_rapl_interface::get_pp0_energy_status(double *status)
388 {
389         int ret;
390         uint64_t value;
391
392         if (!pp0_domain_present()) {
393                 return -1;
394         }
395
396         ret = read_msr(first_cpu, MSR_PP0_ENERY_STATUS, &value);
397         if(ret < 0)
398         {
399                 RAPL_ERROR_PRINT("get_pp0_energy_status failed\n");
400                 return ret;
401         }
402
403         *status = (double) (value & 0xffffffff) * get_energy_status_unit();
404
405         return ret;
406 }
407
408 int c_rapl_interface::get_pp0_power_limit(uint64_t *value)
409 {
410         int ret;
411
412         if (!pp0_domain_present()) {
413                 return -1;
414         }
415
416         ret = read_msr(first_cpu, MSR_PP0_POWER_LIMIT, value);
417         if(ret < 0)
418         {
419                 RAPL_ERROR_PRINT("get_pp0_power_limit failed\n");
420                 return ret;
421         }
422
423         return ret;
424 }
425
426 int c_rapl_interface::set_pp0_power_limit(uint64_t value)
427 {
428         int ret;
429
430         if (!pp0_domain_present()) {
431                 return -1;
432         }
433
434         ret = write_msr(first_cpu, MSR_PP0_POWER_LIMIT, value);
435         if(ret < 0)
436         {
437                 RAPL_ERROR_PRINT("set_pp0_power_limit failed\n");
438                 return ret;
439         }
440
441         return ret;
442 }
443
444 int c_rapl_interface::get_pp0_power_policy(unsigned int *pp0_power_policy)
445 {
446         int ret;
447         uint64_t value;
448
449         if (!pp0_domain_present()) {
450                 return -1;
451         }
452
453         ret = read_msr(first_cpu, MSR_PP0_POLICY, &value);
454         if(ret < 0)
455         {
456                 RAPL_ERROR_PRINT("get_pp0_power_policy failed\n");
457                 return ret;
458         }
459
460         *pp0_power_policy =  value & 0x0f;
461
462         return ret;
463 }
464
465 int c_rapl_interface::get_pp1_energy_status(double *status)
466 {
467         int ret;
468         uint64_t value;
469
470         if (!pp1_domain_present()) {
471                 return -1;
472         }
473
474         ret = read_msr(first_cpu, MSR_PP1_ENERY_STATUS, &value);
475         if(ret < 0)
476         {
477                 RAPL_ERROR_PRINT("get_pp1_energy_status failed\n");
478                 return ret;
479         }
480
481         *status = (double) (value & 0xffffffff) * get_energy_status_unit();
482
483         return ret;
484 }
485
486 int c_rapl_interface::get_pp1_power_limit(uint64_t *value)
487 {
488         int ret;
489
490         if (!pp1_domain_present()) {
491                 return -1;
492         }
493
494         ret = read_msr(first_cpu, MSR_PP1_POWER_LIMIT, value);
495         if(ret < 0)
496         {
497                 RAPL_ERROR_PRINT("get_pp1_power_info failed\n");
498                 return ret;
499         }
500
501         return ret;
502 }
503
504 int c_rapl_interface::set_pp1_power_limit(uint64_t value)
505 {
506         int ret;
507
508         if (!pp1_domain_present()) {
509                 return -1;
510         }
511
512         ret = write_msr(first_cpu, MSR_PP1_POWER_LIMIT, value);
513         if(ret < 0)
514         {
515                 RAPL_ERROR_PRINT("set_pp1_power_limit failed\n");
516                 return ret;
517         }
518
519         return ret;
520 }
521
522 int c_rapl_interface::get_pp1_power_policy(unsigned int *pp1_power_policy)
523 {
524         int ret;
525         uint64_t value;
526
527         if (!pp1_domain_present()) {
528                 return -1;
529         }
530
531         ret = read_msr(first_cpu, MSR_PP1_POLICY, &value);
532         if(ret < 0)
533         {
534                 RAPL_ERROR_PRINT("get_pp1_power_policy failed\n");
535                 return ret;
536         }
537
538         *pp1_power_policy =  value & 0x0f;
539
540         return ret;
541 }
542
543 void c_rapl_interface::rapl_measure_energy()
544 {
545 #ifdef RAPL_TEST_MODE
546         int ret;
547         double energy_status;
548         double thermal_spec_power;
549         double max_power;
550         double min_power;
551         double max_time_window;
552         double pkg_watts = 0;
553         double dram_watts = 0;
554         double pp0_watts = 0;
555         double pp1_watts = 0;
556         double pkg_joules = 0;
557         double dram_joules = 0;
558         double pp0_joules = 0;
559         double pp1_joules = 0;
560
561         ret = get_pkg_power_info(&thermal_spec_power, &max_power, &min_power, &max_time_window);
562         RAPL_DBG_PRINT("Pkg Power Info: Thermal spec %f watts, max %f watts, min %f watts, max time window %f seconds\n", thermal_spec_power, max_power, min_power, max_time_window);
563         ret = get_dram_power_info(&thermal_spec_power, &max_power, &min_power, &max_time_window);
564         RAPL_DBG_PRINT("DRAM Power Info: Thermal spec %f watts, max %f watts, min %f watts, max time window %f seconds\n", thermal_spec_power, max_power, min_power, max_time_window);
565
566         for (;;) {
567                 if (pkg_domain_present()) {
568                         ret = get_pkg_energy_status(&energy_status);
569                         if (last_pkg_energy_status == 0)
570                                 last_pkg_energy_status = energy_status;
571                         if (ret > 0) {
572                                 pkg_joules = energy_status;
573                                 pkg_watts = (energy_status-last_pkg_energy_status)/measurment_interval;
574                         }
575                         last_pkg_energy_status = energy_status;
576                 }
577                 if (dram_domain_present()) {
578                         ret = get_dram_energy_status(&energy_status);
579                         if (last_dram_energy_status == 0)
580                                 last_dram_energy_status = energy_status;
581                         if (ret > 0){
582                                 dram_joules = energy_status;
583                                 dram_watts = (energy_status-last_dram_energy_status)/measurment_interval;
584                         }
585                         last_dram_energy_status = energy_status;
586                 }
587                 if (pp0_domain_present()) {
588                         ret = get_pp0_energy_status(&energy_status);
589                         if (last_pp0_energy_status == 0)
590                                 last_pp0_energy_status = energy_status;
591                         if (ret > 0){
592                                 pp0_joules = energy_status;
593                                 pp0_watts = (energy_status-last_pp0_energy_status)/measurment_interval;
594                         }
595                         last_pp0_energy_status = energy_status;
596                 }
597                 if (pp1_domain_present()) {
598                         ret = get_pp1_energy_status(&energy_status);
599                         if (last_pp1_energy_status == 0)
600                                 last_pp1_energy_status = energy_status;
601                         if (ret > 0){
602                                 pp1_joules = energy_status;
603                                 pp1_watts = (energy_status-last_pp1_energy_status)/measurment_interval;
604                         }
605                         last_pp1_energy_status = energy_status;
606                 }
607                 RAPL_DBG_PRINT("%f, %f, %f, %f\n", pkg_watts, dram_watts, pp0_watts, pp1_watts);
608                 sleep(measurment_interval);
609         }
610 #endif
611 }