// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'dart:isolate';
import 'dart:math' as math;

import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:vm_service/vm_service_io.dart' as vm_service_io;

import '../../../pkg/vm/bin/gen_kernel.dart' as gen_kernel;

const String compilerIsolateName = 'isolate-compiler';

class Result {
  const Result(
    this.rssOnStart,
    this.rssOnEnd,
    this.heapOnStart,
    this.heapOnEnd,
  );

  final int rssOnStart;
  final int rssOnEnd;
  final int heapOnStart;
  final int heapOnEnd;
}

class StartMessage {
  const StartMessage(this.wsUri, this.sendPort);

  final String wsUri;
  final SendPort sendPort;
}

class SpawnMemory {
  SpawnMemory(this.name, this.wsUri);

  Future<void> report() async {
    int maxProcessRss = 0;
    final timer = Timer.periodic(const Duration(microseconds: 100), (_) {
      maxProcessRss = math.max(maxProcessRss, ProcessInfo.currentRss);
    });

    const numberOfBenchmarks = 3;

    final beforeRss = ProcessInfo.currentRss;
    final beforeHeap = await currentHeapUsage(wsUri);

    final iterators = <StreamIterator>[];
    final continuations = <SendPort>[];

    // Start all isolates & make them wait.
    for (int i = 0; i < numberOfBenchmarks; i++) {
      final receivePort = ReceivePort();
      final startMessage = StartMessage(wsUri, receivePort.sendPort);
      await Isolate.spawn(
        isolateCompiler,
        startMessage,
        debugName: compilerIsolateName,
      );
      final iterator = StreamIterator(receivePort);

      if (!await iterator.moveNext()) throw 'failed';
      continuations.add(iterator.current as SendPort);

      iterators.add(iterator);
    }

    final readyRss = ProcessInfo.currentRss;
    final readyHeap = await currentHeapUsage(wsUri);

    // Let all isolates do the gen_kernel compilation.
    for (int i = 0; i < numberOfBenchmarks; i++) {
      final iterator = iterators[i];
      final continuation = continuations[i];
      continuation.send(null);
      if (!await iterator.moveNext()) throw 'failed';
      if (iterator.current != 'done') throw 'failed';
    }

    final doneRss = ProcessInfo.currentRss;
    final doneHeap = await currentHeapUsage(wsUri);

    // Shut down helper isolates
    for (int i = 0; i < numberOfBenchmarks; i++) {
      final iterator = iterators[i];
      final continuation = continuations[i];
      continuation.send(null);
      if (!await iterator.moveNext()) throw 'failed';
      if (iterator.current != 'shutdown') throw 'failed';
      await iterator.cancel();
    }
    timer.cancel();

    final readyDiffRss =
        math.max(0, readyRss - beforeRss) ~/ numberOfBenchmarks;
    final readyDiffHeap =
        math.max(0, readyHeap - beforeHeap) ~/ numberOfBenchmarks;
    final doneDiffRss = math.max(0, doneRss - beforeRss) ~/ numberOfBenchmarks;
    final doneDiffHeap =
        math.max(0, doneHeap - beforeHeap) ~/ numberOfBenchmarks;

    print('${name}RssOnStart(MemoryUse): $readyDiffRss');
    print('${name}RssOnEnd(MemoryUse): $doneDiffRss');
    print('${name}HeapOnStart(MemoryUse): $readyDiffHeap');
    print('${name}HeapOnEnd(MemoryUse): $doneDiffHeap');
    print('${name}PeakProcessRss(MemoryUse): $maxProcessRss');
  }

  final String name;
  final String wsUri;
}

Future<void> isolateCompiler(StartMessage startMessage) async {
  final port = ReceivePort();
  final iterator = StreamIterator(port);

  // Let main isolate know we're ready.
  startMessage.sendPort.send(port.sendPort);
  await iterator.moveNext();

  await runZoned(
    () => gen_kernel.compile(<String>[
      'benchmarks/IsolateSpawn/dart/helloworld.dart',
      'benchmarks/IsolateSpawn/dart/helloworld.dart.dill',
    ]),
    zoneSpecification: ZoneSpecification(
      print: (Zone self, ZoneDelegate parent, Zone zone, String line) {},
    ),
  );

  // Let main isolate know we're done.
  startMessage.sendPort.send('done');
  await iterator.moveNext();

  // Closes the port.
  startMessage.sendPort.send('shutdown');
  await iterator.cancel();
}

Future<int> currentHeapUsage(String wsUri) async {
  final vmService = await vm_service_io.vmServiceConnectUri(wsUri);
  final groupIds = await getGroupIds(vmService);
  int sum = 0;
  for (final groupId in groupIds) {
    final usage = await vmService.getIsolateGroupMemoryUsage(groupId);
    sum += usage.heapUsage! + usage.externalUsage!;
  }
  unawaited(vmService.dispose());
  return sum;
}

Future<void> main() async {
  // Only if we successfully reach the end will we set 0 exit code.
  exitCode = 255;

  final info = await Service.controlWebServer(enable: true);
  final observatoryUri = info.serverUri!;
  final wsUri = 'ws://${observatoryUri.authority}${observatoryUri.path}ws';
  await SpawnMemory('IsolateSpawnMemory.Dart2JSDelta', wsUri).report();

  // Only if we successfully reach the end will we set 0 exit code.
  exitCode = 0;
}

// Returns the set of isolate groups for which we should count the heap usage.
Future<List<String>> getGroupIds(vm_service.VmService vmService) async {
  final groupIds = <String>{};
  final vm = await vmService.getVM();
  for (final groupRef in vm.isolateGroups!) {
    final group = await vmService.getIsolateGroup(groupRef.id!);
    for (final isolateRef in group.isolates!) {
      try {
        await vmService.getIsolate(isolateRef.id!);
        groupIds.add(groupRef.id!);
        break;
      } on vm_service.SentinelException catch (_) {
        // Skip groups with only sentinels.
      }
    }
  }
  if (groupIds.isEmpty) {
    throw 'Could not find main isolate';
  }
  return groupIds.toList();
}
