/** * 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 #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); }