aboutsummaryrefslogtreecommitdiff
path: root/daemon/FtraceDriver.cpp
blob: b156f1c0b8b46f1341477071f7b47106f669fbff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
 * Copyright (C) ARM Limited 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.
 */

#include "FtraceDriver.h"

#include <regex.h>

#include "Logging.h"

class FtraceCounter : public DriverCounter {
public:
	FtraceCounter(DriverCounter *next, char *name, const char *regex);
	~FtraceCounter();

	int read(const char *const line, int64_t *values);

private:
	regex_t reg;

	// 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);
	if (result != 0) {
		char buf[128];
		regerror(result, &reg, buf, sizeof(buf));
		logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf);
		handleException();
	}
}

FtraceCounter::~FtraceCounter() {
	regfree(&reg);
}

int FtraceCounter::read(const char *const line, int64_t *values) {
	regmatch_t match[2];
	int result = regexec(&reg, line, 2, match, 0);
	if (result != 0) {
		// No match
		return 0;
	}

	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();
	}

	values[0] = getKey();
	values[1] = value;

	return 1;
}

FtraceDriver::FtraceDriver() : mValues(NULL) {
}

FtraceDriver::~FtraceDriver() {
	delete [] mValues;
}

void FtraceDriver::readEvents(mxml_node_t *const xml) {
	mxml_node_t *node = xml;
	int count = 0;
	while (true) {
		node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
		if (node == NULL) {
			break;
		}
		const char *counter = mxmlElementGetAttr(node, "counter");
		if (counter == NULL) {
			continue;
		}

		if (strncmp(counter, "ftrace_", 7) != 0) {
			continue;
		}

		const char *regex = mxmlElementGetAttr(node, "regex");
		if (regex == NULL) {
			logg->logError(__FILE__, __LINE__, "The regex counter %s is missing the required regex attribute", counter);
			handleException();
		}
		setCounters(new FtraceCounter(getCounters(), strdup(counter), regex));
		++count;
	}

	mValues = new int64_t[2*count];
}

int FtraceDriver::read(const char *line, int64_t **buf) {
	int count = 0;

	for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
		if (!counter->isEnabled()) {
			continue;
		}
		count += counter->read(line, mValues + 2*count);
	}

	*buf = mValues;
	return count;
}