MSRSensorGroup.cpp 5.37 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
23
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 "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>

#include "../../includes/Logging.h"
#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
196
197
void MSRSensorGroup::printConfig(LOG_LEVEL ll) {
    std::stringstream ss;
    const char* separator = "";
    for (auto &kv : cpuToFd) {
      ss << separator << kv.first;
      separator = ", ";
    }

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