ovr_sdk

view LibOVR/Src/CAPI/CAPI_LatencyStatistics.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line source
1 /************************************************************************************
3 Filename : CAPI_LatencyStatistics.cpp
4 Content : Record latency statistics during rendering
5 Created : Sept 23, 2014
6 Authors : Chris Taylor, Kevin Jenkins
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
12 which is provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
15 You may obtain a copy of the License at
17 http://www.oculusvr.com/licenses/LICENSE-3.2
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
25 ************************************************************************************/
27 #include "CAPI_LatencyStatistics.h"
29 #include "../Kernel/OVR_Log.h"
30 #include "../Kernel/OVR_Threads.h"
31 #include "../Util/Util_SystemInfo.h"
33 namespace OVR { namespace CAPI {
35 //-----------------------------------------------------------------------------
36 // ***** LatencyStatisticsObserver
38 LatencyStatisticsCSV::LatencyStatisticsCSV()
39 {
40 }
42 LatencyStatisticsCSV::~LatencyStatisticsCSV()
43 {
44 Stop();
45 }
47 bool LatencyStatisticsCSV::Start(String fileName, String userData1)
48 {
49 if (_File.IsValid())
50 {
51 if (fileName == FileName)
52 {
53 UserData1 = userData1;
54 return true;
55 }
56 else
57 {
58 Stop();
59 }
60 }
62 OVR::String basePath = OVR::GetBaseOVRPath(true);
63 OVR::String path = basePath;
64 path.AppendString("\\");
65 path.AppendString(fileName);
66 OS = OVR::Util::OSAsString();
67 OSVersion = OVR::Util::OSVersionAsString();
68 #if defined (OVR_OS_WIN64) || defined (OVR_OS_WIN32)
69 ProcessInfo = OVR::Util::GetProcessInfo();
70 DisplayDriverVersion = OVR::Util::GetDisplayDriverVersion();
71 CameraDriverVersion = OVR::Util::GetCameraDriverVersion();
72 OVR::Array< OVR::String > gpus;
73 OVR::Util::GetGraphicsCardList(gpus);
74 StringBuffer sb;
75 size_t gpuIdx;
76 for (gpuIdx = 0; gpuIdx < gpus.GetSize(); gpuIdx++)
77 {
78 sb.AppendString(gpus[gpuIdx]);
79 if (gpuIdx + 1 < gpus.GetSize())
80 sb.AppendString("; ");
81 }
82 GPUVersion = sb;
83 #endif
84 Guid = OVR::Util::GetGuidString();
86 if (!_File.Open(path, OVR::File::Open_Write, OVR::File::Mode_Write))
87 {
88 _File.Create(path, OVR::File::Mode_Write);
89 WriteHeaderV1();
90 }
91 else
92 {
93 _File.Seek(0, FileConstants::Seek_End);
94 }
96 if (_File.IsValid())
97 {
98 UserData1 = userData1;
99 FileName = fileName;
100 _Observer.SetHandler(LatencyStatisticsSlot::FromMember<LatencyStatisticsCSV, &LatencyStatisticsCSV::OnResults>(this));
102 return true;
103 }
105 return false;
106 }
107 bool LatencyStatisticsCSV::Stop()
108 {
109 if (_File.IsValid())
110 {
111 _File.Flush();
112 _File.Close();
113 _Observer.ReleaseAll();
115 Guid.Clear();
116 FileName.Clear();
117 return true;
118 }
119 return false;
120 }
121 void LatencyStatisticsCSV::WriteHeaderV1()
122 {
123 if (_File.IsValid())
124 {
125 // Write header if creating the file
126 const char *str = "GUID,OS,OSVersion,Process,DisplayDriver,CameraDriver,GPU,Time,Interval,FPS,EndFrameExecutionTime,LatencyRender,LatencyTimewarp,LatencyPostPresent,LatencyVisionProc,LatencyVisionFrame,UserData1\n";
127 _File.Write((const uint8_t *) str, (int)OVR_strlen(str));
128 }
129 }
131 void LatencyStatisticsCSV::WriteResultsV1(LatencyStatisticsResults *results)
132 {
133 if (_File.IsValid())
134 {
135 char str[512];
136 OVR_sprintf(str, sizeof(str),
137 "%s,%s,%s,%s,%s,%s,%s,%f,%f,%f,%f,%f,%f,%f,%f,%f,%s\n",
138 Guid.ToCStr(),
139 OS.ToCStr(),
140 OSVersion.ToCStr(),
141 ProcessInfo.ToCStr(),
142 DisplayDriverVersion.ToCStr(),
143 CameraDriverVersion.ToCStr(),
144 GPUVersion.ToCStr(),
145 ovr_GetTimeInSeconds(),
146 results->IntervalSeconds,
147 results->FPS,
148 results->EndFrameExecutionTime,
149 results->LatencyRender,
150 results->LatencyTimewarp,
151 results->LatencyPostPresent,
152 results->LatencyVisionProc,
153 results->LatencyVisionFrame,
154 UserData1.ToCStr());
155 str[sizeof(str)-1] = 0;
156 _File.Write((const uint8_t *)str, (int)OVR_strlen(str));
157 }
158 }
159 void LatencyStatisticsCSV::OnResults(LatencyStatisticsResults *results)
160 {
161 WriteResultsV1(results);
162 }
163 //-------------------------------------------------------------------------------------
164 // ***** LatencyStatisticsCalculator
166 LagStatsCalculator::LagStatsCalculator()
167 {
168 resetPerfStats();
169 }
171 void LagStatsCalculator::resetPerfStats(double resetTime)
172 {
173 EndFrameStartTime = 0.;
174 EndFrameEndTime = 0.;
176 LastCameraFrameCounter = ~(uint32_t)0;
178 EpochBegin = resetTime; // Set epoch start to now
180 FrameCount = 0;
181 //EndFrameSum = 0.;
183 //VisionProcSum = 0.;
184 //VisionLagSum = 0.;
185 VisionFrames = 0;
187 //for (int i = 0; i < 3; ++i)
188 //{
189 // LatencyData[i] = 0.f;
190 // LatencySum[i] = 0.;
191 //}
193 latencyStatisticsData.EndFrameExecutionTime = 0;
194 latencyStatisticsData.LatencyRender = 0;
195 latencyStatisticsData.LatencyTimewarp = 0;
196 latencyStatisticsData.LatencyPostPresent = 0;
197 latencyStatisticsData.LatencyVisionProc = 0;
198 latencyStatisticsData.LatencyVisionFrame = 0;
199 }
201 void LagStatsCalculator::GetLatestResults(LatencyStatisticsResults* results)
202 {
203 *results = Results.GetState();
204 }
205 void LagStatsCalculator::AddResultsObserver(ObserverScope<LatencyStatisticsSlot> *calculateResultsObserver)
206 {
207 Lock::Locker locker(&calculateResultsLock);
208 calculateResultsObserver->GetPtr()->Observe(calculateResultsSubject);
209 }
210 void LagStatsCalculator::InstrumentEndFrameStart(double timestamp)
211 {
212 EndFrameStartTime = timestamp;
213 }
215 void LagStatsCalculator::InstrumentLatencyTimings(FrameTimeManager& ftm)
216 {
217 //latencies[0] = (float)RenderLatencySeconds;
218 //latencies[1] = (float)TimewarpLatencySeconds;
219 //latencies[2] = (float)FrameDeltas.GetMedianTimeDelta();
221 // Note: This assumes that it is called right before InstrumentEndFrameEnd()
222 float latencyRender, latencyTimewarp, latencyPostPresent;
223 ftm.GetLatencyTimings(latencyRender, latencyTimewarp, latencyPostPresent);
224 latencyStatisticsData.LatencyRender += latencyRender;
225 latencyStatisticsData.LatencyTimewarp += latencyTimewarp;
226 latencyStatisticsData.LatencyPostPresent += latencyPostPresent;
227 }
229 void LagStatsCalculator::InstrumentEndFrameEnd(double timestamp)
230 {
231 EndFrameEndTime = timestamp;
233 calculateResults();
234 }
236 void LagStatsCalculator::InstrumentEyePose(const ovrTrackingState& state)
237 {
238 // If the camera frame counter has rolled,
239 if (LastCameraFrameCounter != state.LastCameraFrameCounter)
240 {
241 // Accumulate eye pose data
242 if (state.StatusFlags != 0)
243 {
244 latencyStatisticsData.LatencyVisionProc += state.LastVisionProcessingTime;
245 latencyStatisticsData.LatencyVisionFrame += state.LastVisionFrameLatency;
246 }
247 ++VisionFrames;
249 LastCameraFrameCounter = state.LastCameraFrameCounter;
250 }
251 }
253 // Note: Currently assumes this is being called from OnEndFrameEnd() above.
254 void LagStatsCalculator::calculateResults()
255 {
256 // Calculate time in the current epoch so far
257 double intervalDuration = EndFrameEndTime - EpochBegin;
259 // If stats should be reset due to inactivity,
260 if (intervalDuration >= OVR_LAG_STATS_RESET_LIMIT)
261 {
262 resetPerfStats(EndFrameEndTime);
263 return;
264 }
266 // Calculate EndFrame() duration
267 double endFrameDuration = EndFrameEndTime - EndFrameStartTime;
269 // Incorporate EndFrame() duration into the running sum
270 latencyStatisticsData.EndFrameExecutionTime += endFrameDuration;
272 //for (int i = 0; i < 3; ++i)
273 //{
274 // LatencySum[i] += LatencyData[i];
275 //}
277 // Increment frame counter
278 ++FrameCount;
280 // If enough time has passed,
281 if (intervalDuration >= OVR_LAG_STATS_EPOCH)
282 {
283 LatencyStatisticsResults results;
285 float invFrameCount = 1.0f / (float) FrameCount;
287 // EndFrame() instrumentation
288 results.IntervalSeconds = intervalDuration;
289 results.FPS = FrameCount / intervalDuration;
290 results.EndFrameExecutionTime = latencyStatisticsData.EndFrameExecutionTime * invFrameCount;
292 // Latency data
293 results.LatencyRender = latencyStatisticsData.LatencyRender * invFrameCount;
294 results.LatencyTimewarp = latencyStatisticsData.LatencyTimewarp * invFrameCount;
295 results.LatencyPostPresent = latencyStatisticsData.LatencyPostPresent * invFrameCount;
297 double invVisionFrameCount = 1. / VisionFrames;
299 // Eye pose instrumentation
300 results.LatencyVisionProc = latencyStatisticsData.LatencyVisionProc * invVisionFrameCount;
301 results.LatencyVisionFrame = latencyStatisticsData.LatencyVisionFrame * invVisionFrameCount;
303 Results.SetState(results);
305 {
306 Lock::Locker locker(&calculateResultsLock);
307 calculateResultsSubject.GetPtr()->Call(&results);
308 }
310 // Reset for next frame
311 resetPerfStats();
312 }
313 }
316 }} // namespace OVR::CAPI