[benchmark] Benchmark for switch on various constant types

AOT:
SwitchFSM.enum(RunTime): 29.549523327947906 us.
SwitchFSM.int(RunTime): 37.73789702628717 us.
SwitchFSM.class(RunTime): 138.6418530572675 us.
SwitchFSM.string(RunTime): 797.54075 us.

dart2js+V8:
SwitchFSM.enum(RunTime): 31.484299349840917 us.
SwitchFSM.int(RunTime): 26.022895908416366 us.
SwitchFSM.class(RunTime): 91.67433302667894 us.
SwitchFSM.string(RunTime): 92.31338451577098 us.

Both AOT and dart2js are 'good at' switches on enum values.

When compiled with --enable-experiment=records,patterns:

AOT:
SwitchFSM.enum(RunTime): 141.75470079359405 us.
SwitchFSM.int(RunTime): 145.25322604030737 us.
SwitchFSM.class(RunTime): 138.45460840662005 us.
SwitchFSM.string(RunTime): 797.226 us.

dart2js+V8:
SwitchFSM.enum(RunTime): 98.93787283573403 us.
SwitchFSM.int(RunTime): 29.459852700736498 us.
SwitchFSM.class(RunTime): 98.62184338405162 us.
SwitchFSM.string(RunTime): 92.035889371936 us.

There is work to be done to recover the performance.

Change-Id: I1197129cb32615a06a63a05d7ba300b46c68b4d2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287246
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
Stephen Adams 2023-03-10 04:21:13 +00:00 committed by Commit Queue
parent d52fe19dee
commit 6ca7571e2b
9 changed files with 1138 additions and 0 deletions

View file

@ -0,0 +1,122 @@
// Copyright (c) 2023, 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.
/// This benchmark compares a large switch statement on various kinds of
/// values. The switch statement is part of a finite-state-machine (FSM)
/// recognizer.
///
/// There are four copies of the same code, differing only by importing
/// different declarations of the type `State` which makes the same constant
/// names available using different types.
///
/// The switch dispatch on the following types is benchmarked:
///
/// - a compact range of `int` values,
/// - an enum,
/// - a class that is a bit like an `enum` but not declared as an enum,
/// - strings.
///
/// The actual state-machine is somewhat aritificial. It recognizes a character
/// string of '0' and '1' character 'bits' that encode a valid UTF-8 string. The
/// state machine has 48 states and minimal logic in most states, so that as
/// much time as possible is executing the switch dispatch.
///
/// The data is passed to the recogizer as a Uint8List to minimize the time to
/// access the bytes of the ASCII '0' / '1' character input sequence.
import 'dart:typed_data';
import 'package:expect/expect.dart';
import 'package:benchmark_harness/benchmark_harness.dart';
import 'match_class.dart' as match_class;
import 'match_enum.dart' as match_enum;
import 'match_int.dart' as match_int;
import 'match_string.dart' as match_string;
class Benchmark extends BenchmarkBase {
final bool Function(Uint8List) match;
Benchmark(String kind, this.match) : super('SwitchFSM.$kind');
void validation() {
void check(String s, bool expected) {
Expect.equals(expected, match(convert(s)), '"$s"');
}
check('', true);
check('0', false);
check('00', false);
check('000', false);
check('0000', false);
check('00000', false);
check('000000', false);
check('0000000', false);
check('00000000', true);
check('01010101', true);
check('10000000', false);
check('001010101', false);
check('11000000' '00000000', false);
check('11000000' '10111111', true);
check('11000000' '11111111', false);
check('11100000' '00000000' '00000000', false);
check('11100000' '10000000' '00000000', false);
check('11100000' '10111111' '10111111', true);
check('11110111' '10111111' '10111111' '01111111', false);
check('11110111' '10111111' '10111111' '10111111', true);
Expect.equals(testInputLength, testInput.length);
}
static const testInputLength = 1000;
static final Uint8List testInput = convert(makeTestInput(testInputLength));
static String makeTestInput(int length) {
// The test input uses most states of the FSM. It is repeated and padded to
// make the length 1000.
final testPattern = ''
'11110111101111111011111110111111'
'111011111011111110111111'
'1101111110111111';
final paddingPattern = '00000000';
final repeats = testPattern * (length ~/ testPattern.length);
final padding =
paddingPattern * ((length - repeats.length) ~/ paddingPattern.length);
return repeats + padding;
}
static convert(String s) => Uint8List.fromList(s.codeUnits);
void run() {
Expect.equals(true, match(testInput));
}
}
enum SomeEnum { element }
void main() {
// TODO(http://dartbug.com/51657): dart2js will remove `_Enum.index` in simple
// programs that don't appear to use the field. This defeats the enum-switch
// optimization that works more reliably in larger programs. Remove this code
// that marks `_Enum.index` as used when #51657 is fixed.
Expect.equals(0, SomeEnum.element.index);
final benchmarks = [
Benchmark('enum', match_enum.match),
Benchmark('int', match_int.match),
Benchmark('class', match_class.match),
Benchmark('string', match_string.match),
];
for (final benchmark in benchmarks) {
benchmark.validation();
}
for (final benchmark in benchmarks) {
benchmark.warmup();
}
for (final benchmark in benchmarks) {
benchmark.report();
}
}

