private static void PrintReport(TextWriter tw) { tw.WriteLine("******** Profiling report *********"); tw.WriteLine("ReportName: {0}", sReportName); #if PLATFORM_MONOTOUCH tw.WriteLine("Device: {0}", UIDevice.CurrentDevice.Name); tw.WriteLine("Model: {0}", IOSDeviceHardware.Version.ToString()); tw.WriteLine("SystemVersion: {0}", UIDevice.CurrentDevice.SystemVersion); tw.WriteLine("Screen Size: {0}", UIScreen.MainScreen.Bounds); tw.WriteLine("Screen Scale: {0}", UIScreen.MainScreen.Scale); #endif tw.WriteLine("************* Loading *************"); PrintLoading(tw); tw.WriteLine("************* Session *************"); tw.WriteLine("Total Frames: {0}", sFrameCount); tw.WriteLine("Total Time: {0}", sReportTime.Elapsed); PerformanceFrameData performanceFrameData = GetPerformanceFrameData(); PrintAverageClamped(tw, "frame", performanceFrameData.FastFrame); PrintPercentile(tw, "frame", 95); PrintPercentageOfFrames(tw, "frame", "% Fast Frames", a => (a <= performanceFrameData.FastFrame), string.Format("<={0:0.00}ms", performanceFrameData.FastFrame)); PrintPercentageOfFrames(tw, "frame", "% Slow frames", a => (a >= performanceFrameData.SlowFrame), string.Format(">={0:0.00}ms", performanceFrameData.SlowFrame)); tw.WriteLine("GC Count: {0}", sReportGCCount); tw.WriteLine("*********** Timing (ms) ***********"); PrintFullTimes(tw); tw.WriteLine("*********** Histogram ************"); PrintHistograms(tw); tw.WriteLine("***** Dynamic Runtime Stats ******"); PrintStats(tw); tw.WriteLine("************ History *************"); PrintHistory(tw); tw.WriteLine("**********************************"); }
public static void InvokeReportDelegate() { if (ReporterDelegate == null) { return; } var pd = new ProfilerData(); pd.ReportName = sReportName; pd.Screen = GetScreenData(); #if PLATFORM_MONOTOUCH pd.Device = UIDevice.CurrentDevice.Name; pd.Model = IOSDeviceHardware.Version.ToString(); pd.SystemVersion = UIDevice.CurrentDevice.SystemVersion; #elif PLATFORM_MONODROID // Note: stock Android does not provide a way to set the device's name, // so won't be as meaningful as iOS. pd.Device = Build.Display; pd.Model = Build.Model; pd.SystemVersion = Build.VERSION.Release; #endif // loading section pd.Loading = new LoadingData(PlayScript.Player.Offline); foreach (var milestone in sLoadMilestones) { pd.Loading.AddMilestone(milestone.Key, milestone.Value); } // session section pd.Session = new SessionData(); pd.Session.TotalFrames = sReportFrameCount; pd.Session.TotalTime = sReportTime.Elapsed; PerformanceFrameData performanceFrameData = GetPerformanceFrameData(); string key = "frame"; double minimumClampedValue = performanceFrameData.FastFrame; double sum; if (GetAverageClampedInMs("frame", minimumClampedValue, out sum)) { pd.Session.AverageFrameRateInMs = (float)sum; pd.Session.AverageFrameRateInFps = (float)GetFpsFromMs(sum); pd.Session.AverageMinimumFrameRate = (float)minimumClampedValue; } Section section; if (sSections.TryGetValue(key, out section) == true) { List <double> history = section.History.Select(a => a.Time.TotalMilliseconds).OrderBy(a => a).ToList(); int percentile = 95; int index = (history.Count * percentile) / 100; double pTime = history[index]; pd.Session.NinetyFivePercentInMiliseconds = pTime; pd.Session.NinetyFivePercentInFramesPerSecond = GetFpsFromMs(pTime); } // TODO: convert this to a method. See PrintPercentageOfFrames if (sSections.TryGetValue(key, out section) == true) { int matchingFrames = 0; for (int frame = 0; frame < sFrameCount; frame++) { var history = section.History[frame]; if (history.Time.TotalMilliseconds <= performanceFrameData.FastFrame) { matchingFrames++; } } pd.Session.FastFramePercentage = (double)(100.0 * matchingFrames) / (double)sFrameCount; } // TODO: convert this to a method. See PrintPercentageOfFrames if (sSections.TryGetValue(key, out section) == true) { int matchingFrames = 0; for (int frame = 0; frame < sFrameCount; frame++) { var history = section.History[frame]; if (history.Time.TotalMilliseconds >= performanceFrameData.SlowFrame) { matchingFrames++; } } pd.Session.SlowFramePercentage = (double)(100.0 * matchingFrames) / (double)sFrameCount; } // TODO: missing in ProfilerData // PrintAverageNWorst(tw, "frame", 10); #if ENABLE_GC_COUNT // TODO: use a loop instead. Search for sGCMinGeneration and sGCMaxGeneration pd.Session.GarbageCollection0Count = sReportGCCounts[0]; pd.Session.GarbageCollection1Count = sReportGCCounts[1]; #endif var t = new TimingData(); t.Name = "frame"; t.TotalTime = TimeSpan.Parse("00:01:58.8786507"); t.Average = 36.58; t.Minimum = 9.37; t.Maximum = 915.04; t.Median = 30.64; t.GarbageCollection0Count = 453; t.UsedMemoryInKiloBytes = 0; pd.Timings.Add(t); t = new TimingData(); t.Name = "enterFrame"; t.TotalTime = TimeSpan.Parse("00:01:43.6920595"); t.Average = 31.91; t.Minimum = 7.45; t.Maximum = 912.19; t.Median = 25.52; t.GarbageCollection0Count = 431; t.UsedMemoryInKiloBytes = 0; pd.Timings.Add(t); ReporterDelegate(pd); }
private static void PrintReport(TextWriter tw, bool full) { tw.WriteLine("******** Profiling report *********"); tw.WriteLine("ReportName: {0}", sReportName); #if PLATFORM_MONOTOUCH tw.WriteLine("Device: {0}", UIDevice.CurrentDevice.Name); tw.WriteLine("Model: {0}", IOSDeviceHardware.Version.ToString()); tw.WriteLine("SystemVersion: {0}", UIDevice.CurrentDevice.SystemVersion); tw.WriteLine("Screen Size: {0}", UIScreen.MainScreen.Bounds); tw.WriteLine("Screen Scale: {0}", UIScreen.MainScreen.Scale); #elif PLATFORM_MONODROID // Note: stock Android does not provide a way to set the device's name, // so won't be as meaningful as iOS. tw.WriteLine("Device: {0}", Build.Display); tw.WriteLine("Model: {0}", Build.Model); tw.WriteLine("SystemVersion: {0}", Build.VERSION.Release); Context ctx = Android.App.Application.Context; IWindowManager wm = ctx.GetSystemService(Context.WindowService).JavaCast <IWindowManager>(); Display display = wm.DefaultDisplay; DisplayMetrics metrics = new DisplayMetrics(); display.GetMetrics(metrics); tw.WriteLine("Screen Size: {0}x{1}", metrics.WidthPixels, metrics.HeightPixels); tw.WriteLine("Screen Scale: {0}", metrics.ScaledDensity); #endif tw.WriteLine("************* Loading *************"); PrintLoading(tw); tw.WriteLine("************* Session *************"); tw.WriteLine("Total Frames: {0}", sReportFrameCount); tw.WriteLine("Real Frames: {0}", sFrameCount); tw.WriteLine("Total Time: {0}", sReportTime.Elapsed); if (FrameSkippingEnabled) { tw.WriteLine("Frame Skipping:Yes - Max Frame skipped: {0}", MaxNumberOfFramesElapsed - 1); // -1 because the first frame is not really skipped. } else { tw.WriteLine("Frame Skipping:No"); } PerformanceFrameData performanceFrameData = GetPerformanceFrameData(); PrintAverageClamped(tw, "frame", performanceFrameData.FastFrame); PrintPercentile(tw, "frame", 95); PrintPercentageOfFrames(tw, "frame", "% Fast Frames", a => (a <= performanceFrameData.FastFrame), string.Format("<={0:0.00}ms", performanceFrameData.FastFrame)); PrintPercentageOfFrames(tw, "frame", "% Slow frames", a => (a >= performanceFrameData.SlowFrame), string.Format(">={0:0.00}ms", performanceFrameData.SlowFrame)); PrintAverageNWorst(tw, "frame", 10); #if ENABLE_GC_COUNTS for (int i = sGCMinGeneration; i < sGCMaxGeneration; ++i) { tw.WriteLine("GC {0} Count: {1}", i, sReportGCCounts[i]); } #endif if (SessionData != null) { tw.WriteLine("********* Session Settings ********"); // write extra data about session foreach (var kvp in SessionData) { tw.WriteLine("{0}: {1}", kvp.Key, kvp.Value); } } tw.WriteLine("*********** Timing (ms) ***********"); PrintFullTimes(tw); tw.WriteLine("*********** Histogram ************"); PrintHistograms(tw); tw.WriteLine("***** Dynamic Runtime Stats ******"); PrintStats(tw); if (full) { tw.WriteLine("************ History *************"); PrintHistory(tw); } tw.WriteLine("**********************************"); }
// this should be called at the end of a frame public static void OnEndFrame() { if (!Enabled) { return; } if (EmitSlowFrames && LastTelemetryFrameSpanStart != long.MaxValue) { long endFrameTime = Stopwatch.GetTimestamp(); long spanTimeInTicks = endFrameTime - LastTelemetryFrameSpanStart; // From ticks to ns double spanTimeInNs = (double)spanTimeInTicks * (1000000000.0 / (double)Stopwatch.Frequency); PerformanceFrameData frameData = GetPerformanceFrameData(); double autoProfileFrameInNs = frameData.AutoProfileFrame * 1000000.0; // Convert ms to ns if (spanTimeInNs >= autoProfileFrameInNs) { Telemetry.Session.EndSpan("SlowFrame", LastTelemetryFrameSpanStart); } } Profiler.End("frame"); #if PLATFORM_MONOMAC || PLATFORM_MONOTOUCH || PLATFORM_MONODROID if (ProfileGPU) { // this stalls and waits for the gpu to finish PlayScript.Profiler.Begin("gpu", ".rend.gl.swap"); GL.Finish(); PlayScript.Profiler.End("gpu"); } #endif sFrameCount += NextFramesElapsed; MaxNumberOfFramesElapsed = Math.Max(MaxNumberOfFramesElapsed, NextFramesElapsed); // update all sections foreach (Section section in sSectionList) { section.TotalTime += section.Timer.Elapsed; if (sDoReport) { // pad with zeros if necessary while (section.History.Count < sFrameCount) { section.History.Add(ZeroSectionHistory); } var history = new SectionHistory(); history.Time = section.Timer.Elapsed; history.NumberOfCalls = section.NumberOfCalls; #if ENABLE_GC_COUNTS for (int i = sGCMinGeneration; i < Profiler.sGCMaxGeneration; ++i) { history.GCCounts[i] = section.GCCounts[i]; } #endif section.History.Add(history); } #if ENABLE_GC_COUNTS for (int i = sGCMinGeneration; i < Profiler.sGCMaxGeneration; ++i) { section.GCCounts[i] = 0; } #endif section.Timer.Reset(); section.NumberOfCalls = 0; } if (!sDoReport) { // normal profiling, just print out every so often if ((sPrintFrameCount != 0) && (sFrameCount >= sPrintFrameCount)) { PrintTimes(System.Console.Out); Reset(); } } else { // report generation, accumulate a specified number of frames and then print report if (sFrameCount >= sReportFrameCount) { // print out report OnEndReport(); Reset(); sDoReport = false; } } // check start report countdown if (sReportStartDelay > 0) { if (--sReportStartDelay == 0) { OnStartReport(); } } }