2.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

IPMISensorGroup.cpp 7.4 KB
Newer Older
1
2
3
//================================================================================
// Name        : IPMISensorGroup.cpp
// Author      : Michael Ott, Micha Mueller
Micha Müller's avatar
Micha Müller committed
4
// Contact     : info@dcdb.it
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Copyright   : Leibniz Supercomputing Centre
// Description : Source file for IPMI sensor group class.
//================================================================================

//================================================================================
// This file is part of DCDB (DataCenter DataBase)
// Copyright (C) 2017-2019 Leibniz Supercomputing Centre
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//================================================================================
27
28
29

#include "IPMISensorGroup.h"
#include "IPMIHost.h"
30
#include "LenovoXCC.h"
31
32

#include <chrono>
33
34
#include <exception>
#include <iostream>
35

36
IPMISensorGroup::IPMISensorGroup(const std::string &name)
37
    : SensorGroupTemplateEntity(name) {
38
39
}

40
IPMISensorGroup::IPMISensorGroup(const IPMISensorGroup &other)
41
    : SensorGroupTemplateEntity(other) {
42
}
43

44
45
IPMISensorGroup::~IPMISensorGroup() {}

46
47
IPMISensorGroup &IPMISensorGroup::operator=(const IPMISensorGroup &other) {
	SensorGroupTemplate::operator=(other);
48

49
	return *this;
50
51
}

52
53
54
55
56
float IPMISensorGroup::getMsgRate()  {
	float msgRate = 0;
	for (const auto &s : _sensors) {
		switch(s->getType()) {
			case IPMISensorBase::sensorType::xccDatastorePower:
57
58
				msgRate+= 3000.0f / (s->getSubsampling() * _minValues);
				break;
59
			case IPMISensorBase::sensorType::xccBulkPower:
60
				msgRate+= 100.0f / (s->getSubsampling() * _minValues);
61
62
				break;
			case IPMISensorBase::sensorType::xccBulkEnergy:
63
				msgRate+= 101.0f / (s->getSubsampling() * _minValues);
64
65
66
67
68
69
70
71
				break;
			default:
				msgRate+= SensorGroupTemplate::getMsgRate();
		}
	}
	return msgRate;
}

72
73
74
75
76
77
78
79
80
81
82
83
84
85
uint64_t IPMISensorGroup::readRaw(const std::vector<uint8_t> &rawCmd, uint8_t lsb, uint8_t msb) {
	uint8_t buf[256];
	int     len = -1;

	try {
		len = _entity->sendRawCmd(&rawCmd[0], rawCmd.size(), (void *)buf, sizeof(buf));
	} catch (const std::exception &e) {
		throw e;
		return 0;
	}

	std::stringstream ss;
	if (msb > len) {
		ss << "Error processing IPMI raw data: msb=" << msb << " > len=" << len;
86
	} else if (lsb > len) {
87
		ss << "Error processing IPMI raw data: lsb=" << lsb << " > len=" << len;
88
89
	}
	if (ss.gcount() > 0) {
90
91
		throw std::runtime_error(ss.str());
		return 0;
92
	}
93

94
	int64_t val = 0;
95
	int     i;
96
	if (msb > lsb) {
97
98
99
		for (i = lsb; i <= msb; i++) {
			val |= ((int64_t)buf[i]) << (msb - i) * 8;
		}
100
	} else {
101
102
103
		for (i = lsb; i >= msb; i--) {
			val |= ((int64_t)buf[i]) << (i - msb) * 8;
		}
104
	}
105

106
107
108
	return val;
}

