Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible alternative use of switch that might be fast enough #150

Open
RandalSchwartz opened this issue Jun 25, 2023 · 3 comments
Open

Possible alternative use of switch that might be fast enough #150

RandalSchwartz opened this issue Jun 25, 2023 · 3 comments

Comments

@RandalSchwartz
Copy link

You rewrote this to be faster:

  int fastParseOn(String buffer, int position) {
    final result = parseOn(Context(buffer, position));
    return switch (result) {
      Success(position: final position) => position,
      Failure() => -1
    };
  }

I wonder if this might have been fast enough to still use the switch:

  int fastParseOn(String buffer, int position) {
    final result = parseOn(Context(buffer, position));
    return switch (result) {
      final Success s => s.position,
      Failure _ => -1,
    };
  }

I understand that might work faster for sorting out types and mapping them to branches. I think Type() goes through a lot of extra work compared to Type _.

@renggli
Copy link
Member

renggli commented Jul 16, 2023

True, your code example (switch2) is even a tiny bit faster than the original if-then-else (control):

control             10,180.044μs [10,144.016μs; 10,216.072μs]
switch1             13,883.637μs [13,871.288μs; 13,895.986μs]
                    -36.391% [-36.846%; -35.935%]
switch2             10,051.340μs [10,038.367μs; 10,064.313μs]
                    1.257% [0.896%; 1.617%]
switch3             13,957.153μs [13,942.120μs; 13,972.186μs]
                    -37.114% [-37.648%; -36.581%]

However, switch2 also yields the warnings The generic type 'Success<dynamic>' / 'Failure<dynamic>' should have explicit type arguments but doesn't. Fixing that (switch3) makes everything slow like the original switch1.

import 'dart:math';

import 'package:benchmark/benchmark.dart';
import 'package:more/collection.dart';
import 'package:petitparser/petitparser.dart';

final random = Random(42);
const context = Context('', 0);
final input = IntegerRange(1024 * 1024)
    .map<Result<String>>((_) => random.nextBool()
        ? context.success<String>('success', random.nextInt(0xffff))
        : context.failure<String>('failure', random.nextInt(0xffff)))
    .toList(growable: false);

Benchmark exercise(int Function(Result<String>) underTest) => () {
      for (var i = 0; i < input.length; i++) {
        underTest(input[i]);
      }
    };

void main() {
  experiments(
    control: exercise((result) => result.isSuccess ? result.position : -1),
    experiments: {
      'switch1': exercise((result) => switch (result) {
            Success(position: final position) => position,
            Failure() => -1,
          }),
      'switch2': exercise((result) => switch (result) {
            final Success s => s.position,
            Failure _ => -1,
          }),
      'switch3': exercise((result) => switch (result) {
            final Success<String> s => s.position,
            Failure<String> _ => -1,
          }),
    },
  );
}

@RandalSchwartz
Copy link
Author

The second case could be _ => -1,, which might speed up the match.

@renggli
Copy link
Member

renggli commented Jul 16, 2023

That makes it a bit faster, but not by much:

control             10,138.543μs [10,128.630μs; 10,148.455μs]
switch1             12,682.747μs [12,664.574μs; 12,700.920μs]
                    -25.095% [-25.285%; -24.905%]
switch2             10,060.908μs [10,058.125μs; 10,063.691μs]
                    0.765% [0.665%; 0.866%]
switch3             12,713.996μs [12,705.227μs; 12,722.765μs]
                    -25.403% [-25.565%; -25.242%]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants