Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit d5e7f10c authored by Michael Ott's avatar Michael Ott
Browse files

Fix drift for Lenovo XCC sensors

parent 38f55963
...@@ -88,6 +88,7 @@ uint64_t IPMISensorGroup::readRaw(const std::vector<uint8_t> &rawCmd, uint8_t ls ...@@ -88,6 +88,7 @@ uint64_t IPMISensorGroup::readRaw(const std::vector<uint8_t> &rawCmd, uint8_t ls
void IPMISensorGroup::read() { void IPMISensorGroup::read() {
reading_t reading; reading_t reading;
reading.value = 0;
reading.timestamp = getTimestamp(); reading.timestamp = getTimestamp();
//TODO with SensorGroup refactor we lost the ability to sleep until //TODO with SensorGroup refactor we lost the ability to sleep until
...@@ -108,7 +109,7 @@ void IPMISensorGroup::read() { ...@@ -108,7 +109,7 @@ void IPMISensorGroup::read() {
for (int i=0; i<readings.size(); i++) { for (int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor()); s->storeReading(readings[i], s->getFactor());
} }
reading = readings[2999]; reading = readings.back();
} }
break; break;
} }
...@@ -124,7 +125,7 @@ void IPMISensorGroup::read() { ...@@ -124,7 +125,7 @@ void IPMISensorGroup::read() {
for (unsigned int i=0; i<readings.size(); i++) { for (unsigned int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor()); s->storeReading(readings[i], s->getFactor());
} }
reading = readings[99]; reading = readings.back();
} }
break; break;
} }
...@@ -134,7 +135,7 @@ void IPMISensorGroup::read() { ...@@ -134,7 +135,7 @@ void IPMISensorGroup::read() {
for (unsigned int i=0; i<readings.size(); i++) { for (unsigned int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor()); s->storeReading(readings[i], s->getFactor());
} }
reading = readings[99]; reading = readings.back();
} }
break; break;
} }
...@@ -158,7 +159,7 @@ void IPMISensorGroup::read() { ...@@ -158,7 +159,7 @@ void IPMISensorGroup::read() {
break; break;
} }
#ifdef DEBUG #ifdef DEBUG
LOG(debug) << _groupName << "::" << s->getName() << " reading: ts=" << reading.timestamp << " val=" << reading.value; LOG(debug) << s->getName() << " reading: ts=" << prettyPrintTimestamp(reading.timestamp) << " val=" << reading.value;
#endif #endif
} catch (const std::exception &e) { } catch (const std::exception &e) {
LOG(error) << _groupName << "::" << s->getName() << " could not read value: " << e.what(); LOG(error) << _groupName << "::" << s->getName() << " could not read value: " << e.what();
......
...@@ -11,42 +11,35 @@ ...@@ -11,42 +11,35 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
void printbuf(std::string header, uint8_t *buf, int len) {
std::cout << header << " [" << len << "]" << std::hex;
for (int i = 0; i < len; i++) {
std::cout << " " << (int)buf[i];
}
std::cout << std::endl;
}
LenovoXCC::LenovoXCC(IPMIHost *host) { LenovoXCC::LenovoXCC(IPMIHost *host) {
_host = host; _host = host;
_handle = 0; _handle = 0;
_drift = 0; _generalDrift = 0;
_datastoreDrift = 0;
} }
LenovoXCC::~LenovoXCC() {} LenovoXCC::~LenovoXCC() {}
int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) { int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) {
if (openDatastore() == 0) { if (_datastoreDrift || getDatastoreDrift() == 0) {
uint64_t ts1, ts2; if (openDatastore() == 0) {
uint8_t buf[256]; uint64_t ts1, ts2;
ts2 = 0; uint8_t buf[256];
int i = 0;
if (_drift || getDrift() == 0) {
if ((ts1 = readDatastoreTimestamp()) > 0) { if ((ts1 = readDatastoreTimestamp()) > 0) {
ts2 = 0;
readings.resize(3000);
while (ts1 != ts2) { while (ts1 != ts2) {
int i = 0; i = 0;
for (int offset=16; offset < 6016; offset += 200) { for (int offset=16; offset < 6016; offset += 200) {
int len = readDatastoreRange(offset, 200, buf, sizeof(buf)); int len = readDatastoreRange(offset, 200, buf, sizeof(buf));
if (len >= 0) { if (len >= 0) {
uint16_t n = (buf[5] | buf[6] << 8) / 2; uint16_t n = (buf[5] | buf[6] << 8) / 2;
uint16_t *buf16 = (uint16_t *)&buf[7]; uint16_t *buf16 = (uint16_t *)&buf[7];
for (int j=0; j<n; j++) { for (int j=0; j<n; j++) {
reading_t r; readings[i].timestamp = ts1 + _datastoreDrift + MS_TO_NS(i * 10);
r.timestamp = ts1 + _drift + MS_TO_NS(i * 10); readings[i].value = buf16[j];
r.value = buf16[j];
readings.push_back(r);
i++; i++;
} }
} }
...@@ -55,21 +48,18 @@ int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) { ...@@ -55,21 +48,18 @@ int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) {
ts2 = readDatastoreTimestamp(); ts2 = readDatastoreTimestamp();
} }
} }
closeDatastore();
return i != 3000;
} }
closeDatastore();
}
if (readings.size() == 3000) {
return 0;
} else {
return 1;
} }
return 1;
} }
int LenovoXCC::getSingleEnergy(reading_t &reading) { int LenovoXCC::getSingleEnergy(reading_t &reading) {
if (_drift || getDrift() == 0) { if (_generalDrift || getGeneralDrift() == 0) {
uint64_t ts, energy; uint64_t ts, energy;
if (readSingleEnergyRaw(ts, energy) == 0) { if (readSingleEnergyRaw(ts, energy) == 0) {
reading.timestamp = ts + _drift; reading.timestamp = ts + _generalDrift;
reading.value = energy; reading.value = energy;
return 0; return 0;
} }
...@@ -78,10 +68,11 @@ int LenovoXCC::getSingleEnergy(reading_t &reading) { ...@@ -78,10 +68,11 @@ int LenovoXCC::getSingleEnergy(reading_t &reading) {
} }
int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) { int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
if (_drift || getDrift() == 0) { if (_generalDrift || getGeneralDrift() == 0) {
uint8_t buf[256]; uint8_t buf[256];
uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x00, 0x00, 0x00, 0x00}; uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x00, 0x00, 0x00, 0x00};
int len = -1; int len = -1;
try { try {
len = _host->sendRawCmd(getBulkCmd, sizeof(getBulkCmd), buf, sizeof(buf)); len = _host->sendRawCmd(getBulkCmd, sizeof(getBulkCmd), buf, sizeof(buf));
} catch (const std::exception &e) { } catch (const std::exception &e) {
...@@ -90,14 +81,14 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) { ...@@ -90,14 +81,14 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
} }
if ((len == 208) && (buf[0] == 0x32) && (buf[1] == 0x00)) { if ((len == 208) && (buf[0] == 0x32) && (buf[1] == 0x00)) {
uint64_t timeStamp = extractTimestamp(&buf[2]) + _drift; // The timestamp is the timestamp of the first reading, the last reading is 100*10ms later
uint64_t timeStamp = extractTimestamp(&buf[2]) + _generalDrift - MS_TO_NS(1000);
reading_t r = {0,0};
readings.resize(100, r); readings.resize(100);
uint16_t *buf16 = (uint16_t *)&buf[8]; uint16_t *buf16 = (uint16_t *)&buf[8];
for (int i=0; i<100; i++) { for (int i=0; i<100; i++) {
readings[i].timestamp = timeStamp + MS_TO_NS(i * 10); readings[i].timestamp = timeStamp + MS_TO_NS(i * 10);
readings[i].value = buf16[i]; readings[i].value = buf16[(99-i)]; // The order of readings is descending
} }
return 0; return 0;
} }
...@@ -107,7 +98,7 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) { ...@@ -107,7 +98,7 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
} }
int LenovoXCC::getBulkEnergy(std::vector<reading_t> &readings) { int LenovoXCC::getBulkEnergy(std::vector<reading_t> &readings) {
if (_drift || getDrift() == 0) { if (_generalDrift || getGeneralDrift() == 0) {
uint8_t buf[256]; uint8_t buf[256];
uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x01, 0x00, 0x00, 0x00}; uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x01, 0x00, 0x00, 0x00};
int len = -1; int len = -1;
...@@ -119,20 +110,20 @@ int LenovoXCC::getBulkEnergy(std::vector<reading_t> &readings) { ...@@ -119,20 +110,20 @@ int LenovoXCC::getBulkEnergy(std::vector<reading_t> &readings) {
} }
if ((len == 212) && (buf[0] == 0x32) && (buf[1] == 0x00)) { if ((len == 212) && (buf[0] == 0x32) && (buf[1] == 0x00)) {
uint64_t timeStamp = extractTimestamp(&buf[2]) + _drift; // The timestamp is the timestamp of the first reading, the last reading is 101*10ms later
uint64_t timeStamp = extractTimestamp(&buf[2]) + _generalDrift - MS_TO_NS(1010);
uint32_t baseEnergy; uint32_t baseEnergy;
memcpy(&baseEnergy, &buf[8], sizeof(baseEnergy)); memcpy(&baseEnergy, &buf[8], sizeof(baseEnergy));
reading_t r = {0,0}; readings.resize(101); // This is really 101!
readings.resize(101, r); // This is really 101!
readings[0].timestamp = timeStamp; readings[0].timestamp = timeStamp;
readings[0].value = baseEnergy; readings[0].value = baseEnergy;
uint16_t *buf16 = (uint16_t *)&buf[12]; uint16_t *buf16 = (uint16_t *)&buf[12];
for (int i=1; i<101; i++) { for (int i=1; i<101; i++) {
readings[i].timestamp = timeStamp + MS_TO_NS(i * 10); readings[i].timestamp = timeStamp + MS_TO_NS(i * 10);
readings[i].value = baseEnergy + buf16[i-1]; readings[i].value = baseEnergy + buf16[i-1] ;
} }
return 0; return 0;
} }
...@@ -182,19 +173,6 @@ int LenovoXCC::readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy) { ...@@ -182,19 +173,6 @@ int LenovoXCC::readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy) {
return -1; return -1;
} }
int LenovoXCC::getDrift() {
uint64_t xccTs, dummy;
uint64_t sysTs1 = getTimestamp();
if (readSingleEnergyRaw(xccTs, dummy) == 0) {
uint64_t sysTs2 = getTimestamp();
_drift = sysTs1 + (sysTs2 - sysTs1) / 2 - xccTs;
return 0;
}
return 1;
}
int LenovoXCC::openDatastore() { int LenovoXCC::openDatastore() {
if (_handle) { if (_handle) {
closeDatastore(); closeDatastore();
...@@ -210,7 +188,6 @@ int LenovoXCC::openDatastore() { ...@@ -210,7 +188,6 @@ int LenovoXCC::openDatastore() {
return 255; return 255;
} }
//printbuf("open", buf, len);
if ((len == 9) && (buf[0] == 0x90) && (buf[1] == 0x00)) { if ((len == 9) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
memcpy(&_handle, &buf[5], sizeof(_handle)); memcpy(&_handle, &buf[5], sizeof(_handle));
return 0; return 0;
...@@ -236,7 +213,6 @@ int LenovoXCC::closeDatastore() { ...@@ -236,7 +213,6 @@ int LenovoXCC::closeDatastore() {
return 255; return 255;
} }
//printbuf("close", buf, len);
if ((len == 5) && (buf[0] == 0x90) && (buf[1] == 0x00)) { if ((len == 5) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
_handle = 0; _handle = 0;
return 0; return 0;
...@@ -259,7 +235,6 @@ int LenovoXCC::readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf, ...@@ -259,7 +235,6 @@ int LenovoXCC::readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf,
} }
if ((len >= 2) && (buf[0] == 0x90) && (buf[1] == 0x00)) { if ((len >= 2) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
//printbuf("readDataStoreRange", buf, len);
return len; return len;
} else { } else {
return -1; return -1;
...@@ -284,3 +259,46 @@ uint64_t LenovoXCC::readDatastoreTimestamp() { ...@@ -284,3 +259,46 @@ uint64_t LenovoXCC::readDatastoreTimestamp() {
return 0; return 0;
} }
} }
int LenovoXCC::getDatastoreDrift() {
if ((_handle != 0) || (openDatastore() == 0)) {
uint64_t dsTs1, dsTs2, sysTs1, sysTs2;
dsTs1 = dsTs2 = readDatastoreTimestamp();
// Loop until the timestamp changes so we can be sure it's not outdated
do {
usleep(5000);
sysTs1 = getTimestamp();
dsTs2 = readDatastoreTimestamp();
sysTs2 = getTimestamp();
} while (dsTs1 == dsTs2);
// The timestamp is the timestamp of the first reading, the last reading is 30s later
_datastoreDrift = sysTs1 - (sysTs2 - sysTs1) / 2 - dsTs2 - S_TO_NS(30);
closeDatastore();
#ifdef DEBUG
LOGGER lg;
LOG(debug) << " Datastore drift: " << prettyPrintTimestamp(_datastoreDrift) << " (" << (sysTs2 - sysTs1) << ")" << std::endl;
#endif
return 0;
}
return 1;
}
int LenovoXCC::getGeneralDrift() {
uint64_t xccTs, dummy;
// Do a dummy read to make sure we have the IPMI connection open in order to minimize latency
readSingleEnergyRaw(xccTs, dummy);
uint64_t sysTs1 = getTimestamp();
if (readSingleEnergyRaw(xccTs, dummy) == 0) {
uint64_t sysTs2 = getTimestamp();
_generalDrift = sysTs1 - (sysTs2 - sysTs1) / 2 - xccTs;
#ifdef DEBUG
LOGGER lg;
LOG(debug) << "General drift: " << prettyPrintTimestamp(_generalDrift) << " (" << (sysTs2 - sysTs1) << ")" << std::endl;
#endif
return 0;
}
return 1;
}
...@@ -24,17 +24,23 @@ class LenovoXCC { ...@@ -24,17 +24,23 @@ class LenovoXCC {
int getBulkPower(std::vector<reading_t> &readings); int getBulkPower(std::vector<reading_t> &readings);
int getBulkEnergy(std::vector<reading_t> &readings); int getBulkEnergy(std::vector<reading_t> &readings);
int getGeneralDrift();
int getDatastoreDrift();
private: private:
uint64_t extractTimestamp(const uint8_t *buf); uint64_t extractTimestamp(const uint8_t *buf);
int readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy); int readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy);
int getDrift(); // int getGeneralDrift();
int openDatastore(); int openDatastore();
int closeDatastore(); int closeDatastore();
uint64_t readDatastoreTimestamp(); uint64_t readDatastoreTimestamp();
int readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf, uint16_t bufLen); int readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf, uint16_t bufLen);
// int getDatastoreDrift();
IPMIHost *_host; IPMIHost *_host;
uint32_t _handle; uint32_t _handle;
int64_t _drift; int64_t _generalDrift;
int64_t _datastoreDrift;
}; };
#endif /* LenovoXCC_hpp */ #endif /* LenovoXCC_hpp */
Markdown is supported
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