PerfSensor.cpp 2.77 KB
Newer Older
1
/*
2
 * PerfSensor.cpp
3
4
5
6
7
 *
 *  Created on: 11.12.2017
 *      Author: Micha Mueller
 */

8
9
#include "PerfSensor.h"

10
#include "timestamp.h"
11
#include <unistd.h>
12
13
#include <sys/ioctl.h>
#include <linux/perf_event.h>
14
#include <linux/hw_breakpoint.h>
15
#include <asm/unistd.h>
16
#include <functional>
17
#include <limits.h>
18

19
PerfSensor::PerfSensor(const std::string& name) :
20
	SensorBase(name), PerfSensorBase(name), SingleSensor(name) {}
21

22
PerfSensor::~PerfSensor() {}
23

24
void PerfSensor::start() {
25
26
27
28
29
30
	if (_keepRunning) {
		//we have been started already
		LOG(info) << "Sensor " << _name << " already running.";
		return;
	}

31
	//open perf-counter
32
33
34
35
36
37
38
	struct perf_event_attr pe;

	memset(&pe, 0, sizeof(struct perf_event_attr));
	pe.type = _type;
	pe.size = sizeof(struct perf_event_attr);
	pe.config = _config;
	pe.disabled = 1;
39
	pe.exclude_kernel = 0;
40
41
	pe.exclude_hv = 1;

42
43
44
45
	//perf_event_open()
	_fd = syscall(__NR_perf_event_open, &pe, -1, _cpuId, -1, 0);

	if (_fd == -1) {
46
		LOG(error) << "Failed to open performance-counter \"" << _name << "\"";
47
		return;
48
	}
49
50
51
52

	ioctl(_fd, PERF_EVENT_IOC_RESET, 0);
	ioctl(_fd, PERF_EVENT_IOC_ENABLE, 0);

53
	_keepRunning = 1;
54
	_pendingTasks++;
55
	_timer->async_wait(std::bind(&PerfSensor::readAsync, this));
56
57
58
	LOG(info) << "Sensor " << _name << " started.";
}

59
void PerfSensor::stop() {
60
61
62
63
64
65
	_keepRunning = 0;
	if(_fd != -1) {
		close(_fd);
		_fd = -1;
	}
	LOG(info) << "Sensor " << _name << " stopped.";
66
}
67

68
void PerfSensor::storeReading(reading_t reading, unsigned cacheIndex) {
69
70
71
72
73
74
75
76
77
78
79
	_readingQueue->push(reading);
	_cache[_cacheIndex] = reading;
	_cacheIndex = (_cacheIndex + 1) % _cacheSize;
	//want to store absolute values here
	if (ULLONG_MAX - _latestValue.value < reading.value) {
		_latestValue.value = reading.value - (ULLONG_MAX - _latestValue.value);
	} else {
		_latestValue.value += reading.value;
	}
	_latestValue.timestamp = reading.timestamp;
}
80

81
void PerfSensor::read() {
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
	reading_t reading;
	reading.timestamp = getTimestamp();

	unsigned long long count;

	if (::read(_fd, &count, sizeof(long long)) < 0) {
		LOG(error) << _name << " could not read value";
		return;
	}
	if (count >= _latestValue.value) {
		reading.value = count - _latestValue.value;
	} else {
		//the counter overflow since last read
		//according to perf_event_open() man-page u64 (=64bit) is used for event values
		//--> unsigned long long is usually also 64bit
		reading.value = count + (ULLONG_MAX - _latestValue.value);
	}
#ifdef DEBUG
	LOG(debug) << _name << ": \"" << reading.value << "\"";
#endif
	storeReading(reading, _cacheIndex);
}

105
void PerfSensor::readAsync() {
106
107
108
109
110
111
	uint64_t now = getTimestamp();
	read();
	if (_timer != NULL && _keepRunning) {
		uint64_t next = now + MS_TO_NS(_interval);
		_timer->expires_at(timestamp2ptime(next));
		_pendingTasks++;
112
		_timer->async_wait(std::bind(&PerfSensor::readAsync, this));
113
114
115
	}
	_pendingTasks--;
}