Commit b7f96ccd authored by Micha Mueller's avatar Micha Mueller
Browse files

Outsource Perfevent-Counters to dynamic shared library

Add possibility to compile with symbol DEBUG (use "make debug")
Minor fixes and improvements to debug-output
parent d42fccfa
......@@ -120,7 +120,7 @@ bool Configuration::read() {
ifstream sysfsStream(sysfsConfigFile.c_str());
if (sysfsStream.good()) {
//sysfs.conf exists --> open sysfs.so and read config
cout << "sysfs.conf found" << endl;
cout << endl << "sysfs.conf found" << endl;
sysfs.DL = dlopen("./libsysfs.so", RTLD_NOW);
if(!sysfs.DL) {
cerr << "Cannot load sysfs-library: " << dlerror() << endl;
......@@ -155,6 +155,7 @@ bool Configuration::read() {
_sensors.push_back(s);
} else {
cerr << "MQTT-Suffix used twice! Aborting" << endl;
return false;
}
}
} else {
......@@ -165,9 +166,45 @@ bool Configuration::read() {
perfeventConfigFile.append("perfevent.conf");
ifstream perfeventStream(perfeventConfigFile.c_str());
if (perfeventStream.good()) {
cout << "perfevent.conf found" << endl;
cout << endl << "perfevent.conf found" << endl;
//perfevent.conf exists. Open perfevent.so
//TODO check if mqtt used twice!
perfevent.DL = dlopen("./libperfevent.so", RTLD_NOW);
if(!sysfs.DL) {
cerr << "Cannot load perfevent-library: " << dlerror() << endl;
return false;
}
//reset errors
dlerror();
//set perfevent-struct
perfevent.create = (create_t*) dlsym(perfevent.DL, "create");
const char* dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol create for perfevent: " << dlsym_error << endl;
return false;
}
perfevent.destroy = (destroy_t*) dlsym(perfevent.DL, "destroy");
dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol destroy for perfevent: " << dlsym_error << endl;
return false;
}
perfevent.configurator = perfevent.create();
//read in config
std::vector<Sensor*>& perfeventSensors = perfevent.configurator->readConfig(perfeventConfigFile);
//save only pointers to the sensors; copy-constructing an dynamically loaded object may lead to segfaults
//but before storing them, check if an MQTT-suffix was assigned twice
for(auto s : perfeventSensors) {
if(checkMqtt(s->getMqtt())) {
_sensors.push_back(s);
} else {
cerr << "MQTT-Suffix used twice! Aborting" << endl;
return false;
}
}
} else {
cout << "[INFO] perfevent.conf not found. Omitting..." << endl;
}
......
......@@ -74,7 +74,7 @@ void MQTTPusher::push() {
std::size_t count = s->popReadingQueue(reads, 1024);
totalCount+= count;
#ifdef DEBUG
std::cout << s.getName() << " has read " << count << " values:" << std::endl;
std::cout << s->getName() << " has read " << count << " values:" << std::endl;
for (std::size_t i=0; i<count; i++) {
std::cout << " " << reads[i].timestamp << " " << reads[i].value << std::endl;
}
......
......@@ -7,17 +7,29 @@ include $(realpath $(dir $(lastword $(MAKEFILE_LIST)))/../..)/dcdb/common.mk
CXXFLAGS = -std=c++0x -O2 -g -Wall -Werror -Wno-unused-local-typedefs -Wno-unknown-warning-option -Wno-deprecated-declarations -I$(DCDBDEPLOYPATH)/include -I$(DCDBBASEPATH)/include
CXXFLAGS = -O2 -g -Wall -Wno-unused-function $(CXX11FLAGS) -I$(DCDBBASEPATH)/dcdb/include -I$(DCDBDEPLOYPATH)/include
LIBFLAGS = -fPIC -c $(CXXFLAGS)
LIBS = -L../deps/mosquitto_build/lib -L$(DCDBDEPLOYPATH)/lib/ -ldl -lmosquitto -lboost_system -lboost_thread -rdynamic
OBJS = dcdbpusher.o Configuration.o Sensor.o MQTTPusher.o
$(TARGET): $(OBJS)
$(TARGET): libs $(OBJS)
$(CXX) -o $(TARGET) $(OBJS) $(LIBS)
all: $(TARGET)
debug: CXXFLAGS += -DDEBUG
debug: $(TARGET)
clean:
rm -f $(OBJS) $(TARGET)
rm -f *.o *.so $(TARGET)
install: $(TARGET)
install $(TARGET) $(DCDBDEPLOYPATH)/bin/
install -m 644 $(TARGET).conf $(DCDBDEPLOYPATH)/etc
libs:
$(CXX) $(LIBFLAGS) sensors/sysfs/SysfsSensor.cpp
$(CXX) $(LIBFLAGS) sensors/sysfs/SysfsConfigurator.cpp
$(CXX) -shared -Wl,-soname,libsysfs.so -o libsysfs.so SysfsSensor.o SysfsConfigurator.o
$(CXX) $(LIBFLAGS) sensors/perfevent/PerfCounter.cpp
$(CXX) $(LIBFLAGS) sensors/perfevent/PerfeventConfigurator.cpp
$(CXX) -shared -Wl,-soname,libperfevent.so -o libperfevent.so PerfCounter.o PerfeventConfigurator.o
......@@ -24,8 +24,6 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//================================================================================
//define DEBUG
#include <dcdbdaemon.h>
#include <functional>
#include "Sensor.h"
......@@ -113,7 +111,7 @@ int main(int argc, char** argv) {
for(auto s : sensors) {
#ifdef DEBUG
cout << "Starting sensor " << s.getName() << endl;
cout << "Starting sensor " << s->getName() << endl;
#endif
s->startPolling(io);
}
......
......@@ -7,7 +7,6 @@
#include "PerfCounter.h"
#include "timestamp.h"
#include <string>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
......@@ -17,29 +16,18 @@
extern volatile int keepRunning;
PerfCounter::PerfCounter(const std::string name) {
_name = name;
PerfCounter::PerfCounter(const std::string& name) :
Sensor(name) {
_cpuId = 0;
_mqtt = "";
_minValues = 1;
_interval = 1000;
_type = 0;
_config = 0;
_fd = -1;
_latestValue.timestamp = 0;
_latestValue.value = 0;
_timer = NULL;
_readingQueue = NULL;
}
PerfCounter::~PerfCounter() {
if(_fd != -1) {
close(_fd);
}
if (_readingQueue != NULL) {
delete _readingQueue;
}
}
void PerfCounter::read() {
......@@ -74,7 +62,7 @@ void PerfCounter::readAsync() {
}
void PerfCounter::startPolling(boost::asio::io_service& io) {
if (_readingQueue == NULL) {
if (!_readingQueue) {
_readingQueue = new boost::lockfree::spsc_queue<reading_t>(1024);
}
......
......@@ -10,30 +10,14 @@
//#define DEBUG
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include "../../Sensor.h"
typedef struct {
uint64_t value;
uint64_t timestamp;
} reading_t;
class PerfCounter {
class PerfCounter : public Sensor{
public:
PerfCounter(const std::string name);
PerfCounter(const std::string& name);
virtual ~PerfCounter();
const std::string& getName() const {
return _name;
}
void setName(const std::string& name) {
_name = name;
}
int getCpuId() const {
return _cpuId;
}
......@@ -42,30 +26,6 @@ public:
_cpuId = cpuId;
}
const std::string& getMqtt() const {
return _mqtt;
}
void setMqtt(const std::string& mqtt) {
_mqtt = mqtt;
}
unsigned getMinValues() const {
return _minValues;
}
void setMinValues(unsigned minValues) {
_minValues = minValues;
}
unsigned getInterval() const {
return _interval;
}
void setInterval(unsigned interval) {
_interval = interval;
}
unsigned getType() const {
return _type;
}
......@@ -82,18 +42,6 @@ public:
_config = config;
}
const std::size_t getSizeOfReadingQueue() const {
return _readingQueue->read_available();
}
std::size_t popReadingQueue(reading_t *reads, std::size_t max) const {
return _readingQueue->pop(reads, max);
}
void pushReadingQueue(reading_t *reads, std::size_t count) const {
_readingQueue->push(reads, count);
}
void read();
void readAsync();
......@@ -101,18 +49,10 @@ public:
void startPolling(boost::asio::io_service& io);
private:
std::string _name;
int _cpuId;
std::string _mqtt;
unsigned int _minValues;
unsigned int _interval;
unsigned int _type;
unsigned int _config;
int _fd;
reading_t _latestValue;
boost::asio::deadline_timer* _timer;
boost::lockfree::spsc_queue<reading_t>* _readingQueue;
};
#endif /* PERFCOUNTER_H_ */
/*
* Configuration.cpp
* PerfeventConfigurator.cpp
*
* Created on: 13.12.2017
* Author: Micha Mueller
*/
#include "Configuration.h"
#include "PerfeventConfigurator.h"
#include <iostream>
#include <string>
#include <sstream>
#include <unistd.h>
#include <iomanip>
......@@ -20,9 +19,7 @@
using namespace std;
extern volatile int keepRunning;
PerfeventConfigurator::PerfeventConfigurator(std::string cfgFile) {
PerfeventConfigurator::PerfeventConfigurator() {
//set up enum-maps to map string from cfgFile to an enum value defined in linux/perf_event.h
_enumType["PERF_TYPE_HARDWARE"] = PERF_TYPE_HARDWARE;
_enumType["PERF_TYPE_SOFTWARE"] = PERF_TYPE_SOFTWARE;
......@@ -56,46 +53,27 @@ PerfeventConfigurator::PerfeventConfigurator(std::string cfgFile) {
_enumConfig["PERF_COUNT_SW_DUMMY"] = PERF_COUNT_SW_DUMMY;
//TODO set up map for rest of config enum
}
//set default values for global variables
_global.brokerHost = "";
_global.brokerPort = 1883;
_global.mqttPrefix = "";
_global.threads = 1;
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgFile, cfg);
//read global variables
BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("global")) {
cout << global.first << " " << global.second.data() << endl;
if(boost::iequals(global.first, "mqttBroker")) {
_global.brokerHost = global.second.data();
size_t pos = _global.brokerHost.find(":");
if (pos != string::npos) {
_global.brokerPort = stoi(_global.brokerHost.substr(pos+1));
_global.brokerHost.erase(pos);
}
} else if(boost::iequals(global.first, "mqttprefix")) {
_global.mqttPrefix = global.second.data();
if (_global.mqttPrefix[_global.mqttPrefix.length()-1] != '/') {
_global.mqttPrefix.append("/");
}
} else if (boost::iequals(global.first, "threads")) {
_global.threads = stoi(global.second.data());
} else {
cout << " Value \"" << global.first << "\" not recognized. Omitting..." << endl;
}
PerfeventConfigurator::~PerfeventConfigurator() {
for(auto s : _sensors) {
delete s;
}
}
std::vector<Sensor*>& PerfeventConfigurator::readConfig(std::string cfgPath) {
//read template counters
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgPath, cfg);
BOOST_FOREACH(boost::property_tree::iptree::value_type &counter, cfg.get_child("CounterTemplate")) {
if (boost::iequals(counter.first, "counter")) {
cout << "Template Counter \"" << counter.second.data() << "\"" << endl;
if (!counter.second.empty()) {
PerfCounter perfCounter(counter.second.data());
if(!readCounter(perfCounter, counter.second)) {
_templateCounters.insert(perfCounterMap_t::value_type(perfCounter.getName(), perfCounter));
if(readCounter(perfCounter, counter.second)) {
_templateCounters.insert(counterMap_t::value_type(perfCounter.getName(), perfCounter));
} else {
cout << "Template Counter \"" << counter.second.data() << "\" has bad values! Ignoring..." << endl;
}
......@@ -114,7 +92,7 @@ PerfeventConfigurator::PerfeventConfigurator(std::string cfgFile) {
boost::optional<boost::property_tree::iptree&> defaultC = counter.second.get_child_optional("default");
if(defaultC) {
cout << " Using \"" << defaultC.get().data() << "\" as default." << endl;
perfCounterMap_t::iterator it = _templateCounters.find(defaultC.get().data());
counterMap_t::iterator it = _templateCounters.find(defaultC.get().data());
if(it != _templateCounters.end()) {
perfCounter = it->second;
perfCounter.setName(counter.second.data());
......@@ -124,26 +102,21 @@ PerfeventConfigurator::PerfeventConfigurator(std::string cfgFile) {
}
//read remaining values
if(!readCounter(perfCounter, counter.second)) {
if(readCounter(perfCounter, counter.second)) {
//create distinct perfCounter and mqttSuffix per CPU
string startMqtt = perfCounter.getMqtt();
//customize perfCounter for every CPU
for (int i = 0; i < get_nprocs(); i++) {
PerfCounter* perfCC = new PerfCounter(counter.second.data());
*perfCC = perfCounter;
string incMqtt = increaseMqtt(startMqtt, i);
//check if mqtt-suffix is used twice
auto returnIt = _mqttSuffixes.insert(incMqtt);
if (!returnIt.second) {
cout << "ERROR: Mqtt-Topic (Suffix " << incMqtt << ") is used twice! Aborting" << endl;
keepRunning = 0;
return;
}
std::cout << " CPU " << perfCounter.getCpuId() << " using MQTT-Suffix " << incMqtt << std::endl;
perfCounter.setCpuId(i);
perfCounter.setMqtt(incMqtt);
_perfCounters.push_back(perfCounter);
perfCC->setCpuId(i);
perfCC->setMqtt(incMqtt);
std::cout << " CPU " << perfCC->getCpuId() << " using MQTT-Suffix " << incMqtt << std::endl;
_sensors.push_back(perfCC);
}
} else {
cout << " Counter \"" << counter.second.data() << "\" has bad values! Ignoring..." << endl;
......@@ -151,13 +124,10 @@ PerfeventConfigurator::PerfeventConfigurator(std::string cfgFile) {
}
}
}
return _sensors;
}
PerfeventConfigurator::~PerfeventConfigurator() {
// TODO Auto-generated destructor stub
}
int PerfeventConfigurator::readCounter(PerfCounter& counter, boost::property_tree::iptree& config) {
bool PerfeventConfigurator::readCounter(PerfCounter& counter, boost::property_tree::iptree& config) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
if (boost::iequals(val.first, "interval")) {
counter.setInterval(stoull(val.second.data()));
......@@ -172,15 +142,13 @@ int PerfeventConfigurator::readCounter(PerfCounter& counter, boost::property_tre
cout << " Type: " << val.second.data() << " (=" << counter.getType() << ")" << endl;
} else {
cout << " Type \"" << val.second.data() << "\" not known." << endl;
return 1;
return false;
}
} else if (boost::iequals(val.first, "config")) {
if (counter.getType() == PERF_TYPE_BREAKPOINT) {
//leave config zero
} else if (counter.getType() == PERF_TYPE_RAW) {
//read in custom hex-value
//TODO read in string-name and map to hex-value here?
// see info to perf_event_open and libpfm4
unsigned long config = stoul(val.second.data(), 0, 16);
counter.setConfig(config);
cout << " Config: Raw value: " << counter.getConfig() << endl;
......@@ -191,7 +159,7 @@ int PerfeventConfigurator::readCounter(PerfCounter& counter, boost::property_tre
cout << " Config: " << val.second.data() << " (= " << counter.getConfig() << ")" << endl;
} else {
cout << " Config \"" << val.second.data() << "\" not known." << endl;
return 1;
return false;
}
}
} else if (boost::iequals(val.first, "default")) {
......@@ -204,7 +172,7 @@ int PerfeventConfigurator::readCounter(PerfCounter& counter, boost::property_tre
cout << " StartMQTT: " << counter.getMqtt() << endl;
cout << " Interval : " << counter.getInterval() << endl;
cout << " minValues: " << counter.getMinValues() << endl;
return 0;
return true;
}
const std::string PerfeventConfigurator::increaseMqtt(const std::string& mqtt, int val) {
......
/*
* Configuration.h
* PerfeventConfigurator.h
*
* Created on: 13.12.2017
* Author: Micha Mueller
......@@ -8,49 +8,38 @@
#ifndef PERFEVENTCONFIGURATOR_H_
#define PERFEVENTCONFIGURATOR_H_
#include "PerfCounter.h"
#include "../../Configurator.h"
#include "../../Configuration.h"
#include <string>
#include <vector>
#include <map>
#include <set>
#include "PerfCounter.h"
#include <boost/property_tree/ptree.hpp>
typedef std::vector<Sensor> sensorVector_t;
class PerfeventConfigurator : public Configurator {
typedef std::vector<PerfCounter> perfCounterVector_t;
typedef std::map<std::string, PerfCounter> perfCounterMap_t;
typedef std::map<std::string, unsigned int> enumMap_t;
typedef std::set<std::string> mqttSet_t;
typedef std::map<std::string, PerfCounter> counterMap_t;
typedef std::map<std::string, unsigned int> enumMap_t;
typedef struct {
int brokerPort;
std::string brokerHost;
std::string mqttPrefix;
uint32_t threads;
} global_t;
public:
class PerfeventConfigurator {
PerfeventConfigurator();
virtual ~PerfeventConfigurator();
public:
/**
* Read the configuration for perfpusher.
* @param cfgFile Name of the configuration file
* @param cfgPath Path + name of the configuration file
*/
PerfeventConfigurator(std::string cfgFile);
virtual ~PerfeventConfigurator();
perfCounterVector_t _perfCounters;
global_t _global;
std::vector<Sensor*>& readConfig(std::string cfgPath);
private:
/**
* Set the variables of counter according to the values specified in config.
* @param counter The counter to be configured
* @param config A property(sub)tree containing the values
* @return 0 on success, 1 if a required value could not be parsed
* @return true on success, false if a required value could not be parsed
*/
int readCounter(PerfCounter& counter, boost::property_tree::iptree& config);
bool readCounter(PerfCounter& counter, boost::property_tree::iptree& config);
/**
* Increase the mqtt by val means
......@@ -63,11 +52,19 @@ private:
*/
const std::string increaseMqtt(const std::string& mqtt, int val);
perfCounterMap_t _templateCounters;
std::vector<Sensor*> _sensors;
counterMap_t _templateCounters;
enumMap_t _enumType;
enumMap_t _enumConfig;
mqttSet_t _mqttSuffixes;
};
extern "C" Configurator* create() {
return new PerfeventConfigurator;
}
extern "C" void destroy(Configurator* c) {
delete c;
}
#endif /* PERFEVENTCONFIGURATOR_H_ */
......@@ -101,15 +101,15 @@ void SysfsConfigurator::readSensor(SysfsSensor& sensor, boost::property_tree::ip
if(regex_match(input, matchResults, checkSubstitute)) {
//input has substitute format
#ifdef DEBUG
cout << " Init Regex with " << matchResults[2].str() << endl;
cout << " Substitution: " << matchResults[3].str() << endl;
cout << " Init Regex with: " << matchResults[2].str() << endl;
cout << " Substitution: " << matchResults[3].str() << endl;
#endif
sensor.setRegex(regex(matchResults[2].str(), regex_constants::extended));
sensor.setSubstitution(matchResults[3].str());
} else {
//input is only a regex
#ifdef DEBUG
cout << " Init Regex with " << input << endl;
cout << " Init Regex with " << input << endl;
#endif
sensor.setRegex(regex(input, regex_constants::extended));
sensor.setSubstitution("&");
......
......@@ -28,7 +28,6 @@ public:
/**
* Read in the configuration for sysfs-sensors.
* @param cfgPath Path + name of the config-file
* @param config Configuration where to store sensor-pointers and check for double used MQTT-suffixes
*/
std::vector<Sensor*>& readConfig(std::string cfgPath);
......@@ -37,7 +36,6 @@ private:
* Set the variables of sensor according to the values specified in config.
* @param sensor The sensor to be configured
* @param config A property(sub)tree containing the values
* @return True on success, false otherwise
*/
void readSensor(SysfsSensor& sensor, boost::property_tree::iptree& config);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment