ovr_sdk

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