]> git.cworth.org Git - apitrace/blob - common/trace_callset.cpp
Use skiplist-based FastCallSet within trace::CallSet
[apitrace] / common / trace_callset.cpp
1 /**************************************************************************
2  *
3  * Copyright 2012 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <assert.h>
28 #include <stdlib.h>
29
30 #include <limits>
31 #include <fstream>
32 #include <iostream>
33 #include <string>
34
35 #include <trace_callset.hpp>
36
37 using namespace trace;
38
39
40 // Parser class for call sets
41 class CallSetParser
42 {
43     CallSet &set;
44
45 protected:
46     char lookahead;
47
48     CallSetParser(CallSet &_set) :
49         set(_set),
50         lookahead(0)
51     {}
52
53 public:
54     void parse() {
55         skipWhiteSpace();
56         while (lookahead) {
57             assert(!isSpace());
58             parseRange();
59             // skip any comma
60             isOperator(',');
61         }
62     }
63
64 private:
65     void parseRange() {
66         CallNo start = std::numeric_limits<CallNo>::min();
67         CallNo stop = std::numeric_limits<CallNo>::max();
68         CallNo step = 1;
69         CallFlags freq = FREQUENCY_ALL;
70         if (isAlpha()) {
71             freq = parseFrequency();
72         } else {
73             if (isOperator('*')) {
74                 // no-change
75             } else {
76                 start = parseCallNo();
77                 if (isOperator('-')) {
78                     if (isDigit()) {
79                         stop = parseCallNo();
80                     } else {
81                         // no-change
82                     }
83                 } else {
84                     stop = start;
85                 }
86             }
87             if (isOperator('/')) {
88                 if (isDigit()) {
89                     step = parseCallNo();
90                 } else {
91                     freq = parseFrequency();
92                 }
93             }
94         }
95         set.addRange(CallRange(start, stop, step, freq));
96     }
97
98     // match and consume an operator
99     bool isOperator(char c) {
100         if (lookahead == c) {
101             consume();
102             skipWhiteSpace();
103             return true;
104         } else {
105             return false;
106         }
107     }
108
109     CallNo parseCallNo() {
110         CallNo number = 0;
111         if (isDigit()) {
112             do {
113                 CallNo digit = consume() - '0';
114                 number = number * 10 + digit;
115             } while (isDigit());
116         } else {
117             std::cerr << "error: expected digit, found '" << lookahead << "'\n";
118             exit(0);
119         }
120         skipWhiteSpace();
121         return number;
122     }
123
124     CallFlags parseFrequency() {
125         std::string freq;
126         if (isAlpha()) {
127             do {
128                 freq.push_back(consume());
129             } while (isAlpha());
130         } else {
131             std::cerr << "error: expected frequency, found '" << lookahead << "'\n";
132             exit(0);
133         }
134         skipWhiteSpace();
135         if (freq == "frame") {
136             return FREQUENCY_FRAME;
137         } else if (freq == "rendertarget" || freq == "fbo") {
138             return FREQUENCY_RENDERTARGET;
139         } else if (freq == "render" || freq == "draw") {
140             return FREQUENCY_RENDER;
141         } else {
142             std::cerr << "error: expected frequency, found '" << freq << "'\n";
143             exit(0);
144             return FREQUENCY_NONE;
145         }
146     }
147
148     // match lookahead with a digit (does not consume)
149     bool isDigit() const {
150         return lookahead >= '0' && lookahead <= '9';
151     }
152
153     bool isAlpha() const {
154         return lookahead >= 'a' && lookahead <= 'z';
155     }
156
157     void skipWhiteSpace() {
158         while (isSpace()) {
159             consume();
160         }
161     }
162
163     bool isSpace() const {
164         return lookahead == ' ' ||
165                lookahead == '\t' ||
166                lookahead == '\r' ||
167                lookahead == '\n';
168     }
169
170     virtual char consume() = 0;
171 };
172
173
174 class StringCallSetParser : public CallSetParser
175 {
176     const char *buf;
177
178 public:
179     StringCallSetParser(CallSet &_set, const char *_buf) :
180         CallSetParser(_set),
181         buf(_buf)
182     {
183         lookahead = *buf;
184     }
185
186     char consume() {
187         char c = lookahead;
188         if (lookahead) {
189             ++buf;
190             lookahead = *buf;
191         }
192         return c;
193     }
194 };
195
196
197 class FileCallSetParser : public CallSetParser
198 {
199     std::ifstream stream;
200
201 public:
202     FileCallSetParser(CallSet &_set, const char *filename) :
203         CallSetParser(_set)
204     {
205         stream.open(filename);
206         if (!stream.is_open()) {
207             std::cerr << "error: failed to open \"" << filename << "\"\n";
208             exit(1);
209         }
210
211         stream.get(lookahead);
212     }
213
214     char consume() {
215         char c = lookahead;
216         if (stream.eof()) {
217             lookahead = 0;
218         } else {
219             stream.get(lookahead);
220         }
221         return c;
222     }
223 };
224
225
226 CallSet::CallSet(const char *string): limits(std::numeric_limits<CallNo>::min(), std::numeric_limits<CallNo>::max())
227 {
228     if (*string == '@') {
229         FileCallSetParser parser(*this, &string[1]);
230         parser.parse();
231     } else {
232         StringCallSetParser parser(*this, string);
233         parser.parse();
234     }
235 }
236
237
238 CallSet::CallSet(CallFlags freq): limits(std::numeric_limits<CallNo>::min(), std::numeric_limits<CallNo>::max()) {
239     if (freq != FREQUENCY_NONE) {
240         CallNo start = std::numeric_limits<CallNo>::min();
241         CallNo stop = std::numeric_limits<CallNo>::max();
242         CallNo step = 1;
243         addRange(CallRange(start, stop, step, freq));
244         assert(!empty());
245     }
246 }