fixnum
fixnum copied to clipboard
fixnum classes could be much more performant when targeting the Dart VM
Since Dart conditional imports/exports are a thing, has there been much consideration to making package:fixnum
offer different implementations of Int32
/Int64
for the Dart VM than for the web? For the VM, they could be mostly simple wrappers around int
.
Currently anyone considering package:fixnum
has to make a tradeoff between portability and a significant difference in performance. I made a quick (but very crude) prototype that replaced the internals of Int64
, and it seems ~3x faster for the benchmarks I ran. (It still seems ~3x slower than using int
directly, presumably due to all of the unboxing/boxing, but that's better than the ~9x difference I see with the current implementation.)
I'm not certain of the relative usage of package:fixnum
, and whether we want to consider it a paved path for in terms of our numeric types. This library is used by grpc, profobuf, built_value, intl, and others (https://pub.dev/packages?q=dependency%3Afixnum), though some of those uses may be from when Dart had arbitrary precision integers.
cc @mraleph for the performance questions, and @leafpetersen for the supported types question
I think it would be great to find a way to make fixnum both portable and performant. It's also causing some performance issues and bloat in the protobuf's.
I have some ideas on how it could be made really performant on the VM with few minor tweaks, but it also needs some language support, e.g. I would like to have a way to allow VM loose identity of Int64
wrapper.
I think a conditional import of a better VM version might be a good idea if we keep the current interface.
Why might we change the interface?
Some customers using protobufs want care-free handling of int64
and uint64
values. What they mostly want is to the appropriate sign with toString()
and division. I 'fixed' the former by adding a toStringUnsigned()
method, but that does not help with string interpolation, division, for formatting with NumberFormat. I have toyed with the idea of making Int64
a 64-and-a-half bit value that supports both signed and unsigned. We could support an 'isUnsigned' bit at almost no cost in the current Int64
class, but not if it is a simple wrapper of the Dart VM 64-bit int
. So perhaps it is a good thing I never moved on the idea.
@mraleph
I see very little Int64
arithmetic in one of the big apps I study. It is all 'I/O' - data copying and formatting for display. I'm interested to hear about the performance issues you know of.
To the degree that Int64 operations show up at all in web profiling, it is conversion between Int64 and String during protobuf serialization.
Binary protobuf conversion could be made faster by adding Int64
methods that incorporate the conversion, directly between UInt8List <-> Int64, rather than performing many Int64
operations to process the bytes.
@osa1 I'm happy to share my accumulated thoughts on this if you decide to look at improving the Int64
operations in the protobuf code.
For code where actual arithmetic is actually important:
I have had some success in vector_math
and dart:html
with staging the operations into clear unwrap-compute-wrap steps, where 'compute' is a static function. This allows the outer method to be inlined to enable scalar replacement, leaving calls to the 'compute' method. Since Int64
operations promote arguments from int
and Int32
, perhaps that could be supported by inlining the 'promotion' part. Arguments usually have a static type known well enough to specialize the 'promotion'.
@rakudrama https://github.com/dart-lang/sdk/issues/44175 has example of code that needs reasonable Int64
performance. That being said I agree that I have never seen this problem internally so far.
If we get views, it may be technically possible to retain the current API, and make the VM Int64
a view on an int
. That gives zero overhead, but has different dynamic behavior than an actual wrapper class if you do casts at runtime. (If you don't cast, and always use FixNum
types as typed, it's probably going to be fine.)