root/OpenSceneGraph/trunk/examples/osguserstats/osguserstats.cpp @ 11931

Revision 11931, 14.9 kB (checked in by robert, 4 years ago)

Fixed typo of commercial

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield
2 *
3 * This application is open source and may be redistributed and/or modified
4 * freely and without restriction, both in commercial and non commercial applications,
5 * as long as this copyright notice is maintained.
6 *
7 * This application is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10*/
11
12#include <osgDB/ReadFile>
13#include <osgUtil/Optimizer>
14
15#include <osgViewer/Viewer>
16#include <osgViewer/ViewerEventHandlers>
17
18#include <osgGA/TrackballManipulator>
19#include <osgGA/StateSetManipulator>
20
21#include <iostream>
22
23
24// The idea of user stats is that you record times or values in the viewer's
25// stats, and you also tell the stats handler to watch those values each
26// frame. The stats handler can display the stats in three ways:
27//  - A numeric time beside the stat name
28//    Requires that an elapsed time be recorded in the viewer's stats for the
29//    "timeTakenName".
30//  - A bar in the top bar graph
31//    Requires that two times (relative to the viewer's start tick) be
32//    recorded in the viewer's stats for the "beginTimeName" and "endTimeName".
33//  - A line in the bottom graph
34//    Requires that an elapsed time be recorded in the viewer's stats for the
35//    "timeTakenName".
36
37
38// Anything you want to time has to use a consistent name in both the stats
39// handler and the viewer stats, so it's a good idea to use constants to make
40// sure the names are the same everywhere.
41const std::string frameNumberName    = "Custom Frame Number";
42const std::string frameTimeName      = "Custom Frame Time";
43const std::string customTimeName     = "Custom";
44const std::string operation1TimeName = "Operation1";
45const std::string operation2TimeName = "Operation2";
46const std::string otherThreadTimeName = "Thread";
47
48
49void initUserStats(osgViewer::StatsHandler* statsHandler)
50{
51    // This line displays the frame number. It's not averaged, just displayed as is.
52    statsHandler->addUserStatsLine("Frame", osg::Vec4(0.7,0.7,0.7,1), osg::Vec4(0.7,0.7,0.7,0.5),
53                                   frameNumberName, 1.0, false, false, "", "", 0.0);
54
55    // This line displays the frame time (from beginning of event to end of draw). No bars.
56    statsHandler->addUserStatsLine("MS/frame", osg::Vec4(1,0,1,1), osg::Vec4(1,0,1,0.5),
57                                   frameTimeName, 1000.0, true, false, "", "", 0.02);
58
59    // This line displays the sum of update and main camera cull times.
60    statsHandler->addUserStatsLine("Custom", osg::Vec4(1,1,1,1), osg::Vec4(1,1,1,0.5),
61                                   customTimeName + " time taken", 1000.0, true, false, customTimeName + " begin", customTimeName + " end", 0.016);
62
63    // This line displays the time taken by a function below ( doSomethingAndTimeIt() )
64    statsHandler->addUserStatsLine("Sleep1", osg::Vec4(1,0,0,1), osg::Vec4(1,0,0,0.5),
65                                   operation1TimeName + " time taken", 1000.0, true, false, operation1TimeName + " begin", operation1TimeName + " end", 0.016);
66
67    // This line displays the time taken by a function below ( doSomethingAndTimeIt() )
68    statsHandler->addUserStatsLine("Sleep2", osg::Vec4(1,0.5,0.5,1), osg::Vec4(1,0.5,0.5,0.5),
69                                   operation2TimeName + " time taken", 1000.0, true, false, operation2TimeName + " begin", operation2TimeName + " end", 0.016);
70
71    // This line displays the time taken by a function below ( doSomethingAndTimeIt() )
72    statsHandler->addUserStatsLine("Thread", osg::Vec4(0,0.5,0,1), osg::Vec4(0,0.5,0,0.5),
73                                   otherThreadTimeName + " time taken", 1000.0, true, false, otherThreadTimeName + " begin", otherThreadTimeName + " end", 0.016);
74}
75
76
77void updateUserStats(osgViewer::Viewer& viewer)
78{
79    // Test the custom stats line by just adding up the update and cull
80    // times for the viewer main camera for the previous frame.
81    if (viewer.getViewerStats()->collectStats("update") && viewer.getCamera()->getStats()->collectStats("rendering"))
82    {
83        // First get the frame number. The code below assumes that
84        // updateUserStats() is called after advance(), so the frame number
85        // that will be returned is for the frame that has just started and is
86        // not rendered yet. The previous frame is framenumber-1, but we can't
87        // use that frame's timings because it's probably not finished
88        // rendering yet (in multithreaded viewer modes). So we'll use the
89        // timings for framenumber-2 for this demo.
90        int framenumber = viewer.getFrameStamp()->getFrameNumber();
91
92        // Get the update time and the viewer main camera's cull time. We use
93        // getAveragedAttribute() in order to get the actual time elapsed as
94        // calculated by the stats.
95        double update = 0.0, cull = 0.0;
96        viewer.getViewerStats()->getAveragedAttribute("Update traversal time taken", update);
97        viewer.getCamera()->getStats()->getAveragedAttribute("Cull traversal time taken", cull);
98
99        // Get various begin and end times, note these are not elapsed times
100        // in a frame but rather the simulation time at those moments.
101        double eventBegin = 0.0, updateBegin = 0.0, cullEnd = 0.0, drawEnd = 0.0;
102        viewer.getViewerStats()->getAttribute(framenumber-2, "Event traversal begin time", eventBegin);
103        viewer.getViewerStats()->getAttribute(framenumber-2, "Update traversal begin time", updateBegin);
104        viewer.getCamera()->getStats()->getAttribute(framenumber-2, "Cull traversal end time", cullEnd);
105        viewer.getCamera()->getStats()->getAttribute(framenumber-2, "Draw traversal end time", drawEnd);
106
107        // This line displays the frame number. It's not averaged, just displayed as is.
108        viewer.getViewerStats()->setAttribute(framenumber, frameNumberName, framenumber);
109
110        // This line displays the frame time (from beginning of event to end of draw). No bars.
111        viewer.getViewerStats()->setAttribute(framenumber-1, frameTimeName, drawEnd - eventBegin);
112
113        // This line displays the sum of update and main camera cull times.
114        viewer.getViewerStats()->setAttribute(framenumber-1, customTimeName + " time taken", update+cull);
115        // Since we give begin and end times that correspond to the begin of
116        // the update phase and the end of the cull phase, the bar in the
117        // graph will not correspond to the summed times above if something
118        // happened between update and cull (as in this demo). Also, we need
119        // to translate the updateBegin and cullEnd times by one frame since
120        // we're taking the times for framenumber-2 but using them to display
121        // in the framenumber-1 graph.
122        viewer.getViewerStats()->setAttribute(framenumber-1, customTimeName + " begin", updateBegin + (1.0/60.0));
123        viewer.getViewerStats()->setAttribute(framenumber-1, customTimeName + " end", cullEnd + (1.0/60.0));
124    }
125}
126
127
128/// Utility function you call before something you want to time, so that the
129/// recorded times will all be consistent using the viewer's time.
130void startTiming(osgViewer::Viewer& viewer, const std::string& name)
131{
132    osg::Timer_t tick = osg::Timer::instance()->tick();
133    double currentTime = osg::Timer::instance()->delta_s(viewer.getStartTick(), tick);
134    int framenumber = viewer.getFrameStamp()->getFrameNumber();
135
136    viewer.getViewerStats()->setAttribute(framenumber, name + " begin", currentTime);
137}
138
139/// Utility function you call after something you want to time, so that the
140/// recorded times will all be consistent using the viewer's time.
141void endTiming(osgViewer::Viewer& viewer, const std::string& name)
142{
143    osg::Timer_t tick = osg::Timer::instance()->tick();
144    double currentTime = osg::Timer::instance()->delta_s(viewer.getStartTick(), tick);
145    int framenumber = viewer.getFrameStamp()->getFrameNumber();
146
147    viewer.getViewerStats()->setAttribute(framenumber, name + " end", currentTime);
148
149    double begin = 0.0;
150    double elapsed = 0.0;
151    if (viewer.getViewerStats()->getAttribute(framenumber, name + " begin", begin))
152    {
153        elapsed = currentTime - begin;
154    }
155
156    viewer.getViewerStats()->setAttribute(framenumber, name + " time taken", elapsed);
157}
158
159
160/// Will just sleep for the given number of milliseconds in the same thread
161/// as the caller, recording the time taken in the viewer's stats.
162void doSomethingAndTimeIt(osgViewer::Viewer& viewer, const std::string& name, double milliseconds)
163{
164    startTiming(viewer, name);
165
166    //------------------------------------------------------------
167    // Your processing goes here.
168
169    // Do nothing for the specified number of  milliseconds, just so we can
170    // see it in the stats.
171    osg::Timer_t startTick = osg::Timer::instance()->tick();
172    while (osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick()) < milliseconds)
173    {
174        OpenThreads::Thread::YieldCurrentThread();
175    }
176    //------------------------------------------------------------
177
178    endTiming(viewer, name);
179}
180
181
182/// Thread that will sleep for the given number of milliseconds, recording
183/// the time taken in the viewer's stats, whenever its process() method is
184/// called.
185class UselessThread : public OpenThreads::Thread
186{
187public:
188    UselessThread(osgViewer::Viewer& viewer, double timeToRun)
189        : _viewer(viewer)
190        , _timeToRun(timeToRun)
191        , _done(false)
192        , _process(false)
193    {
194    }
195
196    void run()
197    {
198        while (!_done)
199        {
200            if (_process)
201            {
202                startTiming(_viewer, otherThreadTimeName);
203
204                //------------------------------------------------------------
205                // Your processing goes here.
206
207                // Do nothing for the specified number of  milliseconds, just so we can
208                // see it in the stats.
209                osg::Timer_t startTick = osg::Timer::instance()->tick();
210                while (osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick()) < _timeToRun)
211                {
212                    OpenThreads::Thread::YieldCurrentThread();
213                }
214                //------------------------------------------------------------
215
216                endTiming(_viewer, otherThreadTimeName);
217
218                _process = false;
219            }
220            else
221            {
222                OpenThreads::Thread::microSleep(50);
223            }
224        }
225    }
226
227    int cancel()
228    {
229        _done = true;
230        return OpenThreads::Thread::cancel();
231    }
232
233    void process()
234    {
235        _process = true;
236    }
237
238protected:
239    osgViewer::Viewer& _viewer;
240    double _timeToRun;
241    bool _done;
242    bool _process;
243};
244
245
246int main(int argc, char** argv)
247{
248    // use an ArgumentParser object to manage the program arguments.
249    osg::ArgumentParser arguments(&argc,argv);
250
251    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
252    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
253    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
254    arguments.getApplicationUsage()->addCommandLineOption("--image <filename>","Load an image and render it on a quad");
255    arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>","Load an image/DEM and render it on a HeightField");
256    arguments.getApplicationUsage()->addCommandLineOption("--login <url> <username> <password>","Provide authentication information for http file access.");
257
258    osgViewer::Viewer viewer(arguments);
259
260    unsigned int helpType = 0;
261    if ((helpType = arguments.readHelpType()))
262    {
263        arguments.getApplicationUsage()->write(std::cout, helpType);
264        return 1;
265    }
266
267    // report any errors if they have occurred when parsing the program arguments.
268    if (arguments.errors())
269    {
270        arguments.writeErrorMessages(std::cout);
271        return 1;
272    }
273
274    if (arguments.argc()<=1)
275    {
276        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
277        return 1;
278    }
279
280    std::string url, username, password;
281    while(arguments.read("--login",url, username, password))
282    {
283        if (!osgDB::Registry::instance()->getAuthenticationMap())
284        {
285            osgDB::Registry::instance()->setAuthenticationMap(new osgDB::AuthenticationMap);
286            osgDB::Registry::instance()->getAuthenticationMap()->addAuthenticationDetails(
287                url,
288                new osgDB::AuthenticationDetails(username, password)
289            );
290        }
291    }
292
293    viewer.setCameraManipulator(new osgGA::TrackballManipulator);
294
295    // add the state manipulator
296    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
297
298    // add the thread model handler
299    viewer.addEventHandler(new osgViewer::ThreadingHandler);
300
301    // add the window size toggle handler
302    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
303
304    // add the stats handler
305    osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
306    viewer.addEventHandler(statsHandler);
307
308    initUserStats(statsHandler);
309
310    // add the help handler
311    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
312
313    // load the data
314    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
315    if (!loadedModel)
316    {
317        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
318        return 1;
319    }
320
321    // any option left unread are converted into errors to write out later.
322    arguments.reportRemainingOptionsAsUnrecognized();
323
324    // report any errors if they have occurred when parsing the program arguments.
325    if (arguments.errors())
326    {
327        arguments.writeErrorMessages(std::cout);
328        return 1;
329    }
330
331
332    // optimize the scene graph, remove redundant nodes and state etc.
333    osgUtil::Optimizer optimizer;
334    optimizer.optimize(loadedModel.get());
335
336    viewer.setSceneData( loadedModel.get() );
337
338    viewer.realize();
339
340    // Start up a thread that will just run for a fixed time each frame, in
341    // parallel to the frame loop.
342    UselessThread thread(viewer, 6.0);
343    thread.start();
344
345    while (!viewer.done())
346    {
347        viewer.advance();
348
349        updateUserStats(viewer);
350
351        // Eat up some time on the viewer thread before the event phase.
352        doSomethingAndTimeIt(viewer, operation1TimeName, 2.0);
353
354        // Start taking some time on the other thread.
355        thread.process();
356
357        viewer.eventTraversal();
358        viewer.updateTraversal();
359
360        // Eat up some time on the viewer thread between the update and cull
361        // phases.
362        doSomethingAndTimeIt(viewer, operation2TimeName, 3.0);
363
364        viewer.renderingTraversals();
365    }
366
367    thread.cancel();
368    while (thread.isRunning())
369    {
370        OpenThreads::Thread::YieldCurrentThread();
371    }
372
373}
Note: See TracBrowser for help on using the browser.