View file

@ -0,0 +1,187 @@
// Copyright (c) 2023, 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:typed_data';
import 'state_class.dart';
bool match(Uint8List s) {
int i = 0;
var state = State.start;
if (state.index != 0) throw StateError('state.index = ${state.index}');
OUTER:
while (true) {
if (i == s.length) break;
final zero = s[i++] == 48;
switch (state) {
case State.start:
state = zero ? State.a1 : State.extended1;
break;
// 0xxxxxxx
// ^
case State.a1:
state = State.a2;
break;
case State.a2:
state = State.a3;
break;
case State.a3:
state = State.a4;
break;
case State.a4:
state = State.a5;
break;
case State.a5:
state = State.a6;
break;
case State.a6:
state = State.a7;
break;
case State.a7:
state = State.start;
break;
case State.error:
break OUTER;
// 110xxxxx 10xxxxxx
// ^
// 1110xxxx 10xxxxxx 10xxxxxx
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
case State.extended1:
state = zero ? State.error : State.extended2;
break;
case State.extended2:
state = zero ? State.two3 : State.extended3;
break;
case State.extended3:
state = zero ? State.three4 : State.extended4;
break;
case State.extended4:
state = zero ? State.four5 : State.error;
break;
case State.two3:
state = State.two4;
break;
case State.two4:
state = State.two5;
break;
case State.two5:
state = State.two6;
break;
case State.two6:
state = State.two7;
break;
case State.two7:
state = State.last0;
break;
case State.three4:
state = State.three5;
break;
case State.three5:
state = State.three6;
break;
case State.three6:
state = State.three7;
break;
case State.three7:
state = State.prev0;
break;
case State.four5:
state = State.four6;
break;
case State.four6:
state = State.four7;
break;
case State.four7:
state = State.first0;
break;
// 10xxxxxx 10xxxxxx 10xxxxxx
case State.first0:
state = zero ? State.error : State.first1;
break;
case State.first1:
state = zero ? State.first2 : State.error;
break;
case State.first2:
state = State.first3;
break;
case State.first3:
state = State.first4;
break;
case State.first4:
state = State.first5;
break;
case State.first5:
state = State.first6;
break;
case State.first6:
state = State.first7;
break;
case State.first7:
state = State.prev0;
break;
// 10xxxxxx 10xxxxxx
case State.prev0:
state = zero ? State.error : State.prev1;
break;
case State.prev1:
state = zero ? State.prev2 : State.error;
break;
case State.prev2:
state = State.prev3;
break;
case State.prev3:
state = State.prev4;
break;
case State.prev4:
state = State.prev5;
break;
case State.prev5:
state = State.prev6;
break;
case State.prev6:
state = State.prev7;
break;
case State.prev7:
state = State.last0;
break;
// 10xxxxxx
case State.last0:
state = zero ? State.error : State.last1;
break;
case State.last1:
state = zero ? State.last2 : State.error;
break;
case State.last2:
state = State.last3;
break;
case State.last3:
state = State.last4;
break;
case State.last4:
state = State.last5;
break;
case State.last5:
state = State.last6;
break;
case State.last6:
state = State.last7;
break;
case State.last7:
state = State.start;
break;
}
}
return state == State.start;
}

