MSRSensorGroup.cpp 5.36 KB
Newer Older
1
2
3
4
/*
 * MSRSensorGroup.cpp
 *
 *  Created on: 28.01.2019
5
 *      Author: Carla Guillen
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 */

#include "MSRSensorGroup.h"

#include <boost/log/core/record.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/formatting_ostream.hpp>
#include <boost/parameter/keyword.hpp>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <atomic>
#include <exception>
#include <utility>

23
#include "logging.h"
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "../../includes/SensorBase.h"
#include "timestamp.h"
#include "Types.h"
#include <sstream>
#include <iomanip>


MSRSensorGroup::MSRSensorGroup(const std::string& name) :
	SensorGroupTemplate(name) {
}

MSRSensorGroup::~MSRSensorGroup() {
}

void MSRSensorGroup::start() {
	if (_keepRunning) {
		//we have been started already
		LOG(info) << "Sensorgroup " << _groupName << " already running.";
		return;
	}

	for (auto &kv : cpuToFd) {
		int cpu = kv.first;
		char * path = new char[200];
		snprintf(path, 200, "/dev/cpu/%d/msr", cpu);
		int handle = open(path, O_RDWR);
		if (handle < 0) {   // try msr_safe
			snprintf(path, 200, "/dev/cpu/%d/msr_safe", cpu);
			handle = open(path, O_RDWR);
		}
		if (handle < 0){
			LOG(error) << "Can't open msr device " << path;
			delete [] path; // TODO do this with RAII
			continue;
		}
		delete [] path; //TODO do this with RAII
		cpuToFd[cpu] = handle;
	}

lu43jih's avatar
lu43jih committed
63
64
	program_fixed();

65
66
67
68
69
70
71
	_keepRunning = 1;
	_pendingTasks++;
	_timer->async_wait(std::bind(&MSRSensorGroup::readAsync, this));
	LOG(info) << "Sensorgroup " << _groupName << " started.";
}

void MSRSensorGroup::stop() {
lu43jih's avatar
lu43jih committed
72
73
    _keepRunning = 0;
    //close file descriptors and leave counters running freely
74
75
76
    for (auto &kv: cpuToFd) {
    	close(kv.second);
        kv.second = -1;
Micha Mueller's avatar
Micha Mueller committed
77
78
    }

lu43jih's avatar
lu43jih committed
79
    LOG(info) << "Sensorgroup " << _groupName << " stopped.";
80
81
82
83
84
85
86
87
}

void MSRSensorGroup::read() {
	ureading_t reading;
	reading.timestamp = getTimestamp();

	try {
		for(auto s : _sensors) {
lu43jih's avatar
lu43jih committed
88
89
90
			auto ret_val = msr_read(s->getMetric(), &reading.value, s->getCpu());
			if(ret_val != -1){
				 s->storeReading(reading);
91
#ifdef DEBUG
lu43jih's avatar
lu43jih committed
92
				LOG(debug) << _groupName << "::" << s->getName() << " raw reading: \"" << reading.value << "\"";
93
#endif
lu43jih's avatar
lu43jih committed
94
			}
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
		}
	} catch (const std::exception& e) {
		LOG(error) << "Sensorgroup" << _groupName << " could not read value: " << e.what();
	}
}

void MSRSensorGroup::readAsync() {
	uint64_t now = getTimestamp();
	read();
	if (_timer && _keepRunning) {
		_timer->expires_at(timestamp2ptime(nextReadingTime()));
		_pendingTasks++;
		_timer->async_wait(std::bind(&MSRSensorGroup::readAsync, this));
	}
	_pendingTasks--;
}

int32_t MSRSensorGroup::msr_read(uint64_t msr_number, uint64_t * value, unsigned int cpu){
	return pread(cpuToFd[cpu], (void *) value, sizeof(uint64_t), msr_number);
}

int32_t MSRSensorGroup::msr_write(uint64_t msr_number, uint64_t value, unsigned int cpu){
	return pwrite(cpuToFd[cpu], (const void *) &value, sizeof(uint64_t), msr_number);
}

