// Copyright (c) 2021, 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.

// These micro benchmarks track the speed of native calls.

import 'dart:ffi';
import 'dart:io';

import 'package:benchmark_harness/benchmark_harness.dart';

import 'dlopen_helper.dart';

// Number of benchmark iterations per function.
const N = 1000;

// The native library that holds all the native functions being called.
final nativeFunctionsLib = dlopenPlatformSpecific(
  'native_functions',
  path: Platform.script.resolve('../native/out/').path,
);

final getRootLibraryUrl = nativeFunctionsLib
    .lookupFunction<Handle Function(), Object Function()>('GetRootLibraryUrl');

final setNativeResolverForTest = nativeFunctionsLib
    .lookupFunction<Void Function(Handle), void Function(Object)>(
      'SetNativeResolverForTest',
    );

//
// Benchmark fixtures.
//

abstract class NativeCallBenchmarkBase extends BenchmarkBase {
  NativeCallBenchmarkBase(String name) : super(name);

  void expectEquals(actual, expected) {
    if (actual != expected) {
      throw Exception('$name: Unexpected result: $actual, expected $expected');
    }
  }

  void expectApprox(actual, expected) {
    if (0.999 * expected > actual || actual > 1.001 * expected) {
      throw Exception('$name: Unexpected result: $actual, expected $expected');
    }
  }

  void expectIdentical(actual, expected) {
    if (!identical(actual, expected)) {
      throw Exception('$name: Unexpected result: $actual, expected $expected');
    }
  }
}

class Uint8x01 extends NativeCallBenchmarkBase {
  Uint8x01() : super('NativeCall.Uint8x01');

  @pragma('vm:external-name', 'Function1Uint8')
  external static int f(int a);

  @override
  void run() {
    int x = 0;
    for (int i = 0; i < N; i++) {
      x += f(17);
    }
    expectEquals(x, N * 17 + N * 42);
  }
}

class Int64x20 extends NativeCallBenchmarkBase {
  Int64x20() : super('NativeCall.Int64x20');

  @pragma('vm:external-name', 'Function20Int64')
  external static int f(
    int a,
    int b,
    int c,
    int d,
    int e,
    int f,
    int g,
    int h,
    int i,
    int j,
    int k,
    int l,
    int m,
    int n,
    int o,
    int p,
    int q,
    int r,
    int s,
    int t,
  );

  @override
  void run() {
    int x = 0;
    for (int i = 0; i < N; i++) {
      x += f(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
    }
    expectEquals(x, N * (N - 1) * 20 / 2);
  }
}

class Doublex01 extends NativeCallBenchmarkBase {
  Doublex01() : super('NativeCall.Doublex01');

  @pragma('vm:external-name', 'Function1Double')
  external static double f(double a);

  @override
  void run() {
    double x = 0.0;
    for (int i = 0; i < N; i++) {
      x += f(17.0);
    }
    final double expected = N * (17.0 + 42.0);
    expectApprox(x, expected);
  }
}

class Doublex20 extends NativeCallBenchmarkBase {
  Doublex20() : super('NativeCall.Doublex20');

  @pragma('vm:external-name', 'Function20Double')
  external static double f(
    double a,
    double b,
    double c,
    double d,
    double e,
    double f,
    double g,
    double h,
    double i,
    double j,
    double k,
    double l,
    double m,
    double n,
    double o,
    double p,
    double q,
    double r,
    double s,
    double t,
  );

  @override
  void run() {
    double x = 0;
    for (int i = 0; i < N; i++) {
      x += f(
        1.0,
        2.0,
        3.0,
        4.0,
        5.0,
        6.0,
        7.0,
        8.0,
        9.0,
        10.0,
        11.0,
        12.0,
        13.0,
        14.0,
        15.0,
        16.0,
        17.0,
        18.0,
        19.0,
        20.0,
      );
    }
    final double expected =
        N *
        (1.0 +
            2.0 +
            3.0 +
            4.0 +
            5.0 +
            6.0 +
            7.0 +
            8.0 +
            9.0 +
            10.0 +
            11.0 +
            12.0 +
            13.0 +
            14.0 +
            15.0 +
            16.0 +
            17.0 +
            18.0 +
            19.0 +
            20.0);
    expectApprox(x, expected);
  }
}

class MyClass {
  int a;
  MyClass(this.a);
}

class Handlex01 extends NativeCallBenchmarkBase {
  Handlex01() : super('NativeCall.Handlex01');

  @pragma('vm:external-name', 'Function1Handle')
  external static Object f(Object a);

  @override
  void run() {
    final p1 = MyClass(123);
    Object x = p1;
    for (int i = 0; i < N; i++) {
      x = f(x);
    }
    expectIdentical(x, p1);
  }
}

class Handlex20 extends NativeCallBenchmarkBase {
  Handlex20() : super('NativeCall.Handlex20');

  @pragma('vm:external-name', 'Function20Handle')
  external static Object f(
    Object a,
    Object b,
    Object c,
    Object d,
    Object e,
    Object f,
    Object g,
    Object h,
    Object i,
    Object j,
    Object k,
    Object l,
    Object m,
    Object n,
    Object o,
    Object p,
    Object q,
    Object r,
    Object s,
    Object t,
  );

  @override
  void run() {
    final p1 = MyClass(123);
    final p2 = MyClass(2);
    final p3 = MyClass(3);
    final p4 = MyClass(4);
    final p5 = MyClass(5);
    final p6 = MyClass(6);
    final p7 = MyClass(7);
    final p8 = MyClass(8);
    final p9 = MyClass(9);
    final p10 = MyClass(10);
    final p11 = MyClass(11);
    final p12 = MyClass(12);
    final p13 = MyClass(13);
    final p14 = MyClass(14);
    final p15 = MyClass(15);
    final p16 = MyClass(16);
    final p17 = MyClass(17);
    final p18 = MyClass(18);
    final p19 = MyClass(19);
    final p20 = MyClass(20);
    Object x = p1;
    for (int i = 0; i < N; i++) {
      x = f(
        x,
        p2,
        p3,
        p4,
        p5,
        p6,
        p7,
        p8,
        p9,
        p10,
        p11,
        p12,
        p13,
        p14,
        p15,
        p16,
        p17,
        p18,
        p19,
        p20,
      );
    }
    expectIdentical(x, p1);
  }
}

//
// Main driver.
//

void main() {
  setNativeResolverForTest(getRootLibraryUrl());

  final benchmarks = [
    Uint8x01.new,
    Int64x20.new,
    Doublex01.new,
    Doublex20.new,
    Handlex01.new,
    Handlex20.new,
  ];
  for (final benchmark in benchmarks) {
    benchmark().report();
  }
}