View file

@ -0,0 +1,186 @@
// Copyright (c) 2023, 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:typed_data';
import 'state_enum.dart';
bool match(Uint8List s) {
int i = 0;
var state = State.start;
OUTER:
while (true) {
if (i == s.length) break;
final zero = s[i++] == 48;
switch (state) {
case State.start:
state = zero ? State.a1 : State.extended1;
break;
// 0xxxxxxx
// ^
case State.a1:
state = State.a2;
break;
case State.a2:
state = State.a3;
break;
case State.a3:
state = State.a4;
break;
case State.a4:
state = State.a5;
break;
case State.a5:
state = State.a6;
break;
case State.a6:
state = State.a7;
break;
case State.a7:
state = State.start;
break;
case State.error:
break OUTER;
// 110xxxxx 10xxxxxx
// ^
// 1110xxxx 10xxxxxx 10xxxxxx
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
case State.extended1:
state = zero ? State.error : State.extended2;
break;
case State.extended2:
state = zero ? State.two3 : State.extended3;
break;
case State.extended3:
state = zero ? State.three4 : State.extended4;
break;
case State.extended4:
state = zero ? State.four5 : State.error;
break;
case State.two3:
state = State.two4;
break;
case State.two4:
state = State.two5;
break;
case State.two5:
state = State.two6;
break;
case State.two6:
state = State.two7;
break;
case State.two7:
state = State.last0;
break;
case State.three4:
state = State.three5;
break;
case State.three5:
state = State.three6;
break;
case State.three6:
state = State.three7;
break;
case State.three7:
state = State.prev0;
break;
case State.four5:
state = State.four6;
break;
case State.four6:
state = State.four7;
break;
case State.four7:
state = State.first0;
break;
// 10xxxxxx 10xxxxxx 10xxxxxx
case State.first0:
state = zero ? State.error : State.first1;
break;
case State.first1:
state = zero ? State.first2 : State.error;
break;
case State.first2:
state = State.first3;
break;
case State.first3:
state = State.first4;
break;
case State.first4:
state = State.first5;
break;
case State.first5:
state = State.first6;
break;
case State.first6:
state = State.first7;
break;
case State.first7:
state = State.prev0;
break;
// 10xxxxxx 10xxxxxx
case State.prev0:
state = zero ? State.error : State.prev1;
break;
case State.prev1:
state = zero ? State.prev2 : State.error;
break;
case State.prev2:
state = State.prev3;
break;
case State.prev3:
state = State.prev4;
break;
case State.prev4:
state = State.prev5;
break;
case State.prev5:
state = State.prev6;
break;
case State.prev6:
state = State.prev7;
break;
case State.prev7:
state = State.last0;
break;
// 10xxxxxx
case State.last0:
state = zero ? State.error : State.last1;
break;
case State.last1:
state = zero ? State.last2 : State.error;
break;
case State.last2:
state = State.last3;
break;
case State.last3:
state = State.last4;
break;
case State.last4:
state = State.last5;
break;
case State.last5:
state = State.last6;
break;
case State.last6:
state = State.last7;
break;
case State.last7:
state = State.start;
break;
}
}
return state == State.start;
}

View file

