From 52a830686b3dd8703d710a171a524b591cf8e9d4 Mon Sep 17 00:00:00 2001 From: Steven Briscoe Date: Wed, 4 May 2016 16:37:28 +0100 Subject: [PATCH] Experimental daemon implementation Change-Id: I45ed42ecac9b51b81a0e1d78b62edfa7e5f3b997 --- .gitignore | 2 + cpucounters.cpp | 41 -- cpucounters.h | 40 ++ daemon/.cproject | 112 ++++++ daemon/.gitignore | 8 + daemon/.project | 83 ++++ daemon/client/.cproject | 60 +++ daemon/client/.project | 79 ++++ daemon/client/Debug/makefile | 58 +++ daemon/client/Debug/objects.mk | 8 + daemon/client/Debug/sources.mk | 27 ++ daemon/client/Debug/subdir.mk | 27 ++ daemon/client/client.cpp | 109 ++++++ daemon/client/client.h | 44 +++ daemon/client/main.cpp | 359 +++++++++++++++++ daemon/daemon/.cproject | 60 +++ daemon/daemon/.project | 79 ++++ daemon/daemon/Debug/makefile | 63 +++ daemon/daemon/Debug/objects.mk | 8 + daemon/daemon/Debug/sources.mk | 27 ++ daemon/daemon/Debug/subdir.mk | 29 ++ daemon/daemon/common.h | 241 ++++++++++++ daemon/daemon/daemon.cpp | 691 +++++++++++++++++++++++++++++++++ daemon/daemon/daemon.h | 75 ++++ daemon/daemon/main.cpp | 22 ++ daemon/daemon/pcm.h | 33 ++ daemon/daemon/test/Makefile | 19 + daemon/daemon/test/main.cpp | 84 ++++ utils.cpp | 12 + utils.h | 2 + 30 files changed, 2461 insertions(+), 41 deletions(-) create mode 100644 daemon/.cproject create mode 100644 daemon/.gitignore create mode 100644 daemon/.project create mode 100644 daemon/client/.cproject create mode 100644 daemon/client/.project create mode 100644 daemon/client/Debug/makefile create mode 100644 daemon/client/Debug/objects.mk create mode 100644 daemon/client/Debug/sources.mk create mode 100644 daemon/client/Debug/subdir.mk create mode 100644 daemon/client/client.cpp create mode 100644 daemon/client/client.h create mode 100644 daemon/client/main.cpp create mode 100644 daemon/daemon/.cproject create mode 100644 daemon/daemon/.project create mode 100644 daemon/daemon/Debug/makefile create mode 100644 daemon/daemon/Debug/objects.mk create mode 100644 daemon/daemon/Debug/sources.mk create mode 100644 daemon/daemon/Debug/subdir.mk create mode 100644 daemon/daemon/common.h create mode 100644 daemon/daemon/daemon.cpp create mode 100644 daemon/daemon/daemon.h create mode 100644 daemon/daemon/main.cpp create mode 100644 daemon/daemon/pcm.h create mode 100644 daemon/daemon/test/Makefile create mode 100644 daemon/daemon/test/main.cpp diff --git a/.gitignore b/.gitignore index ffa9092a..6f5b2694 100644 --- a/.gitignore +++ b/.gitignore @@ -16,9 +16,11 @@ *.vxd *.exe *.tgz +.metadata/ *.sdf *.suo Debug Release Debug64 Release64 +.metadata/ diff --git a/cpucounters.cpp b/cpucounters.cpp index 6b607c7b..e5267278 100644 --- a/cpucounters.cpp +++ b/cpucounters.cpp @@ -2720,47 +2720,6 @@ uint64 PCM::getTickCount(uint64 multiplier, uint32 core) return (multiplier * getInvariantTSC(CoreCounterState(), getCoreCounterState(core))) / getNominalFrequency(); } -uint64 RDTSC() -{ - uint64 result = 0; -#ifdef _MSC_VER - // Windows - #if _MSC_VER>= 1600 - result = static_cast(__rdtsc()); - #endif -#else - // Linux - uint32 high = 0, low = 0; - asm volatile("rdtsc" : "=a" (low), "=d" (high)); - result = low + (uint64(high)<<32ULL); -#endif - return result; - -} - -uint64 RDTSCP() -{ - uint64 result = 0; -#ifdef _MSC_VER - // Windows - #if _MSC_VER>= 1600 - unsigned int Aux; - result = __rdtscp(&Aux); - #endif -#else - // Linux and OS X - uint32 high = 0, low = 0; - asm volatile ( - "rdtscp\n\t" - "mov %%edx, %0\n\t" - "mov %%eax, %1\n\t": - "=r" (high), "=r" (low) :: "%rax", "%rcx", "%rdx"); - result = low + (uint64(high)<<32ULL); -#endif - return result; -} - - uint64 PCM::getTickCountRDTSCP(uint64 multiplier) { return (multiplier*RDTSCP())/getNominalFrequency(); diff --git a/cpucounters.h b/cpucounters.h index 5593ca8b..bfb23c74 100644 --- a/cpucounters.h +++ b/cpucounters.h @@ -1264,6 +1264,46 @@ class BasicCounterState int32 getThermalHeadroom() const { return ThermalHeadroom; } }; +inline uint64 RDTSC() +{ + uint64 result = 0; +#ifdef _MSC_VER + // Windows + #if _MSC_VER>= 1600 + result = static_cast(__rdtsc()); + #endif +#else + // Linux + uint32 high = 0, low = 0; + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + result = low + (uint64(high)<<32ULL); +#endif + return result; + +} + +inline uint64 RDTSCP() +{ + uint64 result = 0; +#ifdef _MSC_VER + // Windows + #if _MSC_VER>= 1600 + unsigned int Aux; + result = __rdtscp(&Aux); + #endif +#else + // Linux and OS X + uint32 high = 0, low = 0; + asm volatile ( + "rdtscp\n\t" + "mov %%edx, %0\n\t" + "mov %%eax, %1\n\t": + "=r" (high), "=r" (low) :: "%rax", "%rcx", "%rdx"); + result = low + (uint64(high)<<32ULL); +#endif + return result; +} + /*! \brief Returns QPI LL clock ticks \param port QPI port number \param before CPU counter state before the experiment diff --git a/daemon/.cproject b/daemon/.cproject new file mode 100644 index 00000000..f21ed972 --- /dev/null +++ b/daemon/.cproject @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/daemon/.gitignore b/daemon/.gitignore new file mode 100644 index 00000000..dd909115 --- /dev/null +++ b/daemon/.gitignore @@ -0,0 +1,8 @@ +.project +client/.project +client/.cproject +client/Debug/client +daemon/.project +daemon/.cproject +daemon/Debug/daemon +daemon/test/test \ No newline at end of file diff --git a/daemon/.project b/daemon/.project new file mode 100644 index 00000000..77e1d97a --- /dev/null +++ b/daemon/.project @@ -0,0 +1,83 @@ + + + daemon + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.buildLocation + ${workspace_loc:/daemon/Debug} + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/daemon/client/.cproject b/daemon/client/.cproject new file mode 100644 index 00000000..67171c34 --- /dev/null +++ b/daemon/client/.cproject @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/daemon/client/.project b/daemon/client/.project new file mode 100644 index 00000000..ee9e7c85 --- /dev/null +++ b/daemon/client/.project @@ -0,0 +1,79 @@ + + + client + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/daemon/client/Debug/makefile b/daemon/client/Debug/makefile new file mode 100644 index 00000000..c4537f5c --- /dev/null +++ b/daemon/client/Debug/makefile @@ -0,0 +1,58 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +-include ../makefile.init + +RM := rm -rf + +# All of the sources participating in the build are defined here +-include sources.mk +-include subdir.mk +-include objects.mk + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(strip $(C++_DEPS)),) +-include $(C++_DEPS) +endif +ifneq ($(strip $(C_DEPS)),) +-include $(C_DEPS) +endif +ifneq ($(strip $(CC_DEPS)),) +-include $(CC_DEPS) +endif +ifneq ($(strip $(CPP_DEPS)),) +-include $(CPP_DEPS) +endif +ifneq ($(strip $(CXX_DEPS)),) +-include $(CXX_DEPS) +endif +ifneq ($(strip $(C_UPPER_DEPS)),) +-include $(C_UPPER_DEPS) +endif +endif + +-include ../makefile.defs + +# Add inputs and outputs from these tool invocations to the build variables + +# All Target +all: client + +# Tool invocations +client: $(OBJS) $(USER_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GCC C++ Linker' + g++ -o "client" $(OBJS) $(USER_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +# Other Targets +clean: + -$(RM) $(OBJS)$(C++_DEPS)$(C_DEPS)$(CC_DEPS)$(CPP_DEPS)$(EXECUTABLES)$(CXX_DEPS)$(C_UPPER_DEPS) client + -@echo ' ' + +.PHONY: all clean dependents +.SECONDARY: + +-include ../makefile.targets diff --git a/daemon/client/Debug/objects.mk b/daemon/client/Debug/objects.mk new file mode 100644 index 00000000..742c2da0 --- /dev/null +++ b/daemon/client/Debug/objects.mk @@ -0,0 +1,8 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +USER_OBJS := + +LIBS := + diff --git a/daemon/client/Debug/sources.mk b/daemon/client/Debug/sources.mk new file mode 100644 index 00000000..5b37eadd --- /dev/null +++ b/daemon/client/Debug/sources.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +O_SRCS := +CPP_SRCS := +C_UPPER_SRCS := +C_SRCS := +S_UPPER_SRCS := +OBJ_SRCS := +ASM_SRCS := +CXX_SRCS := +C++_SRCS := +CC_SRCS := +OBJS := +C++_DEPS := +C_DEPS := +CC_DEPS := +CPP_DEPS := +EXECUTABLES := +CXX_DEPS := +C_UPPER_DEPS := + +# Every subdirectory with source files must be described here +SUBDIRS := \ +. \ + diff --git a/daemon/client/Debug/subdir.mk b/daemon/client/Debug/subdir.mk new file mode 100644 index 00000000..70765bc7 --- /dev/null +++ b/daemon/client/Debug/subdir.mk @@ -0,0 +1,27 @@ +################################################################################# +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../client.cpp \ +../main.cpp + +OBJS += \ +./client.o \ +./main.o + +CPP_DEPS += \ +./client.d \ +./main.d + + +# Each subdirectory must supply rules for building sources it contributes +%.o: ../%.cpp + @echo 'Building file: $<' + @echo 'Invoking: GCC C++ Compiler' + g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/daemon/client/client.cpp b/daemon/client/client.cpp new file mode 100644 index 00000000..ed309d4f --- /dev/null +++ b/daemon/client/client.cpp @@ -0,0 +1,109 @@ +/* + Copyright (c) 2009-2016, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// written by Steven Briscoe + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../daemon/common.h" +#include "client.h" + +namespace PCMDaemon { + + Client::Client() + : pollIntervalMs_(0), lastUpdatedClientTsc_(0) + { + setupSharedMemory(); + + //Set last updated timestamp to avoid a detected change + //when the client starts + lastUpdatedClientTsc_ = sharedPCMState_->lastUpdateTsc; + } + + void Client::setPollInterval(int pollMs) + { + pollIntervalMs_ = pollMs; + } + + PCMDaemon::SharedPCMState& Client::read() + { + if(pollIntervalMs_ <= 0) + { + throw std::runtime_error("The poll interval is not set or is negative."); + } + + while(true) + { + // Check client version matches daemon version + if(strlen(sharedPCMState_->version) > 0 && strcmp(sharedPCMState_->version, VERSION) != 0) + { + std::cout << sharedPCMState_->lastUpdateTsc << " " << lastUpdatedClientTsc_ << std::endl; + std::stringstream ss; + ss << "Out of date PCM daemon client. Client version: " << VERSION << " Daemon version: " << sharedPCMState_->version; + + throw std::runtime_error(ss.str()); + } + + if(countersHaveUpdated()) + { + //There is new data + lastUpdatedClientTsc_ = sharedPCMState_->lastUpdateTsc; + + return *sharedPCMState_; + } + else + { + //Nothing has changed since we last checked + usleep(pollIntervalMs_ * 1000); + } + } + } + + bool Client::countersHaveUpdated() + { + return lastUpdatedClientTsc_ != sharedPCMState_->lastUpdateTsc; + } + + void Client::setupSharedMemory(key_t key) + { + int shmFlag = 0660; + + int sharedMemoryId = shmget(key, sizeof(PCMDaemon::SharedPCMState), shmFlag); + if (sharedMemoryId < 0) + { + std::stringstream ss; + ss << "Failed to allocate shared memory segment (errno=" << errno << ")"; + + throw std::runtime_error(ss.str()); + } + + sharedPCMState_ = (PCMDaemon::SharedPCMState*)shmat(sharedMemoryId, NULL, 0); + if (sharedPCMState_ == (void *)-1) + { + std::stringstream ss; + ss << "Failed to attach shared memory segment (errno=" << errno << ")"; + + throw std::runtime_error(ss.str()); + } + } + +} diff --git a/daemon/client/client.h b/daemon/client/client.h new file mode 100644 index 00000000..f90976f8 --- /dev/null +++ b/daemon/client/client.h @@ -0,0 +1,44 @@ +/* + Copyright (c) 2009-2016, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// written by Steven Briscoe + +#include +#include +#include + + +#ifndef CLIENT_H_ +#define CLIENT_H_ + +#include "../daemon/common.h" + +namespace PCMDaemon { + + class Client { + public: + Client(); + void setPollInterval(int pollMs); + PCMDaemon::SharedPCMState& read(); + bool countersHaveUpdated(); + private: + void setupSharedMemory(key_t key = SHARED_MEMORY_KEY); + + int pollIntervalMs_; + PCMDaemon::SharedPCMState* sharedPCMState_; + PCMDaemon::uint64 lastUpdatedClientTsc_; + }; + +} + + +#endif /* CLIENT_H_ */ diff --git a/daemon/client/main.cpp b/daemon/client/main.cpp new file mode 100644 index 00000000..2f1566cc --- /dev/null +++ b/daemon/client/main.cpp @@ -0,0 +1,359 @@ +/* + Copyright (c) 2009-2016, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// written by Steven Briscoe + +//Test program for PCM Daemon client + +#include +#include +#include + +#include "client.h" + +void printTitle(std::string title) +{ + std::cout << std::setw(26) << std::left << title; +} + +int main(int argc, char *argv[]) +{ + PCMDaemon::Client client; + client.setPollInterval(atoi(argv[1])); + + int coutPrecision = 2; + + while(true) + { + PCMDaemon::SharedPCMState& state = client.read(); + PCMDaemon::SharedPCMCounters& counters = state.pcm; + + std::cout << std::endl << "----- Something changed -----" << std::endl << std::endl; + +// Display internal metrics + printTitle("Last updated TSC"); + std::cout << state.lastUpdateTsc << std::endl; + + printTitle("Timestamp"); + std::cout << state.timestamp << std::endl; + + printTitle("Cycles to get counters"); + std::cout << state.cyclesToGetPCMState << std::endl; + + printTitle("Poll interval (ms)"); + std::cout << state.pollMs << std::endl; + + std::cout << std::endl << std::endl; + +// Display core counters + printTitle("Core ID"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].coreId << " "; + } + std::cout << std::endl; + + printTitle("Socket ID"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].socketId << " "; + } + std::cout << std::endl; + + printTitle("IPC"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].instructionsPerCycle << " "; + } + std::cout << std::endl; + + printTitle("Cycles"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].cycles << " "; + } + std::cout << std::endl; + + printTitle("Inst. Ret."); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].instructionsRetired << " "; + } + std::cout << std::endl; + + printTitle("Exec usg."); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].execUsage << " "; + } + std::cout << std::endl; + + printTitle("Rela. Freq."); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].relativeFrequency << " "; + } + std::cout << std::endl; + + printTitle("Active Rela. Freq"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].activeRelativeFrequency << " "; + } + std::cout << std::endl; + + printTitle("L3 C Miss"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l3CacheMisses << " "; + } + std::cout << std::endl; + + printTitle("L3 C Reference"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l3CacheReference << " "; + } + std::cout << std::endl; + + printTitle("L2 C Miss"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l2CacheMisses << " "; + } + std::cout << std::endl; + + printTitle("L3 Hit Ratio"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l3CacheHitRatio << " "; + } + std::cout << std::endl; + + printTitle("L2 Hit Ratio"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l2CacheHitRatio << " "; + } + std::cout << std::endl; + + printTitle("L3 C MPI"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l3CacheMPI << " "; + } + std::cout << std::endl; + + printTitle("L2 C MPI"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l2CacheMPI << " "; + } + std::cout << std::endl; + + printTitle("L3 Occu. Avail."); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l3CacheOccupancyAvailable << " "; + } + std::cout << std::endl; + + printTitle("L3 Occu."); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].l3CacheOccupancy << " "; + } + std::cout << std::endl; + + printTitle("L. Mem. BW Avail."); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].localMemoryBWAvailable << " "; + } + std::cout << std::endl; + + printTitle("L. Mem. BW"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].localMemoryBW << " "; + } + std::cout << std::endl; + + printTitle("R. Mem. BW Avail."); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].remoteMemoryBWAvailable << " "; + } + std::cout << std::endl; + + printTitle("R. Mem. BW"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].remoteMemoryBW << " "; + } + std::cout << std::endl; + + printTitle("L. Mem. Accesses"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].localMemoryAccesses << " "; + } + std::cout << std::endl; + + printTitle("R. Mem. Accesses"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].remoteMemoryAccesses << " "; + } + std::cout << std::endl; + + printTitle("Thermal headroom"); + for(PCMDaemon::uint32 i = 0; i < counters.core.numOfOnlineCores; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.core.cores[i].thermalHeadroom << " "; + } + std::cout << std::endl; + + std::cout << std::endl << std::endl; +// Display memory counters + printTitle("Mem Read p/Sock."); + for(PCMDaemon::uint32 i = 0; i < counters.memory.numOfSockets; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.memory.sockets[i].read << " "; + } + std::cout << std::endl; + + printTitle("Mem Write p/Sock."); + for(PCMDaemon::uint32 i = 0; i < counters.memory.numOfSockets; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.memory.sockets[i].write << " "; + } + std::cout << std::endl; + + printTitle("Mem Part. p/Sock."); + for(PCMDaemon::uint32 i = 0; i < counters.memory.numOfSockets; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.memory.sockets[i].partialWrite << " "; + } + std::cout << std::endl; + + printTitle("Mem Total p/Sock."); + for(PCMDaemon::uint32 i = 0; i < counters.memory.numOfSockets; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.memory.sockets[i].total << " "; + } + std::cout << std::endl; + + printTitle("Mem Read Sys."); + std::cout << std::setprecision(coutPrecision) << counters.memory.system.total << " "; + std::cout << std::endl; + + printTitle("Mem Write Sys."); + std::cout << std::setprecision(coutPrecision) << counters.memory.system.write << " "; + std::cout << std::endl; + + printTitle("Mem Total Sys."); + std::cout << std::setprecision(coutPrecision) << counters.memory.system.total << " "; + std::cout << std::endl; + + printTitle("Mem Energy Avail."); + std::cout << std::setprecision(coutPrecision) << counters.memory.dramEnergyMetricsAvailable << " "; + std::cout << std::endl; + + printTitle("Mem Energy p/Sock"); + for(PCMDaemon::uint32 i = 0; i < counters.memory.numOfSockets; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.memory.dramEnergyForSockets[i] << " "; + } + std::cout << std::endl; + + std::cout << std::endl << std::endl; +// Display QPI counters + printTitle("QPI Links p/Sock"); + std::cout << std::setprecision(coutPrecision) << counters.qpi.numOfLinksPerSocket << " "; + std::cout << std::endl; + + printTitle("QPI in. Avail."); + std::cout << std::setprecision(coutPrecision) << counters.qpi.incomingQPITrafficMetricsAvailable << " "; + std::cout << std::endl; + + printTitle("QPI out. Avail."); + std::cout << std::setprecision(coutPrecision) << counters.qpi.outgoingQPITrafficMetricsAvailable << " "; + std::cout << std::endl; + + printTitle("QPI in. p/Sock"); + for(PCMDaemon::uint32 i = 0; i < counters.qpi.numOfSockets; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.qpi.incoming[i].total << " "; + } + std::cout << std::endl; + + printTitle("QPI out. p/Sock"); + for(PCMDaemon::uint32 i = 0; i < counters.qpi.numOfSockets; ++i) + { + std::cout << std::setprecision(coutPrecision) << counters.qpi.outgoing[i].total << " "; + } + std::cout << std::endl; + + printTitle("QPI in. p/Link/Sock"); + for(PCMDaemon::uint32 i = 0; i < counters.qpi.numOfSockets; ++i) + { + std::cout << i << " "; + for(PCMDaemon::uint32 l = 0; l < counters.qpi.numOfLinksPerSocket; ++l) + { + std::cout << std::setw(12) << std::left << std::setprecision(coutPrecision) << counters.qpi.incoming[i].links[l].bytes << " "; + } + std::cout << std::endl; + printTitle(""); + + std::cout << i << " "; + for(PCMDaemon::uint32 l = 0; l < counters.qpi.numOfLinksPerSocket; ++l) + { + std::cout << std::setw(12) << std::left << std::setprecision(coutPrecision) << counters.qpi.incoming[i].links[l].utilization << " "; + } + std::cout << std::endl; + printTitle(""); + } + std::cout << std::endl; + + printTitle("QPI out. p/Link/Sock"); + for(PCMDaemon::uint32 i = 0; i < counters.qpi.numOfSockets; ++i) + { + std::cout << i << " "; + for(PCMDaemon::uint32 l = 0; l < counters.qpi.numOfLinksPerSocket; ++l) + { + std::cout << std::setw(12) << std::left << std::setprecision(coutPrecision) << counters.qpi.outgoing[i].links[l].bytes << " "; + } + std::cout << std::endl; + printTitle(""); + + std::cout << i << " "; + for(PCMDaemon::uint32 l = 0; l < counters.qpi.numOfLinksPerSocket; ++l) + { + std::cout << std::setw(12) << std::left << std::setprecision(coutPrecision) << counters.qpi.outgoing[i].links[l].utilization << " "; + } + std::cout << std::endl; + printTitle(""); + } + std::cout << std::endl; + + printTitle("QPI in. Total"); + std::cout << std::setprecision(coutPrecision) << counters.qpi.incomingTotal << " "; + std::cout << std::endl; + + printTitle("QPI out. Total"); + std::cout << std::setprecision(coutPrecision) << counters.qpi.outgoingTotal << " "; + std::cout << std::endl; + } + + return 1; +} diff --git a/daemon/daemon/.cproject b/daemon/daemon/.cproject new file mode 100644 index 00000000..bcea796c --- /dev/null +++ b/daemon/daemon/.cproject @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/daemon/daemon/.project b/daemon/daemon/.project new file mode 100644 index 00000000..c01ec864 --- /dev/null +++ b/daemon/daemon/.project @@ -0,0 +1,79 @@ + + + daemon + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/daemon/daemon/Debug/makefile b/daemon/daemon/Debug/makefile new file mode 100644 index 00000000..29244068 --- /dev/null +++ b/daemon/daemon/Debug/makefile @@ -0,0 +1,63 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +-include ../makefile.init + +RM := rm -rf + +# All of the sources participating in the build are defined here +-include sources.mk +-include subdir.mk +-include objects.mk + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(strip $(C++_DEPS)),) +-include $(C++_DEPS) +endif +ifneq ($(strip $(C_DEPS)),) +-include $(C_DEPS) +endif +ifneq ($(strip $(CC_DEPS)),) +-include $(CC_DEPS) +endif +ifneq ($(strip $(CPP_DEPS)),) +-include $(CPP_DEPS) +endif +ifneq ($(strip $(CXX_DEPS)),) +-include $(CXX_DEPS) +endif +ifneq ($(strip $(C_UPPER_DEPS)),) +-include $(C_UPPER_DEPS) +endif +endif + +-include ../makefile.defs + +# Add inputs and outputs from these tool invocations to the build variables + +# All Target +all: daemon + +# Tool invocations +daemon: pre-build $(OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GCC C++ Linker' + g++ -o "daemon" $(OBJS) $(USER_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +# Other Targets +clean: + -$(RM) $(OBJS)$(C++_DEPS)$(C_DEPS)$(CC_DEPS)$(CPP_DEPS)$(EXECUTABLES)$(CXX_DEPS)$(C_UPPER_DEPS) *.o daemon + -@echo ' ' + +pre-build: + -@echo 'Build PCM' + -g++ -c ../../../*.cpp -std=c++0x + -@echo ' ' + +.PHONY: all clean dependents +.SECONDARY: main-build pre-build + +-include ../makefile.targets diff --git a/daemon/daemon/Debug/objects.mk b/daemon/daemon/Debug/objects.mk new file mode 100644 index 00000000..22982031 --- /dev/null +++ b/daemon/daemon/Debug/objects.mk @@ -0,0 +1,8 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +USER_OBJS := ./utils.o ./pci.o ./msr.o ./client_bw.o ./cpucounters.o + +LIBS := -lpthread + diff --git a/daemon/daemon/Debug/sources.mk b/daemon/daemon/Debug/sources.mk new file mode 100644 index 00000000..5b37eadd --- /dev/null +++ b/daemon/daemon/Debug/sources.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +O_SRCS := +CPP_SRCS := +C_UPPER_SRCS := +C_SRCS := +S_UPPER_SRCS := +OBJ_SRCS := +ASM_SRCS := +CXX_SRCS := +C++_SRCS := +CC_SRCS := +OBJS := +C++_DEPS := +C_DEPS := +CC_DEPS := +CPP_DEPS := +EXECUTABLES := +CXX_DEPS := +C_UPPER_DEPS := + +# Every subdirectory with source files must be described here +SUBDIRS := \ +. \ + diff --git a/daemon/daemon/Debug/subdir.mk b/daemon/daemon/Debug/subdir.mk new file mode 100644 index 00000000..d3759681 --- /dev/null +++ b/daemon/daemon/Debug/subdir.mk @@ -0,0 +1,29 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../common.cpp \ +../daemon.cpp \ +../main.cpp + +OBJS += \ +./daemon.o \ +./main.o + +CPP_DEPS += \ +./common.d \ +./daemon.d \ +./main.d + + +# Each subdirectory must supply rules for building sources it contributes +%.o: ../%.cpp + @echo 'Building file: $<' + @echo 'Invoking: GCC C++ Compiler' + g++ -O0 -g3 -Wall -c -fmessage-length=0 -Wno-unknown-pragmas -std=c++0x -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/daemon/daemon/common.h b/daemon/daemon/common.h new file mode 100644 index 00000000..7aa8840a --- /dev/null +++ b/daemon/daemon/common.h @@ -0,0 +1,241 @@ +/* + Copyright (c) 2009-2016, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// written by Steven Briscoe + +#ifndef COMMON_H_ +#define COMMON_H_ + +#include +#include + +static const char VERSION[] = "1.0.1"; + +//P=80, C=67, M=77 +#define SHARED_MEMORY_KEY 806777 + sizeof(PCMDaemon::SharedPCMState) + +#define MAX_CPU_CORES 4096 +#define MAX_SOCKETS 256 +#define MEMORY_MAX_IMC_CHANNELS 8 +#define MEMORY_READ 0 +#define MEMORY_WRITE 1 +#define MEMORY_READ_RANK_A 0 +#define MEMORY_WRITE_RANK_A 1 +#define MEMORY_READ_RANK_B 2 +#define MEMORY_WRITE_RANK_B 3 +#define MEMORY_PARTIAL 2 +#define QPI_MAX_LINKS MAX_SOCKETS * 4 + +#define VERSION_SIZE 12 + +#define ALIGNMENT 64 +#define ALIGN(x) __attribute__((aligned((x)))) + +namespace PCMDaemon { + typedef int int32; + typedef long int64; + typedef unsigned int uint32; + typedef unsigned long uint64; + + struct PCMCoreCounter { + uint64 coreId; + int32 socketId; + double instructionsPerCycle; + uint64 cycles; + uint64 instructionsRetired; + double execUsage; + double relativeFrequency; + double activeRelativeFrequency; + uint64 l3CacheMisses; + uint64 l3CacheReference; + uint64 l2CacheMisses; + double l3CacheHitRatio; + double l2CacheHitRatio; + double l3CacheMPI; + double l2CacheMPI; + bool l3CacheOccupancyAvailable; + uint64 l3CacheOccupancy; + bool localMemoryBWAvailable; + uint64 localMemoryBW; + bool remoteMemoryBWAvailable; + uint64 remoteMemoryBW; + uint64 localMemoryAccesses; + uint64 remoteMemoryAccesses; + int32 thermalHeadroom; + + public: + PCMCoreCounter() : + l3CacheOccupancyAvailable(false), + l3CacheOccupancy(0), + localMemoryBWAvailable(false), + localMemoryBW(0), + remoteMemoryBWAvailable(false), + remoteMemoryBW(0) {} + } ALIGN(ALIGNMENT); + + typedef struct PCMCoreCounter PCMCoreCounter; + + struct PCMCore { + uint32 numOfCores; + uint32 numOfOnlineCores; + uint32 numOfSockets; + PCMCoreCounter cores[MAX_CPU_CORES]; + bool packageEnergyMetricsAvailable; + double energyUsedBySockets[MAX_SOCKETS] ALIGN(ALIGNMENT); + + public: + PCMCore() : + packageEnergyMetricsAvailable(false) { + for(int i = 0; i < MAX_SOCKETS; ++i) + { + energyUsedBySockets[i] = -1.0; + } + } + } ALIGN(ALIGNMENT); + + typedef struct PCMCore PCMCore; + + struct PCMMemoryChannelCounter { + float read; + float write; + float total; + + public: + PCMMemoryChannelCounter() : + read(-1.0), + write(-1.0), + total(-1.0) {} + } ALIGN(ALIGNMENT); + + typedef struct PCMMemoryChannelCounter PCMMemoryChannelCounter; + + struct PCMMemorySocketCounter { + PCMMemoryChannelCounter channels[MEMORY_MAX_IMC_CHANNELS]; + float read; + float write; + float partialWrite; + float total; + + public: + PCMMemorySocketCounter() : + read(-1.0), + write(-1.0), + partialWrite(-1.0), + total(-1.0) {} + } ALIGN(ALIGNMENT); + + typedef struct PCMMemorySocketCounter PCMMemorySocketCounter; + + struct PCMMemorySystemCounter { + float read; + float write; + float total; + + public: + PCMMemorySystemCounter() : + read(-1.0), + write(-1.0), + total(-1.0) {} + } ALIGN(ALIGNMENT); + + typedef struct PCMMemorySystemCounter PCMMemorySystemCounter; + + struct PCMMemory { + uint32 numOfSockets; + PCMMemorySocketCounter sockets[MAX_SOCKETS]; + PCMMemorySystemCounter system; + bool dramEnergyMetricsAvailable; + double dramEnergyForSockets[MAX_SOCKETS] ALIGN(ALIGNMENT); + + public: + PCMMemory() : + dramEnergyMetricsAvailable(false) { + for(int i = 0; i < MAX_SOCKETS; ++i) + { + dramEnergyForSockets[i] = -1.0; + } + } + } ALIGN(ALIGNMENT); + + typedef struct PCMMemory PCMMemory; + + struct PCMQPILinkCounter { + uint64 bytes; + double utilization; + + public: + PCMQPILinkCounter() : + bytes(0), + utilization(-1.0) {} + } ALIGN(ALIGNMENT); + + typedef struct PCMQPILinkCounter PCMQPILinkCounter; + + struct PCMQPISocketCounter { + PCMQPILinkCounter links[QPI_MAX_LINKS]; + uint64 total; + + public: + PCMQPISocketCounter() : + total(0) {} + } ALIGN(ALIGNMENT); + + typedef struct PCMQPISocketCounter PCMQPISocketCounter; + + struct PCMQPI { + uint32 numOfSockets; + uint32 numOfLinksPerSocket; + PCMQPISocketCounter incoming[MAX_SOCKETS]; + uint64 incomingTotal; + PCMQPISocketCounter outgoing[MAX_SOCKETS]; + uint64 outgoingTotal; + bool incomingQPITrafficMetricsAvailable; + bool outgoingQPITrafficMetricsAvailable; + + public: + PCMQPI() : + incomingTotal(0), + outgoingTotal(0), + incomingQPITrafficMetricsAvailable(false), + outgoingQPITrafficMetricsAvailable(false) {} + } ALIGN(ALIGNMENT); + + typedef struct PCMQPI PCMQPI; + + struct SharedPCMCounters { + PCMCore core; + PCMMemory memory; + PCMQPI qpi; + } ALIGN(ALIGNMENT); + + typedef struct SharedPCMCounters SharedPCMCounters; + + struct SharedPCMState { + char version[VERSION_SIZE]; + uint64 lastUpdateTsc; + uint64 timestamp; + uint64 cyclesToGetPCMState; + uint32 pollMs; + SharedPCMCounters pcm; + + public: + SharedPCMState() : + lastUpdateTsc(0), + pollMs(-1) { + memset(this->version, '\0', sizeof(char)*VERSION_SIZE); + } + } ALIGN(ALIGNMENT); + + typedef struct SharedPCMState SharedPCMState; +} + +#endif /* COMMON_H_ */ diff --git a/daemon/daemon/daemon.cpp b/daemon/daemon/daemon.cpp new file mode 100644 index 00000000..779bb4bc --- /dev/null +++ b/daemon/daemon/daemon.cpp @@ -0,0 +1,691 @@ +/* + Copyright (c) 2009-2016, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// written by Steven Briscoe + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "daemon.h" +#include "common.h" +#include "pcm.h" + +namespace PCMDaemon { + + int Daemon::sharedMemoryId_; + SharedPCMState* Daemon::sharedPCMState_; + + Daemon::Daemon(int argc, char *argv[]) + : debugMode_(false), pollIntervalMs_(0), groupName_(""), mode_(Mode::DIFFERENCE), pcmInstance_(NULL) + { + allowedSubscribers_.push_back("core"); + allowedSubscribers_.push_back("memory"); + allowedSubscribers_.push_back("qpi"); + + sharedMemoryId_ = 0; + sharedPCMState_ = NULL; + + readApplicationArguments(argc, argv); + + setupPCM(); + + setupSharedMemory(); + + //Put the poll interval in shared memory so that the client knows + sharedPCMState_->pollMs = pollIntervalMs_; + + updatePCMState(&systemStatesBefore_, &socketStatesBefore_, &coreStatesBefore_); + + serverUncorePowerStatesBefore_ = new ServerUncorePowerState[pcmInstance_->getNumSockets()]; + serverUncorePowerStatesAfter_ = new ServerUncorePowerState[pcmInstance_->getNumSockets()]; + } + + int Daemon::run() + { + std::cout << std::endl << "**** PCM Daemon Started *****" << std::endl; + + while(true) + { + if(debugMode_) + { + time_t rawtime; + struct tm * timeinfo; + char timeBuffer[200]; + time ( &rawtime ); + timeinfo = localtime ( &rawtime ); + + sprintf(timeBuffer, "[%02d %02d %04d %02d:%02d:%02d]",timeinfo->tm_mday, timeinfo->tm_mon + 1, timeinfo->tm_year + 1900, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); + + std::cout << timeBuffer << "\tFetching counters..." << std::endl; + } + + usleep(pollIntervalMs_ * 1000); + + getPCMCounters(); + } + + return EXIT_SUCCESS; + } + + Daemon::~Daemon() + { + delete serverUncorePowerStatesBefore_; + delete serverUncorePowerStatesAfter_; + } + + void Daemon::setupPCM() + { + pcmInstance_ = PCM::getInstance(); + pcmInstance_->setBlocked(false); + set_signal_handlers(); + set_post_cleanup_callback(&Daemon::cleanup); + + checkAccessAndProgramPCM(); + } + + void Daemon::checkAccessAndProgramPCM() + { + PCM::ErrorCode status; + + if(subscribers_.find("core") != subscribers_.end()) + { + EventSelectRegister defEventSelectRegister; + defEventSelectRegister.value = 0; + defEventSelectRegister.fields.usr = 1; + defEventSelectRegister.fields.os = 1; + defEventSelectRegister.fields.enable = 1; + + uint32 numOfCustomCounters = 4; + + EventSelectRegister regs[numOfCustomCounters]; + PCM::ExtendedCustomCoreEventDescription conf; + conf.nGPCounters = numOfCustomCounters; + conf.gpCounterCfg = regs; + + // TODO: This needs to be abstracted somewhere else + switch (pcmInstance_->getCPUModel()) + { + case PCM::WESTMERE_EX: + conf.OffcoreResponseMsrValue[0] = 0x40FF; // OFFCORE_RESPONSE.ANY_REQUEST.LOCAL_DRAM: Offcore requests satisfied by the local DRAM + conf.OffcoreResponseMsrValue[1] = 0x20FF; // OFFCORE_RESPONSE.ANY_REQUEST.REMOTE_DRAM: Offcore requests satisfied by a remote DRAM + break; + case PCM::JAKETOWN: + case PCM::IVYTOWN: + conf.OffcoreResponseMsrValue[0] = 0x780400000 | 0x08FFF; // OFFCORE_RESPONSE.*.LOCAL_DRAM + conf.OffcoreResponseMsrValue[1] = 0x7ff800000 | 0x08FFF; // OFFCORE_RESPONSE.*.REMOTE_DRAM + break; + case PCM::HASWELLX: + conf.OffcoreResponseMsrValue[0] = 0x600400000 | 0x08FFF; // OFFCORE_RESPONSE.*.LOCAL_DRAM + conf.OffcoreResponseMsrValue[1] = 0x63f800000 | 0x08FFF; // OFFCORE_RESPONSE.*.REMOTE_DRAM + break; + case PCM::BDX: + conf.OffcoreResponseMsrValue[0] = 0x0604008FFF; // OFFCORE_RESPONSE.*.LOCAL_DRAM + conf.OffcoreResponseMsrValue[1] = 0x067BC08FFF; // OFFCORE_RESPONSE.*.REMOTE_DRAM + break; + default: + std::cerr << std::endl << "PCM daemon does not support your processor currently." << std::endl << std::endl; + exit(EXIT_FAILURE); + } + + // Set default values for event select registers + for (uint32 i(0); i < numOfCustomCounters; ++i) + regs[i] = defEventSelectRegister; + + regs[0].fields.event_select = 0xB7; // OFFCORE_RESPONSE 0 event + regs[0].fields.umask = 0x01; + regs[1].fields.event_select = 0xBB; // OFFCORE_RESPONSE 1 event + regs[1].fields.umask = 0x01; + regs[2].fields.event_select = ARCH_LLC_MISS_EVTNR; + regs[2].fields.umask = ARCH_LLC_MISS_UMASK; + regs[3].fields.event_select = ARCH_LLC_REFERENCE_EVTNR; + regs[3].fields.umask = ARCH_LLC_REFERENCE_UMASK; + + status = pcmInstance_->program(PCM::EXT_CUSTOM_CORE_EVENTS, &conf); + } + else + { + status = pcmInstance_->program(); + } + + switch (status) + { + case PCM::Success: + break; + case PCM::MSRAccessDenied: + std::cerr << "Access to Intel(r) Performance Counter Monitor has denied (no MSR or PCI CFG space access)." << std::endl; + exit(EXIT_FAILURE); + case PCM::PMUBusy: + std::cerr << "Access to Intel(r) Performance Counter Monitor has denied (Performance Monitoring Unit is occupied by other application). Try to stop the application that uses PMU." << std::endl; + std::cerr << "Alternatively you can try to reset PMU configuration at your own risk. Try to reset? (y/n)" << std::endl; + char yn; + std::cin >> yn; + if ('y' == yn) + { + pcmInstance_->resetPMU(); + std::cerr << "PMU configuration has been reset. Try to rerun the program again." << std::endl; + } + exit(EXIT_FAILURE); + default: + std::cerr << "Access to Intel(r) Performance Counter Monitor has denied (Unknown error)." << std::endl; + exit(EXIT_FAILURE); + } + } + + void Daemon::readApplicationArguments(int argc, char *argv[]) + { + int opt; + int counterCount(0); + + if(argc == 1) + { + printExampleUsageAndExit(argv); + } + + std::cout << std::endl; + + while ((opt = getopt(argc, argv, "p:c:dg:m:")) != -1) + { + switch (opt) { + case 'p': + pollIntervalMs_ = atoi(optarg); + + std::cout << "Polling every " << pollIntervalMs_ << "ms" << std::endl; + break; + case 'c': + { + std::string subscriber(optarg); + + if(subscriber == "all") + { + for(std::vector::const_iterator it = allowedSubscribers_.begin(); it != allowedSubscribers_.end(); ++it) + { + subscribers_.insert(std::pair(*it, 1)); + ++counterCount; + } + } + else + { + if(std::find(allowedSubscribers_.begin(), allowedSubscribers_.end(), subscriber) == allowedSubscribers_.end()) + { + printExampleUsageAndExit(argv); + } + + subscribers_.insert(std::pair(subscriber, 1)); + ++counterCount; + } + + std::cout << "Listening to '" << subscriber << "' counters" << std::endl; + } + break; + case 'd': + debugMode_ = true; + + std::cout << "Debug mode enabled" << std::endl; + break; + case 'g': + { + groupName_ = std::string(optarg); + + std::cout << "Restricting to group: " << groupName_ << std::endl; + } + break; + case 'm': + { + std::string mode = std::string(optarg); + std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower); + + if(mode == "difference") + { + mode_ = Mode::DIFFERENCE; + } + else if(mode == "absolute") + { + mode_ = Mode::ABSOLUTE; + } + else + { + printExampleUsageAndExit(argv); + } + + std::cout << "Operational mode: " << mode << std::endl; + } + break; + default: + printExampleUsageAndExit(argv); + break; + } + } + + if(pollIntervalMs_ <= 0 || counterCount == 0) + { + printExampleUsageAndExit(argv); + } + + std::cout << "PCM Daemon version: " << VERSION << std::endl; + } + + void Daemon::printExampleUsageAndExit(char *argv[]) + { + std::cerr << std::endl; + std::cerr << "-------------------------------------------------------------------" << std::endl; + std::cerr << "Example usage: " << argv[0] << " -p 50 -c numa -c memory" << std::endl; + std::cerr << "Poll every 50ms. Fetch counters for numa and memory" << std::endl << std::endl; + + std::cerr << "Example usage: " << argv[0] << " -p 250 -c all -g pcm -m absolute" << std::endl; + std::cerr << "Poll every 250ms. Fetch all counters (core, numa & memory)." << std::endl; + std::cerr << "Restrict access to user group 'pcm'. Store absolute values on each poll interval" << std::endl << std::endl; + + std::cerr << "-p for poll frequency" << std::endl; + std::cerr << "-c to request specific counters (Allowed counters: all "; + + for(std::vector::const_iterator it = allowedSubscribers_.begin(); it != allowedSubscribers_.end(); ++it) + { + std::cerr << *it; + + if(it+1 != allowedSubscribers_.end()) + { + std::cerr << " "; + } + } + + std::cerr << ")"; + + std::cerr << std::endl << "-d flag for debug output [optional]" << std::endl; + std::cerr << "-g to restrict access to group [optional]" << std::endl; + std::cerr << "-m stores differences or absolute values (Allowed: difference absolute) Default: difference [optional]" << std::endl << std::endl; + + exit(EXIT_FAILURE); + } + + void Daemon::setupSharedMemory(key_t key) + { + int mode = 0660; + int shmFlag = IPC_CREAT | mode; + + sharedMemoryId_ = shmget(key, sizeof(SharedPCMState), shmFlag); + if (sharedMemoryId_ < 0) + { + std::cerr << "Failed to allocate shared memory segment (errno=" << errno << ")" << std::endl; + exit(EXIT_FAILURE); + } + + if(groupName_.size() > 0) + { + ushort gid = (ushort)resolveGroupName(groupName_); + + struct shmid_ds shmData; + shmData.shm_perm.gid = gid; + shmData.shm_perm.mode = mode; + + int success = shmctl(sharedMemoryId_, IPC_SET, &shmData); + if(success < 0) + { + std::cerr << "Failed to IPC_SET (errno=" << errno << ")" << std::endl; + exit(EXIT_FAILURE); + } + } + + sharedPCMState_ = (SharedPCMState*)shmat(sharedMemoryId_, NULL, 0); + if (sharedPCMState_ == (void *)-1) + { + std::cerr << "Failed to attach shared memory segment (errno=" << errno << ")" << std::endl; + exit(EXIT_FAILURE); + } + + //Clear out shared memory + std::memset(sharedPCMState_, 0, sizeof(SharedPCMState)); + } + + gid_t Daemon::resolveGroupName(std::string& groupName) + { + struct group* group = getgrnam(groupName.c_str()); + + if(group == NULL) + { + std::cerr << "Failed to resolve group '" << groupName << "'" << std::endl; + exit(EXIT_FAILURE); + } + + return group->gr_gid; + } + + void Daemon::getPCMCounters() + { + memcpy (sharedPCMState_->version, VERSION, sizeof(VERSION)); + sharedPCMState_->version[sizeof(VERSION)] = '\0'; + + sharedPCMState_->lastUpdateTsc = RDTSC(); + sharedPCMState_->timestamp = getTimestamp(); + + updatePCMState(&systemStatesAfter_, &socketStatesAfter_, &coreStatesAfter_); + + if(subscribers_.find("core") != subscribers_.end()) + { + getPCMCore(); + } + if(subscribers_.find("memory") != subscribers_.end()) + { + getPCMMemory(); + } + if(subscribers_.find("qpi") != subscribers_.end()) + { + getPCMQPI(); + } + + sharedPCMState_->cyclesToGetPCMState = RDTSC() - sharedPCMState_->lastUpdateTsc; + + if(mode_ == Mode::DIFFERENCE) + { + swapPCMBeforeAfterState(); + } + + std::swap(collectionTimeBefore_, collectionTimeAfter_); + } + + void Daemon::updatePCMState(SystemCounterState* systemStates, std::vector* socketStates, std::vector* coreStates) + { + if(subscribers_.find("core") != subscribers_.end()) + { + pcmInstance_->getAllCounterStates(*systemStates, *socketStates, *coreStates); + } + else + { + if(subscribers_.find("memory") != subscribers_.end() || subscribers_.find("qpi") != subscribers_.end()) + { + pcmInstance_->getUncoreCounterStates(*systemStates, *socketStates); + } + } + collectionTimeAfter_ = pcmInstance_->getTickCount(); + } + + void Daemon::swapPCMBeforeAfterState() + { + //After state now becomes before state (for the next iteration) + std::swap(coreStatesBefore_, coreStatesAfter_); + std::swap(socketStatesBefore_, socketStatesAfter_); + std::swap(systemStatesBefore_, systemStatesAfter_); + std::swap(serverUncorePowerStatesBefore_, serverUncorePowerStatesAfter_); + } + + void Daemon::getPCMCore() + { + PCMCore& core = sharedPCMState_->pcm.core; + + const uint32 numCores = pcmInstance_->getNumCores(); + + uint32 onlineCoresI = 0; + for(uint32 coreI = 0; coreI < numCores ; ++coreI) + { + if(!pcmInstance_->isCoreOnline(coreI)) + continue; + + PCMCoreCounter& coreCounters = core.cores[onlineCoresI]; + + int32 socketId = pcmInstance_->getSocketId(coreI); + double instructionsPerCycle = getIPC(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + uint64 cycles = getCycles(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + uint64 instructionsRetired = getInstructionsRetired(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + double execUsage = getExecUsage(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + double relativeFrequency = getRelativeFrequency(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + double activeRelativeFrequency = getActiveRelativeFrequency(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + uint64 l3CacheMisses = getNumberOfCustomEvents(2, coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + uint64 l3CacheReference = getNumberOfCustomEvents(3, coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + uint64 l2CacheMisses = getL2CacheMisses(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + double l3CacheHitRatio = getL3CacheHitRatio(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + double l2CacheHitRatio = getL2CacheHitRatio(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + double l3CacheMPI = double(l3CacheMisses) / instructionsRetired; + double l2CacheMPI = double(l2CacheMisses) / instructionsRetired; + int32 thermalHeadroom = coreStatesAfter_[coreI].getThermalHeadroom(); + + coreCounters.coreId = coreI; + coreCounters.socketId = socketId; + coreCounters.instructionsPerCycle = instructionsPerCycle; + coreCounters.cycles = cycles; + coreCounters.instructionsRetired = instructionsRetired; + coreCounters.execUsage = execUsage; + coreCounters.relativeFrequency = relativeFrequency; + coreCounters.activeRelativeFrequency = activeRelativeFrequency; + coreCounters.l3CacheMisses = l3CacheMisses; + coreCounters.l3CacheReference = l3CacheReference; + coreCounters.l2CacheMisses = l2CacheMisses; + coreCounters.l3CacheHitRatio = l3CacheHitRatio; + coreCounters.l2CacheHitRatio = l2CacheHitRatio; + coreCounters.l3CacheMPI = l3CacheMPI; + coreCounters.l2CacheMPI = l2CacheMPI; + coreCounters.thermalHeadroom = thermalHeadroom; + + coreCounters.l3CacheOccupancyAvailable = pcmInstance_->L3CacheOccupancyMetricAvailable(); + if (coreCounters.l3CacheOccupancyAvailable) + { + uint64 l3CacheOccupancy = getL3CacheOccupancy(coreStatesAfter_[coreI]); + coreCounters.l3CacheOccupancy = l3CacheOccupancy; + } + + coreCounters.localMemoryBWAvailable = pcmInstance_->CoreLocalMemoryBWMetricAvailable(); + if (coreCounters.localMemoryBWAvailable) + { + uint64 localMemoryBW = getLocalMemoryBW(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + coreCounters.localMemoryBW = localMemoryBW; + } + + coreCounters.remoteMemoryBWAvailable = pcmInstance_->CoreRemoteMemoryBWMetricAvailable(); + if (coreCounters.remoteMemoryBWAvailable) + { + uint64 remoteMemoryBW = getRemoteMemoryBW(coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + coreCounters.remoteMemoryBW = remoteMemoryBW; + } + + coreCounters.localMemoryAccesses = getNumberOfCustomEvents(0, coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + coreCounters.remoteMemoryAccesses = getNumberOfCustomEvents(1, coreStatesBefore_[coreI], coreStatesAfter_[coreI]); + + ++onlineCoresI; + } + + core.numOfCores = numCores; + core.numOfOnlineCores = onlineCoresI; + core.numOfSockets = pcmInstance_->getNumSockets(); + + core.packageEnergyMetricsAvailable = pcmInstance_->packageEnergyMetricsAvailable(); + if(core.packageEnergyMetricsAvailable) + { + for (uint32 i(0); i < core.numOfSockets; ++i) + { + core.energyUsedBySockets[i] = getConsumedJoules(socketStatesBefore_[i], socketStatesAfter_[i]); + } + } + } + + void Daemon::getPCMMemory() + { + pcmInstance_->disableJKTWorkaround(); + + for(uint32 i(0); i < pcmInstance_->getNumSockets(); ++i) + { + serverUncorePowerStatesAfter_[i] = pcmInstance_->getServerUncorePowerState(i); + } + + calculateMemoryBandwidth(serverUncorePowerStatesBefore_, serverUncorePowerStatesAfter_, collectionTimeAfter_ - collectionTimeBefore_); + + PCMMemory memory = sharedPCMState_->pcm.memory; + memory.dramEnergyMetricsAvailable = pcmInstance_->dramEnergyMetricsAvailable(); + if(memory.dramEnergyMetricsAvailable) + { + for (uint32 i(0); i < memory.numOfSockets; ++i) + { + memory.dramEnergyForSockets[i] = getDRAMConsumedJoules(socketStatesBefore_[i], socketStatesAfter_[i]); + } + } + } + + void Daemon::calculateMemoryBandwidth(ServerUncorePowerState* uncState1, ServerUncorePowerState* uncState2, uint64 elapsedTime) + { + float iMC_Rd_socket_chan[MAX_SOCKETS][MEMORY_MAX_IMC_CHANNELS]; + float iMC_Wr_socket_chan[MAX_SOCKETS][MEMORY_MAX_IMC_CHANNELS]; + float iMC_Rd_socket[MAX_SOCKETS]; + float iMC_Wr_socket[MAX_SOCKETS]; + uint64 partial_write[MAX_SOCKETS]; + + uint32 numOfSockets = pcmInstance_->getNumSockets(); + + for(uint32 skt = 0; skt < numOfSockets; ++skt) + { + iMC_Rd_socket[skt] = 0.0; + iMC_Wr_socket[skt] = 0.0; + partial_write[skt] = 0; + + for(uint32 channel(0); channel < MEMORY_MAX_IMC_CHANNELS; ++channel) + { + if(getMCCounter(channel,MEMORY_READ,uncState1[skt],uncState2[skt]) == 0.0 && getMCCounter(channel,MEMORY_WRITE,uncState1[skt],uncState2[skt]) == 0.0) //In case of JKT-EN, there are only three channels. Skip one and continue. + { + iMC_Rd_socket_chan[skt][channel] = -1.0; + iMC_Wr_socket_chan[skt][channel] = -1.0; + continue; + } + + iMC_Rd_socket_chan[skt][channel] = (float) (getMCCounter(channel,MEMORY_READ,uncState1[skt],uncState2[skt]) * 64 / 1000000.0 / (elapsedTime/1000.0)); + iMC_Wr_socket_chan[skt][channel] = (float) (getMCCounter(channel,MEMORY_WRITE,uncState1[skt],uncState2[skt]) * 64 / 1000000.0 / (elapsedTime/1000.0)); + + iMC_Rd_socket[skt] += iMC_Rd_socket_chan[skt][channel]; + iMC_Wr_socket[skt] += iMC_Wr_socket_chan[skt][channel]; + + partial_write[skt] += (uint64) (getMCCounter(channel,MEMORY_PARTIAL,uncState1[skt],uncState2[skt]) / (elapsedTime/1000.0)); + } + } + + PCMMemory& memory = sharedPCMState_->pcm.memory; + memory.numOfSockets = numOfSockets; + + float sysRead(0.0); + float sysWrite(0.0); + + for(uint32 skt = 0; skt < numOfSockets; ++skt) + { + uint64 currentChannelI(0); + for(uint64 channel(0); channel < MEMORY_MAX_IMC_CHANNELS; ++channel) + { + if(iMC_Rd_socket_chan[0][skt*MEMORY_MAX_IMC_CHANNELS+channel] < 0.0 && iMC_Wr_socket_chan[0][skt*MEMORY_MAX_IMC_CHANNELS+channel] < 0.0) //If the channel read neg. value, the channel is not working; skip it. + continue; + + memory.sockets[skt].channels[currentChannelI].read = iMC_Rd_socket_chan[0][skt*MEMORY_MAX_IMC_CHANNELS+channel]; + memory.sockets[skt].channels[currentChannelI].write = iMC_Wr_socket_chan[0][skt*MEMORY_MAX_IMC_CHANNELS+channel]; + memory.sockets[skt].channels[currentChannelI].total = memory.sockets[skt].channels[currentChannelI].read + memory.sockets[skt].channels[currentChannelI].write; + + ++currentChannelI; + } + + memory.sockets[skt].read = iMC_Rd_socket[skt]; + memory.sockets[skt].write = iMC_Wr_socket[skt]; + memory.sockets[skt].partialWrite = partial_write[skt]; + memory.sockets[skt].total= iMC_Rd_socket[skt] + iMC_Wr_socket[skt]; + + sysRead += iMC_Rd_socket[skt]; + sysWrite += iMC_Wr_socket[skt]; + } + + memory.system.read = sysRead; + memory.system.write = sysWrite; + memory.system.total = sysRead + sysWrite; + } + + void Daemon::getPCMQPI() + { + PCMQPI& qpi = sharedPCMState_->pcm.qpi; + + qpi.numOfSockets = pcmInstance_->getNumSockets(); + qpi.numOfLinksPerSocket = pcmInstance_->getQPILinksPerSocket(); + + qpi.incomingQPITrafficMetricsAvailable = pcmInstance_->getNumSockets() > 1 && pcmInstance_->incomingQPITrafficMetricsAvailable(); + if (qpi.incomingQPITrafficMetricsAvailable) // QPI info only for multi socket systems + { + int64 qpiLinks = qpi.numOfLinksPerSocket; + + for (uint32 i(0); i < qpi.numOfSockets; ++i) + { + uint64 total(0); + for (uint32 l(0); l < qpiLinks; ++l) + { + qpi.outgoing[i].links[l].bytes = getIncomingQPILinkBytes(i, l, systemStatesBefore_, systemStatesAfter_); + qpi.outgoing[i].links[l].utilization = getIncomingQPILinkUtilization(i, l, systemStatesBefore_, systemStatesAfter_); + + total+=qpi.incoming[i].links[l].bytes; + } + qpi.incoming[i].total = total; + } + + qpi.outgoingTotal = getAllIncomingQPILinkBytes(systemStatesBefore_, systemStatesAfter_); + } + + qpi.outgoingQPITrafficMetricsAvailable = pcmInstance_->getNumSockets() > 1 && pcmInstance_->outgoingQPITrafficMetricsAvailable(); + if (qpi.outgoingQPITrafficMetricsAvailable) // QPI info only for multi socket systems + { + uint64 qpiLinks = qpi.numOfLinksPerSocket; + + for (uint32 i(0); i < qpi.numOfSockets; ++i) + { + uint64 total(0); + for (uint32 l(0); l < qpiLinks; ++l) + { + qpi.outgoing[i].links[l].bytes = getOutgoingQPILinkBytes(i, l, systemStatesBefore_, systemStatesAfter_); + qpi.outgoing[i].links[l].utilization = getOutgoingQPILinkUtilization(i, l, systemStatesBefore_, systemStatesAfter_); + + total+=qpi.outgoing[i].links[l].bytes; + } + qpi.outgoing[i].total = total; + } + + qpi.outgoingTotal = getAllOutgoingQPILinkBytes(systemStatesBefore_, systemStatesAfter_); + } + } + + uint64 Daemon::getTimestamp() + { + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + + uint64 epoch = (uint64)now.tv_sec * 10E9; + epoch+=(uint64)now.tv_nsec; + + return epoch; + } + + void Daemon::cleanup() + { + if(sharedPCMState_ != NULL) + { + // Detatch shared memory segment + int success = shmdt(sharedPCMState_); + if(success != 0) + { + std::cerr << "An error occurred when detatching the shared memory segment (errno=" << errno << ")" << std::endl; + } + else + { + // Delete segment + success = shmctl(sharedMemoryId_, IPC_RMID, NULL); + if(success != 0) + { + std::cerr << "An error occurred when deleting the shared memory segment (errno=" << errno << ")" << std::endl; + } + } + } + } + +} diff --git a/daemon/daemon/daemon.h b/daemon/daemon/daemon.h new file mode 100644 index 00000000..b97e43ad --- /dev/null +++ b/daemon/daemon/daemon.h @@ -0,0 +1,75 @@ +/* + Copyright (c) 2009-2016, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// written by Steven Briscoe + +#ifndef DAEMON_H_ +#define DAEMON_H_ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "pcm.h" + +namespace PCMDaemon { + + enum Mode { DIFFERENCE, ABSOLUTE }; + + class Daemon { + public: + Daemon(int argc, char *argv[]); + ~Daemon(); + int run(); + private: + void setupPCM(); + void checkAccessAndProgramPCM(); + void readApplicationArguments(int argc, char *argv[]); + void printExampleUsageAndExit(char *argv[]); + void setupSharedMemory(key_t key = SHARED_MEMORY_KEY); + gid_t resolveGroupName(std::string& groupName); + void updatePCMState(SystemCounterState* systemStates, std::vector* socketStates, std::vector* coreStates); + void swapPCMBeforeAfterState(); + void getPCMCounters(); + void getPCMCore(); + void getPCMMemory(); + void calculateMemoryBandwidth(ServerUncorePowerState* uncState1, ServerUncorePowerState* uncState2, uint64 elapsedTime); + void getPCMQPI(); + uint64 getTimestamp(); + static void cleanup(); + + bool debugMode_; + uint32 pollIntervalMs_; + std::string groupName_; + Mode mode_; + + static int sharedMemoryId_; + static SharedPCMState* sharedPCMState_; + PCM* pcmInstance_; + std::map subscribers_; + std::vector allowedSubscribers_; + + //Data for core, socket and system state + uint64 collectionTimeBefore_, collectionTimeAfter_; + std::vector coreStatesBefore_, coreStatesAfter_; + std::vector socketStatesBefore_, socketStatesAfter_; + SystemCounterState systemStatesBefore_, systemStatesAfter_; + ServerUncorePowerState * serverUncorePowerStatesBefore_; + ServerUncorePowerState * serverUncorePowerStatesAfter_; + }; + +} + +#endif /* DAEMON_H_ */ diff --git a/daemon/daemon/main.cpp b/daemon/daemon/main.cpp new file mode 100644 index 00000000..80a88bcb --- /dev/null +++ b/daemon/daemon/main.cpp @@ -0,0 +1,22 @@ +/* + Copyright (c) 2009-2016, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// written by Steven Briscoe + +#include "daemon.h" + +int main(int argc, char *argv[]) +{ + PCMDaemon::Daemon daemon(argc, argv); + + return daemon.run(); +} diff --git a/daemon/daemon/pcm.h b/daemon/daemon/pcm.h new file mode 100644 index 00000000..a0d48b59 --- /dev/null +++ b/daemon/daemon/pcm.h @@ -0,0 +1,33 @@ +/* + Copyright (c) 2009-2016, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// written by Steven Briscoe + +#ifndef PCM_H_ +#define PCM_H_ + +#ifdef _MSC_VER + #pragma warning(disable : 4996) // for sprintf + #include + #include "../../../PCM_Win/windriver.h" +#else + #include + #include + #include // for gettimeofday() +#endif +#include "../../cpucounters.h" +#include "../../utils.h" +#ifdef _MSC_VER + #include "../../freegetopt/getopt.h" +#endif + +#endif /* PCM_H_ */ diff --git a/daemon/daemon/test/Makefile b/daemon/daemon/test/Makefile new file mode 100644 index 00000000..22596a9e --- /dev/null +++ b/daemon/daemon/test/Makefile @@ -0,0 +1,19 @@ +CC=g++ +CFLAGS=-c -Wall -std=c++11 +LDFLAGS= +SOURCES=main.cpp +OBJECTS=$(SOURCES:.cpp=.o) +EXECUTABLE=test +RM=rm + +all: $(SOURCES) $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) -o $@ + +.cpp.o: + $(CC) $(CFLAGS) $< -o $@ + +clean: + -$(RM) $(OBJECTS) $(EXECUTABLE) + -@echo ' ' \ No newline at end of file diff --git a/daemon/daemon/test/main.cpp b/daemon/daemon/test/main.cpp new file mode 100644 index 00000000..a49537fc --- /dev/null +++ b/daemon/daemon/test/main.cpp @@ -0,0 +1,84 @@ +#include +#include +#include + +#include "../common.h" + +#define ALIGNMENT 64 + +void checkAlignment(char const * debugMessage, void* ptr) +{ + printf("Checking: %-20s\t\t", debugMessage); + uint64_t currentAlignment = (uint64_t)ptr % ALIGNMENT; + if(currentAlignment != 0) + { + printf("Failed\n"); + printf("Current alignment: %lu\n\n", currentAlignment); + exit(EXIT_FAILURE); + } + else + { + printf("Passed\n"); + } +} + +int main() +{ + printf("Testing alignment\n\n"); + + PCMDaemon::SharedPCMState* pcmState = (PCMDaemon::SharedPCMState*)aligned_alloc(ALIGNMENT, sizeof(PCMDaemon::SharedPCMState)); + + checkAlignment("pcmState", pcmState); + + checkAlignment("pcm", &pcmState->pcm); + + checkAlignment("pcm core", &pcmState->pcm.core); + checkAlignment("pcm memory", &pcmState->pcm.memory); + checkAlignment("pcm qpi", &pcmState->pcm.qpi); + + for(uint32_t i(0); i < MAX_CPU_CORES; ++i) + { + checkAlignment("pcm core cores", &pcmState->pcm.core.cores[i]); + } + + checkAlignment("pcm core energyUsed", &pcmState->pcm.core.energyUsedBySockets); + + for(uint32_t i(0); i < MAX_SOCKETS; ++i) + { + checkAlignment("pcm memory sockets", &pcmState->pcm.memory.sockets[i]); + } + + checkAlignment("pcm memory dramEnergy", &pcmState->pcm.memory.dramEnergyForSockets); + + for(uint32_t i(0); i < MAX_SOCKETS; ++i) + { + checkAlignment("pcm qpi incoming", &pcmState->pcm.qpi.incoming[i]); + } + + for(uint32_t i(0); i < MAX_SOCKETS; ++i) + { + for(uint32_t j(0); j < QPI_MAX_LINKS; ++j) + { + checkAlignment("pcm qpi incoming links", &pcmState->pcm.qpi.incoming[i].links[j]); + } + } + + for(uint32_t i(0); i < MAX_SOCKETS; ++i) + { + checkAlignment("pcm qpi outgoing", &pcmState->pcm.qpi.outgoing[i]); + } + + for(uint32_t i(0); i < MAX_SOCKETS; ++i) + { + for(uint32_t j(0); j < QPI_MAX_LINKS; ++j) + { + checkAlignment("pcm qpi outgoing links", &pcmState->pcm.qpi.outgoing[i].links[j]); + } + } + + free(pcmState); + + printf("\n------ All passed ------\n\n"); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/utils.cpp b/utils.cpp index 424bfd87..b2a04ea5 100644 --- a/utils.cpp +++ b/utils.cpp @@ -27,6 +27,8 @@ CT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT #endif #include "utils.h" +void (*post_cleanup_callback)(void) = NULL; + //! \brief handler of exit() call void exit_cleanup(void) { @@ -39,6 +41,11 @@ void exit_cleanup(void) //TODO: delete other shared objects.... if any. + if(post_cleanup_callback != NULL) + { + post_cleanup_callback(); + } + // now terminate the program immediately _exit(EXIT_SUCCESS); } @@ -326,6 +333,11 @@ void restore_signal_handlers(void) return; } +void set_post_cleanup_callback(void(*cb)(void)) +{ + post_cleanup_callback = cb; +} + //!\brief launches external program in a separate process void MySystem(char * sysCmd, char ** sysArgv) { diff --git a/utils.h b/utils.h index 0865517e..47ab0fef 100644 --- a/utils.h +++ b/utils.h @@ -46,6 +46,8 @@ void sigSTOP_handler(int signum); void sigCONT_handler(int signum); #endif +void set_post_cleanup_callback(void(*cb)(void)); + #ifdef _MSC_VER inline void win_usleep(int delay_us) {