import 'package:flutter/material.dart'; class ProfileScope { final String name; final DateTime start; final DateTime end; const ProfileScope(this.name, this.start, this.end); } class ProfileFrame { final int id; final DateTime start; final DateTime end; final List scopes; const ProfileFrame(this.id, this.start, this.end, this.scopes); } extension DurationExt on Duration { double get toSeconds => this.inMicroseconds.toDouble() / 1000000.0; } class ProfilerPage extends StatelessWidget { final List frames; const ProfilerPage(this.frames, {super.key}); @override Widget build(BuildContext context) { if (frames.isEmpty) { return const Center( child: Text( "Run the project to see profiling information", style: TextStyle(fontSize: 36), ), ); } final frameTimes = this.frames.map((frame) => frame.end.difference(frame.start)).toList(); final totalFrameTime = frameTimes.reduce((a, b) => a + b); final averageFrameTime = totalFrameTime.inMicroseconds / this.frames.length; final averageFps = this.frames.length / totalFrameTime.toSeconds; Duration totalFrameTimeForPreviousSecond = const Duration(); final List frameTimesForPreviousSecond = []; for (int i = frameTimes.length - 1; i >= 0; i--) { final currentFrameTime = frameTimes[i]; totalFrameTimeForPreviousSecond += currentFrameTime; frameTimesForPreviousSecond.add(currentFrameTime); if (totalFrameTimeForPreviousSecond.toSeconds >= 1.0) { break; } } frameTimesForPreviousSecond.sort((a, b) => b.compareTo(a)); final fpsLow = 1 / frameTimesForPreviousSecond[(frameTimesForPreviousSecond.length / 20).floor()].toSeconds; return Padding( padding: const EdgeInsets.all(20), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("Average Frame Time: ${averageFrameTime.round()} μs"), Text("Average FPS: ${averageFps.round()} fps"), Text("Low 5% FPS: ${fpsLow.round()}"), ], ), ], ), ); } }