109
110
void IPMISensorGroup::read() {
	reading_t reading;
Michael Ott's avatar
Michael Ott committed
111
	reading.value = 0;
112
113
	reading.timestamp = getTimestamp();

114
115
116
117
118
119
120
121
122
	if (_entity->connect() == 0) {
		for (const auto &s : _sensors) {
			try {
				switch (s->getType()) {
					case IPMISensorBase::sensorType::xccDatastorePower: {
						std::vector<reading_t> readings;
						LenovoXCC xcc(_entity);
						if (_entity->getXCC()->getDatastorePower(readings) == 0) {
							for (unsigned int i=0; i<readings.size(); i++) {
123
								s->storeReading(readings[i]);
124
125
							}
							reading = readings.back();
126
						}
127
						break;
128
					}
129
130
					case IPMISensorBase::sensorType::xccSingleEnergy: {
						if (_entity->getXCC()->getSingleEnergy(reading) == 0) {
131
							s->storeReading(reading);
132
133
						}
						break;
Michael Ott's avatar
Michael Ott committed
134
					}
135
136
137
138
					case IPMISensorBase::sensorType::xccBulkPower: {
						std::vector<reading_t> readings;
						if (_entity->getXCC()->getBulkPower(readings) == 0) {
							for (unsigned int i=0; i<readings.size(); i++) {
139
								s->storeReading(readings[i]);
140
141
							}
							reading = readings.back();
142
						}
143
						break;
144
					}
145
146
147
148
					case IPMISensorBase::sensorType::xccBulkEnergy: {
						std::vector<reading_t> readings;
						if (_entity->getXCC()->getBulkEnergy(readings) == 0) {
							for (unsigned int i=0; i<readings.size(); i++) {
149
								s->storeReading(readings[i]);
150
151
							}
							reading = readings.back();
152
						}
153
						break;
154
					}
155
156
157
158
159
160
161
					case IPMISensorBase::sensorType::sdr: {
						std::vector<uint8_t> sdrRecord = s->getSdrRecord();
						if (sdrRecord.size() == 0) {
							_entity->getSdrRecord(s->getRecordId(), sdrRecord);
							s->setSdrRecord(sdrRecord);
						}
						reading.value = _entity->readSensorRecord(sdrRecord);
162
						s->storeReading(reading);
163
						break;
164
					}
165
166
					case IPMISensorBase::sensorType::raw: {
						reading.value = readRaw(s->getRawCmd(), s->getLsb(), s->getMsb());
167
						s->storeReading(reading);
168
169
170
171
172
						break;
					}
					default:
						LOG(error) << _groupName << "::" << s->getName() << " undefined sensor type";
						break;
173
				}
174
#ifdef DEBUG
175
				LOG(debug) << s->getName() << " reading: ts=" << prettyPrintTimestamp(reading.timestamp) << " val=" << reading.value;
176
#endif
177
178
179
180
			} catch (const std::exception &e) {
				LOG(error) << _entity->getName() << " " << e.what() << ": " << s->getName();
				continue;
			}
181
		}
182
		_entity->disconnect();
183
184
	}
}
185
186

uint64_t IPMISensorGroup::nextReadingTime() {
187
	if ((_sensors.size() == 1) && (_sensors.front()->getType() == IPMISensorBase::sensorType::xccDatastorePower)) {
188
		reading_t r = _sensors.front()->getLatestValue();
189
190
		uint64_t  now = getTimestamp();

191
192
193
194
195
196
197
198
199
200
201
202
203
204
		if (r.timestamp < now - S_TO_NS(35)) {
			// There was no reading yet or it is too old, so schedule next in 30s
			return now + S_TO_NS(30);
		} else {
			// The first reading of the next 30s block is 10ms after the last reading in the current block.
			// A block becomes available 30s after its first reading, adding 2s grace period
			return r.timestamp + MS_TO_NS(32010);
		}
	}
	return SensorGroupInterface::nextReadingTime();
}

bool IPMISensorGroup::checkConfig() {
	if (_sensors.size() > 1) {
205
		for (const auto &s : _sensors) {
206
			if (s->getType() == IPMISensorBase::sensorType::xccDatastorePower) {
207
208
				LOG(error) << _groupName << " contains an XCC sensor among others, this is not possible";
				return false;
209
210
211
212
213
214
215
216
			} 
		}
	}
	
	for (const auto &s : _sensors) {
		if (s->getType() == IPMISensorBase::sensorType::undefined) {
			LOG(error) << _groupName << "::" << s->getName() << " has an undefined sensor type";
			return false;
217
		}
218
219
220
221
222
223
		if (s->getType() == IPMISensorBase::sensorType::xccDatastorePower) {
			if (_queueSize < 3000) {
				LOG(info) << _groupName << "::" << s->getName() << " increasing queueSize to 3000 to store all data store readings (was " << _queueSize << ")";
				_queueSize = 3000;
			}
		}
224
225
226
	}
	return true;
}
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

void IPMISensorGroup::execOnInit() {
	for (const auto &s : _sensors) {
		switch(s->getType()) {
			case IPMISensorBase::sensorType::xccDatastorePower:
			case IPMISensorBase::sensorType::xccSingleEnergy:
			case IPMISensorBase::sensorType::xccBulkPower:
			case IPMISensorBase::sensorType::xccBulkEnergy:
				if (_entity->getXCC() == nullptr) {
					_entity->setXCC(new LenovoXCC(_entity));
				}
				break;
			default:
				break;
		}
	}
}