blob: 5deb0f375f3a4c937789b9bf0741ea96499bebb4 [file] [log] [blame]
/**
* Copyright (C) ARM Limited 2013-2014. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
// Define to get format macros from inttypes.h
#define __STDC_FORMAT_MACROS
#include "DiskIODriver.h"
#include <inttypes.h>
#include "Logging.h"
#include "SessionData.h"
class DiskIOCounter : public DriverCounter {
public:
DiskIOCounter(DriverCounter *next, char *const name, int64_t *const value);
~DiskIOCounter();
int64_t read();
private:
int64_t *const mValue;
int64_t mPrev;
// Intentionally unimplemented
DiskIOCounter(const DiskIOCounter &);
DiskIOCounter &operator=(const DiskIOCounter &);
};
DiskIOCounter::DiskIOCounter(DriverCounter *next, char *const name, int64_t *const value) : DriverCounter(next, name), mValue(value), mPrev(0) {
}
DiskIOCounter::~DiskIOCounter() {
}
int64_t DiskIOCounter::read() {
int64_t result = *mValue - mPrev;
mPrev = *mValue;
// Kernel assumes a sector is 512 bytes
return result << 9;
}
DiskIODriver::DiskIODriver() : mBuf(), mReadBytes(0), mWriteBytes(0) {
}
DiskIODriver::~DiskIODriver() {
}
void DiskIODriver::readEvents(mxml_node_t *const) {
// Only for use with perf
if (!gSessionData->perf.isSetup()) {
return;
}
setCounters(new DiskIOCounter(getCounters(), strdup("Linux_block_rq_rd"), &mReadBytes));
setCounters(new DiskIOCounter(getCounters(), strdup("Linux_block_rq_wr"), &mWriteBytes));
}
void DiskIODriver::doRead() {
if (!countersEnabled()) {
return;
}
if (!mBuf.read("/proc/diskstats")) {
logg->logError(__FILE__, __LINE__, "Unable to read /proc/diskstats");
handleException();
}
mReadBytes = 0;
mWriteBytes = 0;
char *lastName = NULL;
int lastNameLen = -1;
char *start = mBuf.getBuf();
while (*start != '\0') {
char *end = strchr(start, '\n');
if (end != NULL) {
*end = '\0';
}
int nameStart = -1;
int nameEnd = -1;
int64_t readBytes = -1;
int64_t writeBytes = -1;
const int count = sscanf(start, "%*d %*d %n%*s%n %*u %*u %" SCNu64 " %*u %*u %*u %" SCNu64, &nameStart, &nameEnd, &readBytes, &writeBytes);
if (count != 2) {
logg->logError(__FILE__, __LINE__, "Unable to parse /proc/diskstats");
handleException();
}
// Skip partitions which are identified if the name is a substring of the last non-partition
if ((lastName == NULL) || (strncmp(lastName, start + nameStart, lastNameLen) != 0)) {
lastName = start + nameStart;
lastNameLen = nameEnd - nameStart;
mReadBytes += readBytes;
mWriteBytes += writeBytes;
}
if (end == NULL) {
break;
}
start = end + 1;
}
}
void DiskIODriver::start() {
doRead();
// Initialize previous values
for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
if (!counter->isEnabled()) {
continue;
}
counter->read();
}
}
void DiskIODriver::read(Buffer *const buffer) {
doRead();
super::read(buffer);
}