readenergy.c revision dfc63a1cc09d0d701e0faa9af6b5509c95bd86de
14e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/* Copyright 2014-2015 ARM Limited 24e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * 34e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * Licensed under the Apache License, Version 2.0 (the "License"); 44e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * you may not use this file except in compliance with the License. 54e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * You may obtain a copy of the License at 64e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * 74e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * http://www.apache.org/licenses/LICENSE-2.0 84e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * 94e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * Unless required by applicable law or agreed to in writing, software 104e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * distributed under the License is distributed on an "AS IS" BASIS, 114e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * See the License for the specific language governing permissions and 134e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * limitations under the License. 144e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov*/ 154e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 164e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 174e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/* 184e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * readenergy.c 194e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * 204e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * Reads APB energy registers in Juno and outputs the measurements (converted to appropriate units). 214e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * 224e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov*/ 234e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <errno.h> 244e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <fcntl.h> 254e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <stdint.h> 264e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <stdio.h> 274e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <stdlib.h> 284e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <string.h> 294e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <signal.h> 304e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <sys/mman.h> 314e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <sys/stat.h> 324e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <sys/types.h> 334e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <time.h> 344e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <unistd.h> 354e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 364e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// The following values obtained from Juno TRM 2014/03/04 section 4.5 374e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 384e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Location of APB registers in memory 394e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define APB_BASE_MEMORY 0x1C010000 404e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// APB energy counters start at offset 0xD0 from the base APB address. 414e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define BASE_INDEX 0xD0 / 4 424e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// the one-past last APB counter 434e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define APB_SIZE 0x120 444e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 454e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Masks specifying the bits that contain the actual counter values 464e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define CMASK 0xFFF 474e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define VMASK 0xFFF 484e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define PMASK 0xFFFFFF 494e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 504e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Sclaing factor (divisor) or getting measured values from counters 514e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH0_PM1_SYS_SCALE 761 524e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH1_PM2_A57_SCALE 381 534e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH2_PM3_A53_SCALE 761 544e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH3_PM4_GPU_SCALE 381 554e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH4_VSYS_SCALE 1622 564e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH5_VA57_SCALE 1622 574e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH6_VA53_SCALE 1622 584e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH7_VGPU_SCALE 1622 594e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_POW_CH04_SYS_SCALE (SYS_ADC_CH0_PM1_SYS_SCALE * SYS_ADC_CH4_VSYS_SCALE) 604e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_POW_CH15_A57_SCALE (SYS_ADC_CH1_PM2_A57_SCALE * SYS_ADC_CH5_VA57_SCALE) 614e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_POW_CH26_A53_SCALE (SYS_ADC_CH2_PM3_A53_SCALE * SYS_ADC_CH6_VA53_SCALE) 624e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_POW_CH37_GPU_SCALE (SYS_ADC_CH3_PM4_GPU_SCALE * SYS_ADC_CH7_VGPU_SCALE) 634e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ENM_CH0_SYS_SCALE 12348030000 644e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ENM_CH1_A57_SCALE 6174020000 654e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ENM_CH0_A53_SCALE 12348030000 664e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ENM_CH0_GPU_SCALE 6174020000 674e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 684e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Original values prior to re-callibrations. 694e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH0_PM1_SYS_SCALE 819.2*/ 704e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH1_PM2_A57_SCALE 409.6*/ 714e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH2_PM3_A53_SCALE 819.2*/ 724e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH3_PM4_GPU_SCALE 409.6*/ 734e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH4_VSYS_SCALE 1638.4*/ 744e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH5_VA57_SCALE 1638.4*/ 754e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH6_VA53_SCALE 1638.4*/ 764e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH7_VGPU_SCALE 1638.4*/ 774e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_POW_CH04_SYS_SCALE (SYS_ADC_CH0_PM1_SYS_SCALE * SYS_ADC_CH4_VSYS_SCALE)*/ 784e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_POW_CH15_A57_SCALE (SYS_ADC_CH1_PM2_A57_SCALE * SYS_ADC_CH5_VA57_SCALE)*/ 794e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_POW_CH26_A53_SCALE (SYS_ADC_CH2_PM3_A53_SCALE * SYS_ADC_CH6_VA53_SCALE)*/ 804e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_POW_CH37_GPU_SCALE (SYS_ADC_CH3_PM4_GPU_SCALE * SYS_ADC_CH7_VGPU_SCALE)*/ 814e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ENM_CH0_SYS_SCALE 13421772800.0*/ 824e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ENM_CH1_A57_SCALE 6710886400.0*/ 834e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ENM_CH0_A53_SCALE 13421772800.0*/ 844e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ENM_CH0_GPU_SCALE 6710886400.0*/ 854e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 864e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Ignore individual errors but if see too many, abort. 874e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define ERROR_THRESHOLD 10 884e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 894e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Default counter poll period (in milliseconds). 904e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define DEFAULT_PERIOD 100 914e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 92dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse// Default duration for the instrument execution (in seconds); 0 means 'forever' 93dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse#define DEFAULT_DURATION 0 94dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse 954e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// A single reading from the energy meter. The values are the proper readings converted 964e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// to appropriate units (e.g. Watts for power); they are *not* raw counter values. 974e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovstruct reading 984e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 994e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_adc_ch0_pm1_sys; 1004e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_adc_ch1_pm2_a57; 1014e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_adc_ch2_pm3_a53; 1024e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_adc_ch3_pm4_gpu; 1034e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_adc_ch4_vsys; 1044e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_adc_ch5_va57; 1054e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_adc_ch6_va53; 1064e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_adc_ch7_vgpu; 1074e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_pow_ch04_sys; 1084e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_pow_ch15_a57; 1094e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_pow_ch26_a53; 1104e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_pow_ch37_gpu; 1114e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_enm_ch0_sys; 1124e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_enm_ch1_a57; 1134e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_enm_ch0_a53; 1144e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov double sys_enm_ch0_gpu; 1154e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}; 1164e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1174e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovinline uint64_t join_64bit_register(uint32_t *buffer, int index) 1184e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 1194e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov uint64_t result = 0; 1204e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov result |= buffer[index]; 1214e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov result |= (uint64_t)(buffer[index+1]) << 32; 1224e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov return result; 1234e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 1244e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1254e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovint nsleep(const struct timespec *req, struct timespec *rem) 1264e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 1274e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov struct timespec temp_rem; 1284e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov if (nanosleep(req, rem) == -1) 1294e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 1304e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov if (errno == EINTR) 1314e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 1324e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov nsleep(rem, &temp_rem); 1334e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 1344e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov else 1354e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 1364e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov return errno; 1374e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 1384e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 1394e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov else 1404e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 1414e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov return 0; 1424e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 1434e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 1444e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1454e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid print_help() 1464e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 14709915101d849cdc285726f6366f4b1a168a7f74aChris Redpath fprintf(stderr, "Usage: readenergy [-t PERIOD] [-o OUTFILE]\n\n" 1484e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov "Read Juno energy counters every PERIOD milliseconds, writing them\n" 149dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse "to OUTFILE in CSV format either until SIGTERM is received OR\n" 150dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse "till the specified duration elapsed.\n" 15109915101d849cdc285726f6366f4b1a168a7f74aChris Redpath "If OUTFILE is not specified, stdout will be used.\n\n" 1524e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov "Parameters:\n" 1534e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov " PERIOD is the counter poll period in milliseconds.\n" 1544e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov " (Defaults to 100 milliseconds.)\n" 155dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse " DURATION is the duration before execution terminates.\n" 156dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse " (Defaults to 0 seconds, meaning run till user\n" 157dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse " terminates execution.\n" 1584e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov " OUTFILE is the output file path\n"); 1594e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 1604e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1614e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// debugging only... 1624e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovinline void dprint(char *msg) 1634e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 1644e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fprintf(stderr, "%s\n", msg); 1654e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov sync(); 1664e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 1674e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1684e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// -------------------------------------- config ---------------------------------------------------- 1694e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1704e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovstruct config 1714e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 1724e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov struct timespec period; 1734e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov char *output_file; 174dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse long duration_in_sec; 1754e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}; 1764e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1774e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid config_init_period_from_millis(struct config *this, long millis) 1784e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 1794e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov this->period.tv_sec = (time_t)(millis / 1000); 1804e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov this->period.tv_nsec = (millis % 1000) * 1000000; 1814e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 1824e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1834e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid config_init(struct config *this, int argc, char *argv[]) 1844e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 1854e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov this->output_file = NULL; 1864e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov config_init_period_from_millis(this, DEFAULT_PERIOD); 187dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse this->duration_in_sec = DEFAULT_DURATION; 1884e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 1894e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov int opt; 190dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse while ((opt = getopt(argc, argv, "ht:o:d:")) != -1) 1914e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 1924e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov switch(opt) 1934e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 1944e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov case 't': 1954e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov config_init_period_from_millis(this, atol(optarg)); 1964e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov break; 1974e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov case 'o': 1984e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov this->output_file = optarg; 1994e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov break; 200dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse case 'd': 201dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse this->duration_in_sec = atol(optarg); 202dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse break; 2034e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov case 'h': 2044e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov print_help(); 2054e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov exit(EXIT_SUCCESS); 2064e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov break; 2074e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov default: 2084e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fprintf(stderr, "ERROR: Unexpected option %s\n\n", opt); 2094e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov print_help(); 2104e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov exit(EXIT_FAILURE); 2114e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 2124e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 2134e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 2144e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 2154e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// -------------------------------------- /config --------------------------------------------------- 2164e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 2174e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// -------------------------------------- emeter ---------------------------------------------------- 2184e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 2194e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovstruct emeter 2204e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 2214e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov int fd; 2224e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov FILE *out; 2234e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov void *mmap_base; 2244e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}; 2254e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 2264e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid emeter_init(struct emeter *this, char *outfile) 2274e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 22809915101d849cdc285726f6366f4b1a168a7f74aChris Redpath if(outfile) 2294e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 23009915101d849cdc285726f6366f4b1a168a7f74aChris Redpath this->out = fopen(outfile, "w"); 23109915101d849cdc285726f6366f4b1a168a7f74aChris Redpath if (this->out == NULL) 23209915101d849cdc285726f6366f4b1a168a7f74aChris Redpath { 23309915101d849cdc285726f6366f4b1a168a7f74aChris Redpath fprintf(stderr, "ERROR: Could not open output file %s; got %s\n", outfile, strerror(errno)); 23409915101d849cdc285726f6366f4b1a168a7f74aChris Redpath exit(EXIT_FAILURE); 23509915101d849cdc285726f6366f4b1a168a7f74aChris Redpath } 23609915101d849cdc285726f6366f4b1a168a7f74aChris Redpath } else { 23709915101d849cdc285726f6366f4b1a168a7f74aChris Redpath this->out = stdout; 2384e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 2394e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov this->fd = open("/dev/mem", O_RDONLY); 2404e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov if(this->fd < 0) 2414e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 2424e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fprintf(stderr, "ERROR: Can't open /dev/mem; got %s\n", strerror(errno)); 2434e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fclose(this->out); 2444e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov exit(EXIT_FAILURE); 2454e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 2464e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 2474e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov this->mmap_base = mmap(NULL, APB_SIZE, PROT_READ, MAP_SHARED, this->fd, APB_BASE_MEMORY); 2484e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov if (this->mmap_base == MAP_FAILED) 2494e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 2504e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fprintf(stderr, "ERROR: mmap failed; got %s\n", strerror(errno)); 2514e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov close(this->fd); 2524e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fclose(this->out); 2534e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov exit(EXIT_FAILURE); 2544e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 2554e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 25609915101d849cdc285726f6366f4b1a168a7f74aChris Redpath if(this->out) { 25709915101d849cdc285726f6366f4b1a168a7f74aChris Redpath fprintf(this->out, "sys_curr,a57_curr,a53_curr,gpu_curr," 25809915101d849cdc285726f6366f4b1a168a7f74aChris Redpath "sys_volt,a57_volt,a53_volt,gpu_volt," 25909915101d849cdc285726f6366f4b1a168a7f74aChris Redpath "sys_pow,a57_pow,a53_pow,gpu_pow," 26009915101d849cdc285726f6366f4b1a168a7f74aChris Redpath "sys_cenr,a57_cenr,a53_cenr,gpu_cenr\n"); 26109915101d849cdc285726f6366f4b1a168a7f74aChris Redpath } 2624e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 2634e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 2644e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid emeter_read_measurements(struct emeter *this, struct reading *reading) 2654e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 2664e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov uint32_t *buffer = (uint32_t *)this->mmap_base; 2674e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_adc_ch0_pm1_sys = (double)(CMASK & buffer[BASE_INDEX+0]) / SYS_ADC_CH0_PM1_SYS_SCALE; 2684e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_adc_ch1_pm2_a57 = (double)(CMASK & buffer[BASE_INDEX+1]) / SYS_ADC_CH1_PM2_A57_SCALE; 2694e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_adc_ch2_pm3_a53 = (double)(CMASK & buffer[BASE_INDEX+2]) / SYS_ADC_CH2_PM3_A53_SCALE; 2704e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_adc_ch3_pm4_gpu = (double)(CMASK & buffer[BASE_INDEX+3]) / SYS_ADC_CH3_PM4_GPU_SCALE; 2714e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_adc_ch4_vsys = (double)(VMASK & buffer[BASE_INDEX+4]) / SYS_ADC_CH4_VSYS_SCALE; 2724e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_adc_ch5_va57 = (double)(VMASK & buffer[BASE_INDEX+5]) / SYS_ADC_CH5_VA57_SCALE; 2734e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_adc_ch6_va53 = (double)(VMASK & buffer[BASE_INDEX+6]) / SYS_ADC_CH6_VA53_SCALE; 2744e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_adc_ch7_vgpu = (double)(VMASK & buffer[BASE_INDEX+7]) / SYS_ADC_CH7_VGPU_SCALE; 2754e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_pow_ch04_sys = (double)(PMASK & buffer[BASE_INDEX+8]) / SYS_POW_CH04_SYS_SCALE; 2764e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_pow_ch15_a57 = (double)(PMASK & buffer[BASE_INDEX+9]) / SYS_POW_CH15_A57_SCALE; 2774e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_pow_ch26_a53 = (double)(PMASK & buffer[BASE_INDEX+10]) / SYS_POW_CH26_A53_SCALE; 2784e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_pow_ch37_gpu = (double)(PMASK & buffer[BASE_INDEX+11]) / SYS_POW_CH37_GPU_SCALE; 2794e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_enm_ch0_sys = (double)join_64bit_register(buffer, BASE_INDEX+12) / SYS_ENM_CH0_SYS_SCALE; 2804e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_enm_ch1_a57 = (double)join_64bit_register(buffer, BASE_INDEX+14) / SYS_ENM_CH1_A57_SCALE; 2814e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_enm_ch0_a53 = (double)join_64bit_register(buffer, BASE_INDEX+16) / SYS_ENM_CH0_A53_SCALE; 2824e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading->sys_enm_ch0_gpu = (double)join_64bit_register(buffer, BASE_INDEX+18) / SYS_ENM_CH0_GPU_SCALE; 2834e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 2844e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 2854e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid emeter_take_reading(struct emeter *this) 2864e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 2874e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov static struct reading reading; 2884e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov int error_count = 0; 2894e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov emeter_read_measurements(this, &reading); 2904e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov int ret = fprintf(this->out, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n", 2914e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_adc_ch0_pm1_sys, 2924e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_adc_ch1_pm2_a57, 2934e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_adc_ch2_pm3_a53, 2944e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_adc_ch3_pm4_gpu, 2954e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_adc_ch4_vsys, 2964e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_adc_ch5_va57, 2974e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_adc_ch6_va53, 2984e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_adc_ch7_vgpu, 2994e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_pow_ch04_sys, 3004e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_pow_ch15_a57, 3014e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_pow_ch26_a53, 3024e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_pow_ch37_gpu, 3034e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_enm_ch0_sys, 3044e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_enm_ch1_a57, 3054e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_enm_ch0_a53, 3064e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov reading.sys_enm_ch0_gpu); 3074e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov if (ret < 0) 3084e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 3094e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fprintf(stderr, "ERROR: while writing a meter reading: %s\n", strerror(errno)); 3104e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov if (++error_count > ERROR_THRESHOLD) 3114e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov exit(EXIT_FAILURE); 3124e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 3134e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 3144e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 3154e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid emeter_finalize(struct emeter *this) 3164e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 3174e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov if (munmap(this->mmap_base, APB_SIZE) == -1) 3184e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 3194e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov // Report the error but don't bother doing anything else, as we're not gonna do 3204e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov // anything with emeter after this point anyway. 3214e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fprintf(stderr, "ERROR: munmap failed; got %s\n", strerror(errno)); 3224e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 3234e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov close(this->fd); 3244e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov fclose(this->out); 3254e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 3264e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 3274e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// -------------------------------------- /emeter ---------------------------------------------------- 3284e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 329dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljusevolatile int done = 0; 3304e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 3314e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid term_handler(int signum) 3324e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 3334e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov done = 1; 3344e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 3354e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 336dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljusevoid sigalrm_handler(int signum) 337dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse{ 338dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse done = 1; 339dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse} 340dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse 341dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse 3424e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovint main(int argc, char *argv[]) 3434e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{ 3444e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov struct sigaction action; 3454e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov memset(&action, 0, sizeof(struct sigaction)); 3464e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov action.sa_handler = term_handler; 3474e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov sigaction(SIGTERM, &action, NULL); 3484e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 3494e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov struct config config; 3504e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov struct emeter emeter; 3514e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov config_init(&config, argc, argv); 3524e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov emeter_init(&emeter, config.output_file); 3534e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 354dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse if (0 != config.duration_in_sec) 355dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse { 356dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse /*Set the alarm with the duration from use only if a non-zero value is specified 357dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse else it will run forever until SIGTERM signal received from user*/ 358dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse /*Set the signal handler first*/ 359dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse signal(SIGALRM, sigalrm_handler); 360dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse /*Now set the alarm for the duration specified by the user*/ 361dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse alarm(config.duration_in_sec); 362dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse 363dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse } 364dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse 36509915101d849cdc285726f6366f4b1a168a7f74aChris Redpath if(config.output_file) 3664e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov { 36709915101d849cdc285726f6366f4b1a168a7f74aChris Redpath struct timespec remaining; 36809915101d849cdc285726f6366f4b1a168a7f74aChris Redpath while (!done) 36909915101d849cdc285726f6366f4b1a168a7f74aChris Redpath { 37009915101d849cdc285726f6366f4b1a168a7f74aChris Redpath emeter_take_reading(&emeter); 37109915101d849cdc285726f6366f4b1a168a7f74aChris Redpath nsleep(&config.period, &remaining); 37209915101d849cdc285726f6366f4b1a168a7f74aChris Redpath } 37309915101d849cdc285726f6366f4b1a168a7f74aChris Redpath } else { 3744e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov emeter_take_reading(&emeter); 3754e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov } 3764e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov 3774e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov emeter_finalize(&emeter); 3784e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov return EXIT_SUCCESS; 3794e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov} 380