@ -0,0 +1,186 @@
// Copyright (c) 2023, 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:typed_data';
import 'state_int.dart';
bool match(Uint8List s) {
int i = 0;
var state = State.start;
OUTER:
while (true) {
if (i == s.length) break;
final zero = s[i++] == 48;
switch (state) {
case State.start:
state = zero ? State.a1 : State.extended1;
break;
// 0xxxxxxx
// ^
case State.a1:
state = State.a2;
break;
case State.a2:
state = State.a3;
break;
case State.a3:
state = State.a4;
break;
case State.a4:
state = State.a5;
break;
case State.a5:
state = State.a6;
break;
case State.a6:
state = State.a7;
break;
case State.a7:
state = State.start;
break;
case State.error:
break OUTER;
// 110xxxxx 10xxxxxx
// ^
// 1110xxxx 10xxxxxx 10xxxxxx
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
case State.extended1:
state = zero ? State.error : State.extended2;
break;
case State.extended2:
state = zero ? State.two3 : State.extended3;
break;
case State.extended3:
state = zero ? State.three4 : State.extended4;
break;
case State.extended4:
state = zero ? State.four5 : State.error;
break;
case State.two3:
state = State.two4;
break;
case State.two4:
state = State.two5;
break;
case State.two5:
state = State.two6;
break;
case State.two6:
state = State.two7;
break;
case State.two7:
state = State.last0;
break;
case State.three4:
state = State.three5;
break;
case State.three5:
state = State.three6;
break;
case State.three6:
state = State.three7;
break;
case State.three7:
state = State.prev0;
break;
case State.four5:
state = State.four6;
break;
case State.four6:
state = State.four7;
break;
case State.four7:
state = State.first0;
break;
// 10xxxxxx 10xxxxxx 10xxxxxx
case State.first0:
state = zero ? State.error : State.first1;
break;
case State.first1:
state = zero ? State.first2 : State.error;
break;
case State.first2:
state = State.first3;
break;
case State.first3:
state = State.first4;
break;
case State.first4:
state = State.first5;
break;
case State.first5:
state = State.first6;
break;
case State.first6:
state = State.first7;
break;
case State.first7:
state = State.prev0;
break;
// 10xxxxxx 10xxxxxx
case State.prev0:
state = zero ? State.error : State.prev1;
break;
case State.prev1:
state = zero ? State.prev2 : State.error;
break;
case State.prev2:
state = State.prev3;
break;
case State.prev3:
state = State.prev4;
break;
case State.prev4:
state = State.prev5;
break;
case State.prev5:
state = State.prev6;
break;
case State.prev6:
state = State.prev7;
break;
case State.prev7:
state = State.last0;
break;
// 10xxxxxx
case State.last0:
state = zero ? State.error : State.last1;
break;
case State.last1:
state = zero ? State.last2 : State.error;
break;
case State.last2:
state = State.last3;
break;
case State.last3:
state = State.last4;
break;
case State.last4:
state = State.last5;
break;
case State.last5:
state = State.last6;
break;
case State.last6:
state = State.last7;
break;
case State.last7:
state = State.start;
break;
}
}
return state == State.start;
}

View file

@ -0,0 +1,186 @@
// Copyright (c) 2023, 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:typed_data';
import 'state_string.dart';
bool match(Uint8List s) {
int i = 0;
var state = State.start;
OUTER:
while (true) {
if (i == s.length) break;
final zero = s[i++] == 48;
switch (state) {
case State.start:
state = zero ? State.a1 : State.extended1;
break;
// 0xxxxxxx
// ^
case State.a1:
state = State.a2;
break;
case State.a2:
state = State.a3;
break;
case State.a3:
state = State.a4;
break;
case State.a4:
state = State.a5;
break;
case State.a5:
state = State.a6;
break;
case State.a6:
state = State.a7;
break;
case State.a7:
state = State.start;
break;
case State.error:
break OUTER;
// 110xxxxx 10xxxxxx
// ^
// 1110xxxx 10xxxxxx 10xxxxxx
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
case State.extended1:
state = zero ? State.error : State.extended2;
break;
case State.extended2:
state = zero ? State.two3 : State.extended3;
break;
case State.extended3:
state = zero ? State.three4 : State.extended4;
break;
case State.extended4:
state = zero ? State.four5 : State.error;
break;
case State.two3:
state = State.two4;
break;
case State.two4:
state = State.two5;
break;
case State.two5:
state = State.two6;
break;
case State.two6:
state = State.two7;
break;
case State.two7:
state = State.last0;
break;
case State.three4:
state = State.three5;
break;
case State.three5:
state = State.three6;
break;
case State.three6:
state = State.three7;
break;
case State.three7:
state = State.prev0;
break;
case State.four5:
state = State.four6;
break;
case State.four6:
state = State.four7;
break;
case State.four7:
state = State.first0;
break;
// 10xxxxxx 10xxxxxx 10xxxxxx
case State.first0:
state = zero ? State.error : State.first1;
break;
case State.first1:
state = zero ? State.first2 : State.error;
break;
case State.first2:
state = State.first3;
break;
case State.first3:
state = State.first4;
break;
case State.first4:
state = State.first5;
break;
case State.first5:
state = State.first6;
break;
case State.first6:
state = State.first7;
break;
case State.first7:
state = State.prev0;
break;
// 10xxxxxx 10xxxxxx
case State.prev0:
state = zero ? State.error : State.prev1;
break;
case State.prev1:
state = zero ? State.prev2 : State.error;
break;
case State.prev2:
state = State.prev3;
break;
case State.prev3:
state = State.prev4;
break;
case State.prev4:
state = State.prev5;
break;
case State.prev5:
state = State.prev6;
break;
case State.prev6:
state = State.prev7;
break;
case State.prev7:
state = State.last0;
break;
// 10xxxxxx
case State.last0:
state = zero ? State.error : State.last1;
break;
case State.last1:
state = zero ? State.last2 : State.error;
break;
case State.last2:
state = State.last3;
break;
case State.last3:
state = State.last4;
break;
case State.last4:
state = State.last5;
break;
case State.last5:
state = State.last6;
break;
case State.last6:
state = State.last7;
break;
case State.last7:
state = State.start;
break;
}
}
return state == State.start;
}

View file

@ -0,0 +1,71 @@
// Copyright (c) 2023, 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.
typedef State = _Class;
class _Class {
final int index;
const _Class(this.index);
static const start = _Class(0);
static const a1 = _Class(1);
static const a2 = _Class(2);
static const a3 = _Class(3);
static const a4 = _Class(4);
static const a5 = _Class(5);
static const a6 = _Class(6);
static const a7 = _Class(7);
static const error = _Class(8);
static const extended1 = _Class(9);
static const extended2 = _Class(10);
static const extended3 = _Class(11);
static const extended4 = _Class(12);
static const two3 = _Class(13);
static const two4 = _Class(14);
static const two5 = _Class(15);
static const two6 = _Class(16);
static const two7 = _Class(17);
static const three4 = _Class(18);
static const three5 = _Class(19);
static const three6 = _Class(20);
static const three7 = _Class(21);
static const four5 = _Class(22);
static const four6 = _Class(23);
static const four7 = _Class(24);
// First additional byte of 3.
static const first0 = _Class(25);
static const first1 = _Class(26);
static const first2 = _Class(27);
static const first3 = _Class(28);
static const first4 = _Class(29);
static const first5 = _Class(30);
static const first6 = _Class(31);
static const first7 = _Class(32);
// Second last additional byte.
static const prev0 = _Class(33);
static const prev1 = _Class(34);
static const prev2 = _Class(35);
static const prev3 = _Class(36);
static const prev4 = _Class(37);
static const prev5 = _Class(38);
static const prev6 = _Class(39);
static const prev7 = _Class(40);
// Last additional byte.
static const last0 = _Class(41);
static const last1 = _Class(42);
static const last2 = _Class(43);
static const last3 = _Class(44);
static const last4 = _Class(45);
static const last5 = _Class(46);
static const last6 = _Class(47);
static const last7 = _Class(48);
}

View file

