gator: Version 5.21.1

Signed-off-by: Drew Richardson <drew.richardson@arm.com>
Signed-off-by: Jon Medhurst <tixy@linaro.org>
diff --git a/tools/gator/daemon/FtraceDriver.cpp b/tools/gator/daemon/FtraceDriver.cpp
index b156f1c..98bd0a5 100644
--- a/tools/gator/daemon/FtraceDriver.cpp
+++ b/tools/gator/daemon/FtraceDriver.cpp
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. 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
@@ -9,56 +9,80 @@
 #include "FtraceDriver.h"
 
 #include <regex.h>
+#include <unistd.h>
 
+#include "DriverSource.h"
 #include "Logging.h"
+#include "Setup.h"
 
 class FtraceCounter : public DriverCounter {
 public:
-	FtraceCounter(DriverCounter *next, char *name, const char *regex);
+	FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable);
 	~FtraceCounter();
 
+	void prepare();
 	int read(const char *const line, int64_t *values);
+	void stop();
 
 private:
-	regex_t reg;
+	regex_t mReg;
+	char *const mEnable;
+	int mWasEnabled;
 
 	// Intentionally unimplemented
 	FtraceCounter(const FtraceCounter &);
 	FtraceCounter &operator=(const FtraceCounter &);
 };
 
-FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex) : DriverCounter(next, name) {
-	int result = regcomp(&reg, regex, REG_EXTENDED);
+FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
+	int result = regcomp(&mReg, regex, REG_EXTENDED);
 	if (result != 0) {
 		char buf[128];
-		regerror(result, &reg, buf, sizeof(buf));
-		logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf);
+		regerror(result, &mReg, buf, sizeof(buf));
+		logg->logError("Invalid regex '%s': %s", regex, buf);
 		handleException();
 	}
 }
 
 FtraceCounter::~FtraceCounter() {
-	regfree(&reg);
+	regfree(&mReg);
+	if (mEnable != NULL) {
+		free(mEnable);
+	}
+}
+
+void FtraceCounter::prepare() {
+	if (mEnable == NULL) {
+		return;
+	}
+
+	char buf[1<<10];
+	snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+	if ((DriverSource::readIntDriver(buf, &mWasEnabled) != 0) ||
+			(DriverSource::writeDriver(buf, 1) != 0)) {
+		logg->logError("Unable to read or write to %s", buf);
+		handleException();
+	}
 }
 
 int FtraceCounter::read(const char *const line, int64_t *values) {
 	regmatch_t match[2];
-	int result = regexec(&reg, line, 2, match, 0);
+	int result = regexec(&mReg, line, 2, match, 0);
 	if (result != 0) {
 		// No match
 		return 0;
 	}
 
+	int64_t value;
 	if (match[1].rm_so < 0) {
-		logg->logError(__FILE__, __LINE__, "Parsing %s failed", getName());
-		handleException();
-	}
-
-	errno = 0;
-	int64_t value = strtoll(line + match[1].rm_so, NULL, 0);
-	if (errno != 0) {
-		logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", getName(), strerror(errno));
-		handleException();
+		value = 1;
+	} else {
+		errno = 0;
+		value = strtoll(line + match[1].rm_so, NULL, 0);
+		if (errno != 0) {
+			logg->logError("Parsing %s failed: %s", getName(), strerror(errno));
+			handleException();
+		}
 	}
 
 	values[0] = getKey();
@@ -67,6 +91,16 @@
 	return 1;
 }
 
+void FtraceCounter::stop() {
+	if (mEnable == NULL) {
+		return;
+	}
+
+	char buf[1<<10];
+	snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+	DriverSource::writeDriver(buf, mWasEnabled);
+}
+
 FtraceDriver::FtraceDriver() : mValues(NULL) {
 }
 
@@ -75,6 +109,19 @@
 }
 
 void FtraceDriver::readEvents(mxml_node_t *const xml) {
+	// Check the kernel version
+	int release[3];
+	if (!getLinuxVersion(release)) {
+		logg->logError("getLinuxVersion failed");
+		handleException();
+	}
+
+	// The perf clock was added in 3.10
+	if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 10, 0)) {
+		logg->logMessage("Unsupported kernel version, to use ftrace please upgrade to Linux 3.10 or later");
+		return;
+	}
+
 	mxml_node_t *node = xml;
 	int count = 0;
 	while (true) {
@@ -93,16 +140,37 @@
 
 		const char *regex = mxmlElementGetAttr(node, "regex");
 		if (regex == NULL) {
-			logg->logError(__FILE__, __LINE__, "The regex counter %s is missing the required regex attribute", counter);
+			logg->logError("The regex counter %s is missing the required regex attribute", counter);
 			handleException();
 		}
-		setCounters(new FtraceCounter(getCounters(), strdup(counter), regex));
-		++count;
+		bool addCounter = true;
+		const char *enable = mxmlElementGetAttr(node, "enable");
+		if (enable != NULL) {
+			char buf[1<<10];
+			snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", enable);
+			if (access(buf, W_OK) != 0) {
+				logg->logMessage("Disabling counter %s, %s not found", counter, buf);
+				addCounter = false;
+			}
+		}
+		if (addCounter) {
+			setCounters(new FtraceCounter(getCounters(), strdup(counter), regex, enable));
+			++count;
+		}
 	}
 
 	mValues = new int64_t[2*count];
 }
 
+void FtraceDriver::prepare() {
+	for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
+		if (!counter->isEnabled()) {
+			continue;
+		}
+		counter->prepare();
+	}
+}
+
 int FtraceDriver::read(const char *line, int64_t **buf) {
 	int count = 0;
 
@@ -116,3 +184,12 @@
 	*buf = mValues;
 	return count;
 }
+
+void FtraceDriver::stop() {
+	for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
+		if (!counter->isEnabled()) {
+			continue;
+		}
+		counter->stop();
+	}
+}