]> git.cworth.org Git - apitrace/blob - retrace/retrace_main.cpp
Improved GPU profiling code.
[apitrace] / retrace / retrace_main.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
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 <string.h>
28 #include <iostream>
29
30 #include "os_binary.hpp"
31 #include "os_time.hpp"
32 #include "image.hpp"
33 #include "trace_callset.hpp"
34 #include "trace_dump.hpp"
35 #include "retrace.hpp"
36
37
38 static bool waitOnFinish = false;
39
40 static const char *comparePrefix = NULL;
41 static const char *snapshotPrefix = NULL;
42 static trace::CallSet snapshotFrequency;
43 static trace::CallSet compareFrequency;
44
45 static unsigned dumpStateCallNo = ~0;
46
47
48 namespace retrace {
49
50
51 trace::Parser parser;
52 trace::Profiler profiler;
53
54
55 int verbosity = 0;
56 bool debug = true;
57 bool profiling = false;
58 bool profileGPU = false;
59 bool dumpingState = false;
60
61
62 bool doubleBuffer = true;
63 bool coreProfile = false;
64
65
66 unsigned frameNo = 0;
67
68
69 void
70 frameComplete(trace::Call &call) {
71     ++frameNo;
72 }
73
74
75 static void
76 takeSnapshot(unsigned call_no) {
77     assert(snapshotPrefix || comparePrefix);
78
79     image::Image *ref = NULL;
80
81     if (comparePrefix) {
82         os::String filename = os::String::format("%s%010u.png", comparePrefix, call_no);
83         ref = image::readPNG(filename);
84         if (!ref) {
85             return;
86         }
87         if (retrace::verbosity >= 0) {
88             std::cout << "Read " << filename << "\n";
89         }
90     }
91
92     image::Image *src = getSnapshot();
93     if (!src) {
94         return;
95     }
96
97     if (snapshotPrefix) {
98         if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) {
99             char comment[21];
100             snprintf(comment, sizeof comment, "%u", call_no);
101             src->writePNM(std::cout, comment);
102         } else {
103             os::String filename = os::String::format("%s%010u.png", snapshotPrefix, call_no);
104             if (src->writePNG(filename) && retrace::verbosity >= 0) {
105                 std::cout << "Wrote " << filename << "\n";
106             }
107         }
108     }
109
110     if (ref) {
111         std::cout << "Snapshot " << call_no << " average precision of " << src->compare(*ref) << " bits\n";
112         delete ref;
113     }
114
115     delete src;
116
117     return;
118 }
119
120
121 static void
122 mainLoop() {
123     retrace::Retracer retracer;
124
125     addCallbacks(retracer);
126
127     long long startTime = 0; 
128     frameNo = 0;
129
130     startTime = os::getTime();
131     trace::Call *call;
132
133     while ((call = retrace::parser.parse_call())) {
134         bool swapRenderTarget = call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET;
135         bool doSnapshot =
136             snapshotFrequency.contains(*call) ||
137             compareFrequency.contains(*call)
138         ;
139
140         // For calls which cause rendertargets to be swaped, we take the
141         // snapshot _before_ swapping the rendertargets.
142         if (doSnapshot && swapRenderTarget) {
143             if (call->flags & trace::CALL_FLAG_END_FRAME) {
144                 // For swapbuffers/presents we still use this call number,
145                 // spite not have been executed yet.
146                 takeSnapshot(call->no);
147             } else {
148                 // Whereas for ordinate fbo/rendertarget changes we use the
149                 // previous call's number.
150                 takeSnapshot(call->no - 1);
151             }
152         }
153
154         retracer.retrace(*call);
155
156         if (doSnapshot && !swapRenderTarget) {
157             takeSnapshot(call->no);
158         }
159
160         if (call->no >= dumpStateCallNo &&
161             dumpState(std::cout)) {
162             exit(0);
163         }
164
165         delete call;
166     }
167
168     // Reached the end of trace
169     flushRendering();
170
171     long long endTime = os::getTime();
172     float timeInterval = (endTime - startTime) * (1.0 / os::timeFrequency);
173
174     if ((retrace::verbosity >= -1) || (retrace::profiling) || (retrace::profileGPU)) {
175         std::cout << 
176             "Rendered " << frameNo << " frames"
177             " in " <<  timeInterval << " secs,"
178             " average of " << (frameNo/timeInterval) << " fps\n";
179     }
180
181     if (waitOnFinish) {
182         waitForInput();
183     } else {
184         return;
185     }
186 }
187
188
189 } /* namespace retrace */
190
191
192 static void
193 usage(const char *argv0) {
194     std::cout << 
195         "Usage: " << argv0 << " [OPTION] TRACE [...]\n"
196         "Replay TRACE.\n"
197         "\n"
198         "  -b           benchmark mode (no error checking or warning messages)\n"
199         "  -p           profiling mode (run whole trace, dump profiling info)\n"
200         "  -pgpu        gpu profiling mode (run whole trace, dump gpu profiling info)\n"
201         "  -c PREFIX    compare against snapshots\n"
202         "  -C CALLSET   calls to compare (default is every frame)\n"
203         "  -core        use core profile\n"
204         "  -db          use a double buffer visual (default)\n"
205         "  -sb          use a single buffer visual\n"
206         "  -s PREFIX    take snapshots; `-` for PNM stdout output\n"
207         "  -S CALLSET   calls to snapshot (default is every frame)\n"
208         "  -v           increase output verbosity\n"
209         "  -D CALLNO    dump state at specific call no\n"
210         "  -w           waitOnFinish on final frame\n";
211 }
212
213
214 extern "C"
215 int main(int argc, char **argv)
216 {
217     using namespace retrace;
218
219     assert(compareFrequency.empty());
220     assert(snapshotFrequency.empty());
221
222     int i;
223     for (i = 1; i < argc; ++i) {
224         const char *arg = argv[i];
225
226         if (arg[0] != '-') {
227             break;
228         }
229
230         if (!strcmp(arg, "--")) {
231             break;
232         } else if (!strcmp(arg, "-b")) {
233             retrace::debug = false;
234             retrace::verbosity = -1;
235         } else if (!strcmp(arg, "-p")) {
236             retrace::debug = false;
237             retrace::profiling = true;
238             retrace::verbosity = -1;
239         } else if (!strcmp(arg, "-pgpu")) {
240             retrace::profileGPU = true;
241
242             retrace::debug = false;
243             retrace::profiling = false;
244             retrace::verbosity = -1;
245         } else if (!strcmp(arg, "-c")) {
246             comparePrefix = argv[++i];
247             if (compareFrequency.empty()) {
248                 compareFrequency = trace::CallSet(trace::FREQUENCY_FRAME);
249             }
250         } else if (!strcmp(arg, "-C")) {
251             compareFrequency = trace::CallSet(argv[++i]);
252             if (comparePrefix == NULL) {
253                 comparePrefix = "";
254             }
255         } else if (!strcmp(arg, "-D")) {
256             dumpStateCallNo = atoi(argv[++i]);
257             dumpingState = true;
258             retrace::verbosity = -2;
259         } else if (!strcmp(arg, "-core")) {
260             retrace::coreProfile = true;
261         } else if (!strcmp(arg, "-db")) {
262             retrace::doubleBuffer = true;
263         } else if (!strcmp(arg, "-sb")) {
264             retrace::doubleBuffer = false;
265         } else if (!strcmp(arg, "--help")) {
266             usage(argv[0]);
267             return 0;
268         } else if (!strcmp(arg, "-s")) {
269             snapshotPrefix = argv[++i];
270             if (snapshotFrequency.empty()) {
271                 snapshotFrequency = trace::CallSet(trace::FREQUENCY_FRAME);
272             }
273             if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) {
274                 os::setBinaryMode(stdout);
275                 retrace::verbosity = -2;
276             }
277         } else if (!strcmp(arg, "-S")) {
278             snapshotFrequency = trace::CallSet(argv[++i]);
279             if (snapshotPrefix == NULL) {
280                 snapshotPrefix = "";
281             }
282         } else if (!strcmp(arg, "-v")) {
283             ++retrace::verbosity;
284         } else if (!strcmp(arg, "-w")) {
285             waitOnFinish = true;
286         } else {
287             std::cerr << "error: unknown option " << arg << "\n";
288             usage(argv[0]);
289             return 1;
290         }
291     }
292
293     retrace::setUp();
294
295     for ( ; i < argc; ++i) {
296         if (!retrace::parser.open(argv[i])) {
297             std::cerr << "error: failed to open " << argv[i] << "\n";
298             return 1;
299         }
300
301         retrace::mainLoop();
302
303         retrace::parser.close();
304     }
305
306     // XXX: X often hangs on XCloseDisplay
307     //retrace::cleanUp();
308
309     return 0;
310 }
311