@ -0,0 +1,66 @@
// Copyright (c) 2023, 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.
enum State {
start,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
error,
extended1,
extended2,
extended3,
extended4,
two3,
two4,
two5,
two6,
two7,
three4,
three5,
three6,
three7,
four5,
four6,
four7,
// First additional byte of 3.
first0,
first1,
first2,
first3,
first4,
first5,
first6,
first7,
// Second last additional byte.
prev0,
prev1,
prev2,
prev3,
prev4,
prev5,
prev6,
prev7,
// Last additional byte.
last0,
last1,
last2,
last3,
last4,
last5,
last6,
last7,
}

View file

@ -0,0 +1,66 @@
// Copyright (c) 2023, 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.
class State {
static const int start = 0;
static const int a1 = 1;
static const int a2 = 2;
static const int a3 = 3;
static const int a4 = 4;
static const int a5 = 5;
static const int a6 = 6;
static const int a7 = 7;
static const int error = 8;
static const int extended1 = 9;
static const int extended2 = 10;
static const int extended3 = 11;
static const int extended4 = 12;
static const int two3 = 13;
static const int two4 = 14;
static const int two5 = 15;
static const int two6 = 16;
static const int two7 = 17;
static const int three4 = 18;
static const int three5 = 19;
static const int three6 = 20;
static const int three7 = 21;
static const int four5 = 22;
static const int four6 = 23;
static const int four7 = 24;
// First additional byte of 3.
static const int first0 = 25;
static const int first1 = 26;
static const int first2 = 27;
static const int first3 = 28;
static const int first4 = 29;
static const int first5 = 30;
static const int first6 = 31;
static const int first7 = 32;
// Second last additional byte.
static const int prev0 = 33;
static const int prev1 = 34;
static const int prev2 = 35;
static const int prev3 = 36;
static const int prev4 = 37;
static const int prev5 = 38;
static const int prev6 = 39;
static const int prev7 = 40;
// Last additional byte.
static const int last0 = 41;
static const int last1 = 42;
static const int last2 = 43;
static const int last3 = 44;
static const int last4 = 45;
static const int last5 = 46;
static const int last6 = 47;
static const int last7 = 48;
}

View file

@ -0,0 +1,68 @@
// Copyright (c) 2023, 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.
typedef State = _Strings;
class _Strings {
static const String start = 'start';
static const String a1 = 'a1';
static const String a2 = 'a2';
static const String a3 = 'a3';
static const String a4 = 'a4';
static const String a5 = 'a5';
static const String a6 = 'a6';
static const String a7 = 'a7';
static const String error = 'error';
static const String extended1 = 'extended1';
static const String extended2 = 'extended2';
static const String extended3 = 'extended3';
static const String extended4 = 'extended4';
static const String two3 = 'two3';
static const String two4 = 'two4';
static const String two5 = 'two5';
static const String two6 = 'two6';
static const String two7 = 'two7';
static const String three4 = 'three4';
static const String three5 = 'three5';
static const String three6 = 'three6';
static const String three7 = 'three7';
static const String four5 = 'four5';
static const String four6 = 'four6';
static const String four7 = 'four7';
// First additional byte of 3.
static const String first0 = 'first0';
static const String first1 = 'first1';
static const String first2 = 'first2';
static const String first3 = 'first3';
static const String first4 = 'first4';
static const String first5 = 'first5';
static const String first6 = 'first6';
static const String first7 = 'first7';
// Second last additional byte.
static const String prev0 = 'prev0';
static const String prev1 = 'prev1';
static const String prev2 = 'prev2';
static const String prev3 = 'prev3';
static const String prev4 = 'prev4';
static const String prev5 = 'prev5';
static const String prev6 = 'prev6';
static const String prev7 = 'prev7';
// Last additional byte.
static const String last0 = 'last0';
static const String last1 = 'last1';
static const String last2 = 'last2';
static const String last3 = 'last3';
static const String last4 = 'last4';
static const String last5 = 'last5';
static const String last6 = 'last6';
static const String last7 = 'last7';
}