1 /**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
9 #include <string.h>
10 #include <stdlib.h>
11 #include <dirent.h>
12 #include "ConfigurationXML.h"
13 #include "Driver.h"
14 #include "Logging.h"
15 #include "OlyUtility.h"
16 #include "SessionData.h"
18 static const char* ATTR_COUNTER = "counter";
19 static const char* ATTR_REVISION = "revision";
20 static const char* ATTR_TITLE = "title";
21 static const char* ATTR_NAME = "name";
22 static const char* ATTR_EVENT = "event";
23 static const char* ATTR_COUNT = "count";
24 static const char* ATTR_PER_CPU = "per_cpu";
25 static const char* ATTR_DESCRIPTION = "description";
26 static const char* ATTR_EBS = "supports_event_based_sampling";
27 static const char* ATTR_DISPLAY = "display";
28 static const char* ATTR_UNITS = "units";
29 static const char* ATTR_MODIFIER = "modifier";
30 static const char* ATTR_AVERAGE_SELECTION = "average_selection";
32 ConfigurationXML::ConfigurationXML() {
33 const char * configuration_xml;
34 unsigned int configuration_xml_len;
35 getDefaultConfigurationXml(configuration_xml, configuration_xml_len);
37 char path[PATH_MAX];
39 if (gSessionData->mConfigurationXMLPath) {
40 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX);
41 } else {
42 if (util->getApplicationFullPath(path, PATH_MAX) != 0) {
43 logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
44 }
45 strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1);
46 }
47 mConfigurationXML = util->readFromDisk(path);
49 for (int retryCount = 0; retryCount < 2; ++retryCount) {
50 if (mConfigurationXML == NULL) {
51 logg->logMessage("Unable to locate configuration.xml, using default in binary");
52 // null-terminate configuration_xml
53 mConfigurationXML = (char*)malloc(configuration_xml_len + 1);
54 memcpy(mConfigurationXML, (const void*)configuration_xml, configuration_xml_len);
55 mConfigurationXML[configuration_xml_len] = 0;
56 }
58 int ret = parse(mConfigurationXML);
59 if (ret == 1) {
60 // remove configuration.xml on disk to use the default
61 if (remove(path) != 0) {
62 logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
63 handleException();
64 }
65 logg->logMessage("Invalid configuration.xml file detected and removed");
67 // Free the current configuration and reload
68 free((void*)mConfigurationXML);
69 mConfigurationXML = NULL;
70 continue;
71 }
73 break;
74 }
76 validate();
77 }
79 ConfigurationXML::~ConfigurationXML() {
80 if (mConfigurationXML) {
81 free((void*)mConfigurationXML);
82 }
83 }
85 int ConfigurationXML::parse(const char* configurationXML) {
86 mxml_node_t *tree, *node;
87 int ret;
89 // clear counter overflow
90 gSessionData->mCounterOverflow = false;
91 mIndex = 0;
93 // disable all counters prior to parsing the configuration xml
94 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
95 gSessionData->mCounters[i].setEnabled(false);
96 }
98 tree = mxmlLoadString(NULL, configurationXML, MXML_NO_CALLBACK);
100 node = mxmlGetFirstChild(tree);
101 while (node && mxmlGetType(node) != MXML_ELEMENT)
102 node = mxmlWalkNext(node, tree, MXML_NO_DESCEND);
104 ret = configurationsTag(node);
106 node = mxmlGetFirstChild(node);
107 while (node) {
108 if (mxmlGetType(node) != MXML_ELEMENT) {
109 node = mxmlWalkNext(node, tree, MXML_NO_DESCEND);
110 continue;
111 }
112 configurationTag(node);
113 node = mxmlWalkNext(node, tree, MXML_NO_DESCEND);
114 }
116 mxmlDelete(tree);
118 return ret;
119 }
121 void ConfigurationXML::validate(void) {
122 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
123 const Counter & counter = gSessionData->mCounters[i];
124 if (counter.isEnabled()) {
125 if (strcmp(counter.getType(), "") == 0) {
126 logg->logError(__FILE__, __LINE__, "Invalid required attribute in configuration.xml:\n counter=\"%s\"\n title=\"%s\"\n name=\"%s\"\n event=%d\n", counter.getType(), counter.getTitle(), counter.getName(), counter.getEvent());
127 handleException();
128 }
130 // iterate through the remaining enabled performance counters
131 for (int j = i + 1; j < MAX_PERFORMANCE_COUNTERS; j++) {
132 const Counter & counter2 = gSessionData->mCounters[j];
133 if (counter2.isEnabled()) {
134 // check if the types are the same
135 if (strcmp(counter.getType(), counter2.getType()) == 0) {
136 logg->logError(__FILE__, __LINE__, "Duplicate performance counter type in configuration.xml: %s", counter.getType());
137 handleException();
138 }
139 }
140 }
141 }
142 }
143 }
145 #define CONFIGURATION_REVISION 2
146 int ConfigurationXML::configurationsTag(mxml_node_t *node) {
147 const char* revision_string;
149 revision_string = mxmlElementGetAttr(node, ATTR_REVISION);
150 if (!revision_string) {
151 return 1; //revision issue;
152 }
154 int revision = strtol(revision_string, NULL, 10);
155 if (revision < CONFIGURATION_REVISION) {
156 return 1; // revision issue
157 }
159 return 0;
160 }
162 void ConfigurationXML::configurationTag(mxml_node_t *node) {
163 // handle all other performance counters
164 if (mIndex >= MAX_PERFORMANCE_COUNTERS) {
165 gSessionData->mCounterOverflow = true;
166 return;
167 }
169 // read attributes
170 Counter & counter = gSessionData->mCounters[mIndex];
171 counter.clear();
172 if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER));
173 if (mxmlElementGetAttr(node, ATTR_TITLE)) counter.setTitle(mxmlElementGetAttr(node, ATTR_TITLE));
174 if (mxmlElementGetAttr(node, ATTR_NAME)) counter.setName(mxmlElementGetAttr(node, ATTR_NAME));
175 if (mxmlElementGetAttr(node, ATTR_DESCRIPTION)) counter.setDescription(mxmlElementGetAttr(node, ATTR_DESCRIPTION));
176 if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16));
177 if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10));
178 if (mxmlElementGetAttr(node, ATTR_PER_CPU)) counter.setPerCPU(util->stringToBool(mxmlElementGetAttr(node, ATTR_PER_CPU), false));
179 if (mxmlElementGetAttr(node, ATTR_EBS)) counter.setEBSCapable(util->stringToBool(mxmlElementGetAttr(node, ATTR_EBS), false));
180 if (mxmlElementGetAttr(node, ATTR_DISPLAY)) counter.setDisplay(mxmlElementGetAttr(node, ATTR_DISPLAY));
181 if (mxmlElementGetAttr(node, ATTR_UNITS)) counter.setUnits(mxmlElementGetAttr(node, ATTR_UNITS));
182 if (mxmlElementGetAttr(node, ATTR_MODIFIER)) counter.setModifier(strtol(mxmlElementGetAttr(node, ATTR_MODIFIER), NULL, 10));
183 if (mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION)) counter.setAverageSelection(util->stringToBool(mxmlElementGetAttr(node, ATTR_AVERAGE_SELECTION), false));
184 counter.setEnabled(true);
186 // Associate a driver with each counter
187 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
188 if (driver->claimCounter(counter)) {
189 if (counter.getDriver() != NULL) {
190 logg->logError(__FILE__, __LINE__, "More than one driver has claimed %s: %s", counter.getTitle(), counter.getName());
191 handleException();
192 }
193 counter.setDriver(driver);
194 }
195 }
197 // If no driver is associated with the counter, disable it
198 if (counter.getDriver() == NULL) {
199 logg->logMessage("No driver has claimed %s (%s: %s)", counter.getType(), counter.getTitle(), counter.getName());
200 counter.setEnabled(false);
201 }
203 // update counter index
204 mIndex++;
205 }
207 void ConfigurationXML::getDefaultConfigurationXml(const char * & xml, unsigned int & len) {
208 #include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len
209 xml = (const char *)configuration_xml;
210 len = configuration_xml_len;
211 }