summaryrefslogtreecommitdiff
path: root/lib/profiler.dart
blob: 495dc4830c738fe0267fa18fd66168b997e91569 (plain)
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<ProfileScope> 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<ProfileFrame> 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<Duration> 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()}"),
            ],
          ),
        ],
      ),
    );
  }
}