Micha Mueller's avatar
Micha Mueller committed
120
121
122
123
124
125
/**
 * Program the fixed MSR as required for this plugin.
 *
 * @return  True if counters programmed successfully, false otherwise, e.g.
 *          because the counters are already in use.
 */
126
void MSRSensorGroup::program_fixed(){
Micha Mueller's avatar
Micha Mueller committed
127

128
129
130
	for (auto &kv : cpuToFd) {
		// program core counters

Micha Mueller's avatar
Micha Mueller committed
131
132
	    //we do not want to interrupt other services already doing measurements with MSRs
        //therefore check if any fixed counter is currently enabled
133
		struct FixedEventControlRegister ctrl_reg;
Micha Mueller's avatar
Micha Mueller committed
134

135
		msr_read(IA32_CR_FIXED_CTR_CTRL, &ctrl_reg.value, kv.first);
136
137
138
139
140
		//are they all enabled?
		if (ctrl_reg.fields.os0 && ctrl_reg.fields.usr0 && ctrl_reg.fields.os1
						&& ctrl_reg.fields.usr1 && ctrl_reg.fields.os2
						&& ctrl_reg.fields.usr2) {
			//yes! Free running counters were set by someone else => we don't need to program them, just read them.
lu43jih's avatar
lu43jih committed
141
			LOG(debug) << "CPU" << kv.first << " has free running counter, so there will be no fixed counter programming";
142
			continue;
Micha Mueller's avatar
Micha Mueller committed
143
		}
144
		//not all of them (or none) are enabled => we program them again
Micha Mueller's avatar
Micha Mueller committed
145
146
147
148

		// disable counters while programming
        msr_write(IA32_CR_PERF_GLOBAL_CTRL, 0, kv.first);

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
		ctrl_reg.fields.os0 = 1;
		ctrl_reg.fields.usr0 = 1;
		ctrl_reg.fields.any_thread0 = 0;
		ctrl_reg.fields.enable_pmi0 = 0;

		ctrl_reg.fields.os1 = 1;
		ctrl_reg.fields.usr1 = 1;
		ctrl_reg.fields.any_thread1 = 0;
		ctrl_reg.fields.enable_pmi1 = 0;

		ctrl_reg.fields.os2 = 1;
		ctrl_reg.fields.usr2 = 1;
		ctrl_reg.fields.any_thread2 = 0;
		ctrl_reg.fields.enable_pmi2 = 0;

		ctrl_reg.fields.reserved1 = 0;
165

166
		// program them
167
168
		msr_write(IA32_CR_FIXED_CTR_CTRL, ctrl_reg.value, kv.first);

169
		// start counting, enable 3 fixed counters (enable also the programmables counters)
lu43jih's avatar
lu43jih committed
170
		uint64_t value = (1ULL << 0) + (1ULL << 1) + (1ULL << 2) + (1ULL << 3) + (1ULL << 32) + (1ULL << 33) + (1ULL << 34);
171
		//uint64_t value = (1ULL << 32) + (1ULL << 33) + (1ULL << 34);
172
173
174
175
176
177
178
		msr_write(IA32_CR_PERF_GLOBAL_CTRL, value, kv.first);
	}
}

void MSRSensorGroup::addCpu(unsigned int cpu){
	cpuToFd[cpu] = -1; /* -1 because no file descriptor has been assigned yet. */
}
179

180
181
182
183
184
185
186
187
std::vector<unsigned> MSRSensorGroup::getCpus() {
  std::vector<unsigned> cpus;
  for(auto kv : cpuToFd) {
    cpus.push_back(kv.first);
  }
  return cpus;
}

188
189
190
191
192
193
194
195
void MSRSensorGroup::printConfig(LOG_LEVEL ll) {
    std::stringstream ss;
    const char* separator = "";
    for (auto &kv : cpuToFd) {
      ss << separator << kv.first;
      separator = ", ";
    }

196
    LOG_VAR(ll) << "            CPUs:  " << ss.str();
197
}