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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
|
/*=========================================================================
Program: Visualization Toolkit
Module: vtkRenderTimerLog.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/**
* @class vtkRenderTimerLog
* @brief Asynchronously measures GPU execution times for a series of events.
*
* This class measures the time it takes for events to occur on the GPU by
* posting timing events into the rendering command stream. This can be used
* to compute the time spent doing work on the GPU without stalling the
* CPU.
*
* To aid asynchronous usage, this class uses the concepts "Event" and "Frame",
* where a Frame is a logical collection of Events. The timer log can manage
* multiple Frames at a time:
* - The current Frame, where new Events are created.
* - Pending Frames, for which all Events have been marked, but the results are
* not available (the timer requests are still waiting to be processed by the
* graphics device).
* - Ready Frames, which have been completed by the graphics device and may be
* retrieved.
*
* Call MarkFrame() to begin a new Frame. This pushes the current Frame to the
* collection of pending Frames, and creates a new one to store future Events.
*
* Call MarkStartEvent() and MarkEndEvent() to mark the beginning and end of
* an Event. These Events may be nested, but all child Events must have their
* end marked before the parent Event ends.
*
* Use FrameReady() and PopFirstReadyFrame() to check for completed Frames and
* retrieve results.
*
* This is currently only implemented for the OpenGL2 backend. The IsSupported()
* method can be used to detect if there is a valid implementation available.
*/
#ifndef vtkRenderTimerLog_h
#define vtkRenderTimerLog_h
#include "vtkObject.h"
#include "vtkRenderingCoreModule.h" // For export macro
#include "vtkType.h" // For vtkTypeUint64, etc
#include <sstream> // for std::ostringstream
#include <string> // for std::string
#include <vector> // for std::vector
/**
* Creates a ScopedEventLogger on @a timer with the given @a name. @a name is
* passed into a stream and may be constructed using the << operator.
*/
#define VTK_SCOPED_RENDER_EVENT(eventName, timer) VTK_SCOPED_RENDER_EVENT2(eventName, timer, _event)
/**
* Creates a ScopedEventLogger on @a timer with the given @a name. @a name is
* passed into a stream and may be constructed using the << operator. The logger
* will be created with the provided @a identifier.
*/
#define VTK_SCOPED_RENDER_EVENT2(eventName, timer, identifier) \
vtkRenderTimerLog::ScopedEventLogger identifier; \
do \
{ \
std::ostringstream _eventNameStream; \
_eventNameStream << eventName; \
identifier = timer->StartScopedEvent(_eventNameStream.str()); \
(void)identifier; /* Prevent set-but-not-used var warnings */ \
} while (false) /* Do-while loop prevents duplicate semicolon warnings */
VTK_ABI_NAMESPACE_BEGIN
class VTKRENDERINGCORE_EXPORT vtkRenderTimerLog : public vtkObject
{
public:
struct Frame;
/** Container for a single timed event. */
struct VTKRENDERINGCORE_EXPORT Event
{
/** Event name. */
std::string Name;
/** Times are in nanoseconds. @{ */
vtkTypeUInt64 StartTime;
vtkTypeUInt64 EndTime;
/**@}*/
/** Convenience methods to compute times */
float ElapsedTimeSeconds() const { return this->ElapsedTimeNanoseconds() * 1e-9f; }
float ElapsedTimeMilliseconds() const { return this->ElapsedTimeNanoseconds() * 1e-6f; }
vtkTypeUInt64 ElapsedTimeNanoseconds() const { return this->EndTime - this->StartTime; }
/** Child events that occurred while this event was running. */
std::vector<Event> Events;
/** Print details of the event to a stream.
* @param os The stream.
* @param threshMs Only print events with a time > threshMs milliseconds.
* @param indent Starting indentation for the first event.
*/
void Print(std::ostream& os, float threshMs = 0.f, vtkIndent indent = vtkIndent())
{
this->Print(os, 0.f, threshMs, indent);
}
friend struct vtkRenderTimerLog::Frame;
protected:
void Print(std::ostream& os, float parentTime, float threshMs, vtkIndent indent);
};
/** Container for a frame's events. */
struct VTKRENDERINGCORE_EXPORT Frame
{
std::vector<Event> Events;
/** Print details of all events in this frame to a stream.
* @param os The stream.
* @param threshMs Only print events with a time > threshMs milliseconds.
*/
void Print(std::ostream& os, float threshMs = 0.f);
};
/**
* RAII struct for logging events. Such events start when
* vtkRenderTimerLog::StartScopedEvent(name) is called, and end when the
* returned object is destroyed, or ScopedEventLogger::Stop() is called.
*/
struct VTKRENDERINGCORE_EXPORT ScopedEventLogger
{
ScopedEventLogger()
: Log(nullptr)
{
}
ScopedEventLogger(ScopedEventLogger&& other) noexcept;
ScopedEventLogger& operator=(ScopedEventLogger&& other) noexcept;
~ScopedEventLogger() { this->Stop(); }
void Stop();
friend class vtkRenderTimerLog;
protected:
ScopedEventLogger(vtkRenderTimerLog* log)
: Log(log)
{
}
private:
void operator=(const ScopedEventLogger&) = delete;
ScopedEventLogger(const ScopedEventLogger& other) = delete;
vtkRenderTimerLog* Log;
};
static vtkRenderTimerLog* New();
vtkTypeMacro(vtkRenderTimerLog, vtkObject);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Returns true if stream timings are implemented for the current graphics
* backend.
*/
virtual bool IsSupported() VTK_FUTURE_CONST;
/**
* Call to mark the start of a new frame, or the end of an old one. Does
* nothing if no events have been recorded in the current frame.
*/
virtual void MarkFrame();
/**
* Create a RAII scoped event. See ScopedEventLogger for details.
*/
ScopedEventLogger StartScopedEvent(const std::string& name);
/**
* Mark the beginning or end of an event. @{
*/
virtual void MarkStartEvent(const std::string& name);
virtual void MarkEndEvent();
/**@}*/
/**
* Returns true if there are any frames ready with complete timing info.
*/
virtual bool FrameReady();
/**
* Retrieve the first available frame's timing info. The returned frame is
* removed from this log.
*/
virtual Frame PopFirstReadyFrame();
/** If false, no events are recorded. Default is false. @{ */
vtkSetMacro(LoggingEnabled, bool);
vtkGetMacro(LoggingEnabled, bool);
vtkBooleanMacro(LoggingEnabled, bool);
/**@}*/
/**
* If there are more than FrameLimit frames pending/ready, drop the old ones
* until we are under this limit. Prevents things from backing up.
* Default is 32. Set to 0 to disable. @{
*/
vtkSetMacro(FrameLimit, unsigned int);
vtkGetMacro(FrameLimit, unsigned int);
/**@}*/
/**
* Releases any resources allocated on the graphics device.
*/
virtual void ReleaseGraphicsResources();
protected:
vtkRenderTimerLog();
~vtkRenderTimerLog() override;
mutable bool LoggingEnabled;
unsigned int FrameLimit;
private:
vtkRenderTimerLog(const vtkRenderTimerLog&) = delete;
void operator=(const vtkRenderTimerLog&) = delete;
};
VTK_ABI_NAMESPACE_END
#endif // vtkRenderTimerLog_h
|